Add and Fix tests
[pharos-tools.git] / dashboard / src / dashboard / testing_utils.py
1 ##############################################################################
2 # Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, 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 from django.contrib.auth.models import User
11 from django.core.files.base import ContentFile
12 from django.utils import timezone
13
14 import json
15 import re
16 from datetime import timedelta
17
18 from dashboard.exceptions import InvalidHostnameException
19 from booking.models import Booking
20 from account.models import UserProfile, Lab, LabStatus, VlanManager, PublicNetwork
21 from resource_inventory.models import (
22     Host,
23     HostProfile,
24     InterfaceProfile,
25     DiskProfile,
26     CpuProfile,
27     Opsys,
28     Image,
29     Scenario,
30     Installer,
31     OPNFVRole,
32     RamProfile,
33     Network,
34     GenericResourceBundle,
35     GenericResource,
36     GenericHost,
37     ConfigBundle,
38     GenericInterface,
39     HostConfiguration,
40     OPNFVConfig,
41     NetworkConnection,
42     HostOPNFVConfig
43 )
44 from resource_inventory.resource_manager import ResourceManager
45
46 """
47 Info for make_booking() function:
48 [topology] argument structure:
49     the [topology] argument should describe the structure of the pod
50     the top level should be a dictionary, with each key being a hostname
51     each value in the top level should be a dictionary with two keys:
52         "type" should map to a host profile instance
53         "nets" should map to a list of interfaces each with a list of
54             dictionaries each defining a network in the format
55             { "name": "netname", "tagged": True|False, "public": True|False }
56             each network is defined if a matching name is not found
57
58     sample argument structure:
59         topology={
60             "host1": {
61                       "type": instanceOf HostProfile,
62                       "role": instanceOf OPNFVRole
63                       "image": instanceOf Image
64                       "nets": [
65                                 0: [
66                                         0: { "name": "public", "tagged": True, "public": True },
67                                         1: { "name": "private", "tagged": False, "public": False },
68                                    ]
69                                 1: []
70                               ]
71                   }
72         }
73 """
74
75
76 def make_booking(owner=None, start=timezone.now(),
77                  end=timezone.now() + timedelta(days=1),
78                  lab=None, purpose="my_purpose",
79                  project="my_project", collaborators=[],
80                  topology={}, installer=None, scenario=None):
81
82     grb, host_set = make_grb(topology, owner, lab)
83     config_bundle = make_config_bundle(grb, owner, topology, host_set, installer, scenario)
84     resource = ResourceManager.getInstance().convertResourceBundle(grb, config=config_bundle)
85     if not resource:
86         raise Exception("Resource not created")
87
88     return Booking.objects.create(
89         resource=resource,
90         config_bundle=config_bundle,
91         start=start,
92         end=end,
93         owner=owner,
94         purpose=purpose,
95         project=project,
96         lab=lab
97     )
98
99
100 def make_config_bundle(grb, owner, topology={}, host_set={},
101                        installer=None, scenario=None):
102     cb = ConfigBundle.objects.create(
103         owner=owner,
104         name="config bundle " + str(ConfigBundle.objects.count()),
105         description="cb generated by make_config_bundle() method"
106     )
107
108     opnfv_config = OPNFVConfig.objects.create(
109         installer=installer,
110         scenario=scenario,
111         bundle=cb
112     )
113
114     # generate host configurations based on topology and host set
115     for hostname, host_info in topology.items():
116         host_config = HostConfiguration.objects.create(
117             host=host_set[hostname],
118             image=host_info["image"],
119             bundle=cb,
120             is_head_node=host_info['role'].name.lower() == "jumphost"
121         )
122         HostOPNFVConfig.objects.create(
123             role=host_info["role"],
124             host_config=host_config,
125             opnfv_config=opnfv_config
126         )
127     return cb
128
129
130 def make_network(name, lab, grb, public):
131     network = Network(name=name, bundle=grb, is_public=public)
132     if public:
133         public_net = lab.vlan_manager.get_public_vlan()
134         if not public_net:
135             raise Exception("No more public networks available")
136         lab.vlan_manager.reserve_public_vlan(public_net.vlan)
137         network.vlan_id = public_net.vlan
138     else:
139         private_net = lab.vlan_manager.get_vlan()
140         if not private_net:
141             raise Exception("No more generic vlans are available")
142         lab.vlan_manager.reserve_vlans([private_net])
143         network.vlan_id = private_net
144
145     network.save()
146     return network
147
148
149 def make_grb(topology, owner, lab):
150
151     grb = GenericResourceBundle.objects.create(
152         owner=owner,
153         lab=lab,
154         name="Generic ResourceBundle " + str(GenericResourceBundle.objects.count()),
155         description="grb generated by make_grb() method"
156     )
157
158     networks = {}
159     host_set = {}
160
161     for hostname, info in topology.items():
162         host_profile = info["type"]
163
164         # need to construct host from hostname and type
165         generic_host = make_generic_host(grb, host_profile, hostname)
166         host_set[hostname] = generic_host
167
168         # set up networks
169         nets = info["nets"]
170         for interface_index, interface_profile in enumerate(host_profile.interfaceprofile.all()):
171             generic_interface = GenericInterface.objects.create(host=generic_host, profile=interface_profile)
172             netconfig = nets[interface_index]
173             for network_info in netconfig:
174                 network_name = network_info["name"]
175                 if network_name not in networks:
176                     networks[network_name] = make_network(network_name, lab, grb, network_info['public'])
177
178                 generic_interface.connections.add(NetworkConnection.objects.create(
179                     network=networks[network_name],
180                     vlan_is_tagged=network_info["tagged"]
181                 ))
182
183     return grb, host_set
184
185
186 def make_generic_host(grb, host_profile, hostname):
187     if not re.match(r"(?=^.{1,253}$)(^([A-Za-z0-9-_]{1,62}\.)*[A-Za-z0-9-_]{1,63})$", hostname):
188         raise InvalidHostnameException("Hostname must comply to RFC 952 and all extensions")
189     gresource = GenericResource.objects.create(bundle=grb, name=hostname)
190
191     return GenericHost.objects.create(resource=gresource, profile=host_profile)
192
193
194 def make_user(is_superuser=False, username="testuser",
195               password="testpassword", email="default_email@user.com"):
196     user = User.objects.create_user(username=username, email=email, password=password)
197     user.is_superuser = is_superuser
198     user.save()
199
200     return user
201
202
203 def make_user_profile(user=None, email_addr="email@email.com",
204                       company="company", full_name="John Doe",
205                       booking_privledge=True, ssh_file=None):
206     user = user or User.objects.first() or make_user()
207     profile = UserProfile.objects.create(
208         email_addr=email_addr,
209         company=company,
210         full_name=full_name,
211         booking_privledge=booking_privledge,
212         user=user
213     )
214     profile.ssh_public_key.save("user_ssh_key", ssh_file if ssh_file else ContentFile("public key content string"))
215
216     return profile
217
218
219 def make_vlan_manager(vlans=None, block_size=20, allow_overlapping=False, reserved_vlans=None):
220     if not vlans:
221         vlans = [vlan % 2 for vlan in range(4095)]
222     if not reserved_vlans:
223         reserved_vlans = [0 for i in range(4095)]
224
225     return VlanManager.objects.create(
226         vlans=json.dumps(vlans),
227         reserved_vlans=json.dumps(vlans),
228         block_size=block_size,
229         allow_overlapping=allow_overlapping
230     )
231
232
233 def make_lab(user=None, name="Test Lab Instance",
234              status=LabStatus.UP, vlan_manager=None,
235              pub_net_count=5):
236     if not vlan_manager:
237         vlan_manager = make_vlan_manager()
238
239     if not user:
240         user = make_user()
241
242     lab = Lab.objects.create(
243         lab_user=user,
244         name=name,
245         contact_email='test_lab@test_site.org',
246         contact_phone='603 123 4567',
247         status=status,
248         vlan_manager=vlan_manager,
249         description='test lab instantiation',
250         api_token='12345678'
251     )
252
253     for i in range(pub_net_count):
254         make_public_net(vlan=i * 2 + 1, lab=lab)
255
256     return lab
257
258
259 """
260 resource_inventory instantiation section for permanent resources
261 """
262
263
264 def make_complete_host_profile(lab, name="test_hostprofile"):
265     host_profile = make_host_profile(lab, name=name)
266     make_disk_profile(host_profile, 500, name=name)
267     make_cpu_profile(host_profile)
268     make_interface_profile(host_profile, name=name)
269     make_ram_profile(host_profile)
270
271     return host_profile
272
273
274 def make_host_profile(lab, host_type=0, name="test hostprofile"):
275     host_profile = HostProfile.objects.create(
276         host_type=host_type,
277         name=name,
278         description='test hostprofile instance'
279     )
280     host_profile.labs.add(lab)
281
282     return host_profile
283
284
285 def make_ram_profile(host, channels=4, amount=256):
286     return RamProfile.objects.create(
287         host=host,
288         amount=amount,
289         channels=channels
290     )
291
292
293 def make_disk_profile(hostprofile, size=0, media_type="SSD",
294                       name="test diskprofile", rotation=0,
295                       interface="sata"):
296     return DiskProfile.objects.create(
297         name=name,
298         size=size,
299         media_type=media_type,
300         host=hostprofile,
301         rotation=rotation,
302         interface=interface
303     )
304
305
306 def make_cpu_profile(hostprofile,
307                      cores=4,
308                      architecture="x86_64",
309                      cpus=4,):
310     return CpuProfile.objects.create(
311         cores=cores,
312         architecture=architecture,
313         cpus=cpus,
314         host=hostprofile,
315         cflags=''
316     )
317
318
319 def make_interface_profile(hostprofile,
320                            speed=1000,
321                            name="test interface profile",
322                            nic_type="pcie"):
323     return InterfaceProfile.objects.create(
324         host=hostprofile,
325         name=name,
326         speed=speed,
327         nic_type=nic_type
328     )
329
330
331 def make_image(lab, lab_id, owner, os, host_profile,
332                public=True, name="default image", description="default image"):
333     return Image.objects.create(
334         from_lab=lab,
335         lab_id=lab_id,
336         os=os,
337         host_type=host_profile,
338         public=public,
339         name=name,
340         description=description
341     )
342
343
344 def make_scenario(name="test scenario"):
345     return Scenario.objects.create(name=name)
346
347
348 def make_installer(scenarios, name="test installer"):
349     installer = Installer.objects.create(name=name)
350     for scenario in scenarios:
351         installer.sup_scenarios.add(scenario)
352
353     return installer
354
355
356 def make_os(installers, name="test OS"):
357     os = Opsys.objects.create(name=name)
358     for installer in installers:
359         os.sup_installers.add(installer)
360
361     return os
362
363
364 def make_host(host_profile, lab, labid="test_host", name="test_host",
365               booked=False, working=True, config=None, template=None,
366               bundle=None, model="Model 1", vendor="ACME"):
367     return Host.objects.create(
368         lab=lab,
369         profile=host_profile,
370         name=name,
371         booked=booked,
372         working=working,
373         config=config,
374         template=template,
375         bundle=bundle,
376         model=model,
377         vendor=vendor
378     )
379
380
381 def make_opnfv_role(name="Jumphost", description="test opnfvrole"):
382     return OPNFVRole.objects.create(
383         name=name,
384         description=description
385     )
386
387
388 def make_public_net(vlan, lab, in_use=False,
389                     cidr="0.0.0.0/0", gateway="0.0.0.0"):
390     return PublicNetwork.objects.create(
391         lab=lab,
392         vlan=vlan,
393         cidr=cidr,
394         gateway=gateway
395     )