Add test utils and tests for quick booking
[pharos-tools.git] / dashboard / src / account / models.py
1 ##############################################################################
2 # Copyright (c) 2016 Max Breitenfeldt and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10
11 from django.contrib.auth.models import User
12 from django.db import models
13 import json
14 import random
15
16
17 class LabStatus(object):
18     UP = 0
19     TEMP_DOWN = 100
20     DOWN = 200
21
22
23 def upload_to(object, filename):
24     return object.user.username + '/' + filename
25
26
27 class UserProfile(models.Model):
28     user = models.OneToOneField(User, on_delete=models.CASCADE)
29     timezone = models.CharField(max_length=100, blank=False, default='UTC')
30     ssh_public_key = models.FileField(upload_to=upload_to, null=True, blank=True)
31     pgp_public_key = models.FileField(upload_to=upload_to, null=True, blank=True)
32     email_addr = models.CharField(max_length=300, blank=False, default='email@mail.com')
33     company = models.CharField(max_length=200, blank=False)
34
35     oauth_token = models.CharField(max_length=1024, blank=False)
36     oauth_secret = models.CharField(max_length=1024, blank=False)
37
38     jira_url = models.CharField(max_length=100, default='')
39     full_name = models.CharField(max_length=100, default='')
40     booking_privledge = models.BooleanField(default=False)
41
42     class Meta:
43         db_table = 'user_profile'
44
45     def __str__(self):
46         return self.user.username
47
48
49 class VlanManager(models.Model):
50     # list of length 4096 containing either 0 (not available) or 1 (available)
51     vlans = models.TextField()
52     block_size = models.IntegerField()
53     allow_overlapping = models.BooleanField()
54     # list of length 4096 containing either 0 (not rexerved) or 1 (reserved)
55     reserved_vlans = models.TextField()
56
57     def get_vlan(self, count=1):
58         allocated = []
59         vlans = json.loads(self.vlans)
60         for i in range(count):
61             new_vlan = vlans.index(1)  # will throw if none available
62             vlans[new_vlan] = 0
63             allocated.append(new_vlan)
64         if count == 1:
65             return allocated[0]
66         return allocated
67
68     def get_public_vlan(self):
69         return PublicNetwork.objects.filter(lab=self.lab_set.first(), in_use=False).first()
70
71     def reserve_public_vlan(self, vlan):
72         net = PublicNetwork.objects.get(lab=self.lab_set.first(), vlan=vlan, in_use=False)
73         net.in_use = True
74         net.save()
75
76     def release_public_vlan(self, vlan):
77         net = PublicNetwork.objects.get(lab=self.lab_set.first(), vlan=vlan, in_use=True)
78         net.in_use = False
79         net.save()
80
81     def public_vlan_is_available(self, vlan):
82         net = PublicNetwork.objects.get(lab=self.lab_set.first(), vlan=vlan)
83         return not net.in_use
84
85     def is_available(self, vlans):
86         """
87         'vlans' is either a single vlan id integer or a list of integers
88         will return true (available) or false
89         """
90         if self.allow_overlapping:
91             return True
92
93         reserved = json.loads(self.reserved_vlans)
94         vlan_master_list = json.loads(self.vlans)
95         try:
96             iter(vlans)
97         except Exception:
98             vlans = [vlans]
99
100         for vlan in vlans:
101             if not vlan_master_list[vlan] or reserved[vlan]:
102                 return False
103         return True
104
105     def release_vlans(self, vlans):
106         """
107         'vlans' is either a single vlan id integer or a list of integers
108         will make the vlans available
109         doesnt return a value
110         """
111         my_vlans = json.loads(self.vlans)
112
113         try:
114             iter(vlans)
115         except Exception:
116             vlans = [vlans]
117
118         for vlan in vlans:
119             my_vlans[vlan] = 1
120         self.vlans = json.dumps(my_vlans)
121         self.save()
122
123     def reserve_vlans(self, vlans):
124         my_vlans = json.loads(self.vlans)
125
126         try:
127             iter(vlans)
128         except Exception:
129             vlans = [vlans]
130
131         vlans = set(vlans)
132
133         for vlan in vlans:
134             if my_vlans[vlan] == 0:
135                 raise ValueError("vlan " + str(vlan) + " is not available")
136
137             my_vlans[vlan] = 0
138         self.vlans = json.dumps(my_vlans)
139         self.save()
140
141
142 class Lab(models.Model):
143     lab_user = models.OneToOneField(User, on_delete=models.CASCADE)
144     name = models.CharField(max_length=200, primary_key=True, unique=True, null=False, blank=False)
145     contact_email = models.EmailField(max_length=200, null=True, blank=True)
146     contact_phone = models.CharField(max_length=20, null=True, blank=True)
147     status = models.IntegerField(default=LabStatus.UP)
148     vlan_manager = models.ForeignKey(VlanManager, on_delete=models.CASCADE, null=True)
149     location = models.TextField(default="unknown")
150     api_token = models.CharField(max_length=50)
151     description = models.CharField(max_length=240)
152
153     @staticmethod
154     def make_api_token():
155         alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
156         key = ""
157         for i in range(45):
158             key += random.choice(alphabet)
159         return key
160
161     def __str__(self):
162         return self.name
163
164
165 class PublicNetwork(models.Model):
166     vlan = models.IntegerField()
167     lab = models.ForeignKey(Lab, on_delete=models.CASCADE)
168     in_use = models.BooleanField(default=False)
169     cidr = models.CharField(max_length=50, default="0.0.0.0/0")
170     gateway = models.CharField(max_length=50, default="0.0.0.0")