971f7572ea0ccd2533fb9aef075329de2f750b01
[pharos-tools.git] / dashboard / src / api / tests / test_models_unittest.py
1 ##############################################################################
2 # Copyright (c) 2019 Sawyer Bergeron, Parker Berberian, 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 datetime import timedelta
12 from django.utils import timezone
13
14 from booking.models import Booking
15 from api.models import (
16     Job,
17     JobStatus,
18     JobFactory,
19     AccessRelation,
20     HostNetworkRelation,
21     HostHardwareRelation,
22     SoftwareRelation,
23 )
24
25 from resource_inventory.models import (
26     OPNFVRole,
27     HostProfile,
28 )
29
30 from django.test import TestCase, Client
31
32 from dashboard.testing_utils import (
33     instantiate_host,
34     instantiate_user,
35     instantiate_userprofile,
36     instantiate_lab,
37     instantiate_installer,
38     instantiate_image,
39     instantiate_scenario,
40     instantiate_os,
41     make_hostprofile_set,
42     instantiate_opnfvrole,
43     instantiate_publicnet,
44     instantiate_booking,
45 )
46
47
48 class ValidBookingCreatesValidJob(TestCase):
49     @classmethod
50     def setUpTestData(cls):
51         cls.loginuser = instantiate_user(False, username="newtestuser", password="testpassword")
52         cls.userprofile = instantiate_userprofile(cls.loginuser)
53
54         lab_user = instantiate_user(True)
55         cls.lab = instantiate_lab(lab_user)
56
57         cls.host_profile = make_hostprofile_set(cls.lab)
58         cls.scenario = instantiate_scenario()
59         cls.installer = instantiate_installer([cls.scenario])
60         os = instantiate_os([cls.installer])
61         cls.image = instantiate_image(cls.lab, 1, cls.loginuser, os, cls.host_profile)
62         for i in range(30):
63             instantiate_host(cls.host_profile, cls.lab, name="host" + str(i), labid="host" + str(i))
64         cls.role = instantiate_opnfvrole("Jumphost")
65         cls.computerole = instantiate_opnfvrole("Compute")
66         instantiate_publicnet(10, cls.lab)
67         instantiate_publicnet(12, cls.lab)
68         instantiate_publicnet(14, cls.lab)
69
70         cls.lab_selected = 'lab_' + str(cls.lab.lab_user.id) + '_selected'
71         cls.host_selected = 'host_' + str(cls.host_profile.id) + '_selected'
72
73         cls.post_data = cls.build_post_data()
74
75         cls.client = Client()
76
77     def setUp(self):
78         self.client.login(
79             username=self.loginuser.username, password="testpassword")
80         self.booking, self.compute_hostnames, self.jump_hostname = self.create_multinode_generic_booking()
81
82     @classmethod
83     def build_post_data(cls):
84         post_data = {}
85         post_data['filter_field'] = '{"hosts":[{"host_' + str(cls.host_profile.id) + '":"true"}], "labs": [{"lab_' + str(cls.lab.lab_user.id) + '":"true"}]}'
86         post_data['purpose'] = 'purposefieldcontentstring'
87         post_data['project'] = 'projectfieldcontentstring'
88         post_data['length'] = '3'
89         post_data['ignore_this'] = 1
90         post_data['users'] = ''
91         post_data['hostname'] = 'hostnamefieldcontentstring'
92         post_data['image'] = str(cls.image.id)
93         post_data['installer'] = str(cls.installer.id)
94         post_data['scenario'] = str(cls.scenario.id)
95         return post_data
96
97     def post(self, changed_fields={}):
98         payload = self.post_data.copy()
99         payload.update(changed_fields)
100         response = self.client.post('/booking/quick/', payload)
101         return response
102
103     def generate_booking(self):
104         self.post()
105         return Booking.objects.first()
106
107     def test_valid_access_configs(self):
108         job = Job.objects.get(booking=self.booking)
109         self.assertIsNotNone(job)
110
111         access_configs = [r.config for r in AccessRelation.objects.filter(job=job).all()]
112
113         vpnconfigs = []
114         sshconfigs = []
115
116         for config in access_configs:
117             if config.access_type == "vpn":
118                 vpnconfigs.append(config)
119             elif config.access_type == "ssh":
120                 sshconfigs.append(config)
121             else:
122                 self.fail(msg="Undefined accessconfig: " + config.access_type + " found")
123
124         user_set = []
125         user_set.append(self.booking.owner)
126         user_set += self.booking.collaborators.all()
127
128         for configs in [vpnconfigs, sshconfigs]:
129             for user in user_set:
130                 configusers = [c.user for c in configs]
131                 self.assertTrue(user in configusers)
132
133     def test_valid_network_configs(self):
134         job = Job.objects.get(booking=self.booking)
135         self.assertIsNotNone(job)
136
137         booking_hosts = self.booking.resource.hosts.all()
138
139         netrelation_set = HostNetworkRelation.objects.filter(job=job)
140         netconfig_set = [r.config for r in netrelation_set]
141
142         netrelation_hosts = [r.host for r in netrelation_set]
143
144         for config in netconfig_set:
145             for interface in config.interfaces.all():
146                 self.assertTrue(interface.host in booking_hosts)
147
148         # if no interfaces are referenced that shouldn't have vlans,
149         # and no vlans exist outside those accounted for in netconfigs,
150         # then the api is faithfully representing networks
151         # as netconfigs reference resource_inventory models directly
152
153         # this test relies on the assumption that
154         # every interface is configured, whether it does or does not have vlans
155         # if this is not true, the  test fails
156
157         for host in booking_hosts:
158             self.assertTrue(host in netrelation_hosts)
159             relation = HostNetworkRelation.objects.filter(job=job).get(host=host)
160
161             # do 2 direction matching that interfaces are one to one
162             config = relation.config
163             for interface in config.interfaces.all():
164                 self.assertTrue(interface in host.interfaces)
165             for interface in host.interfaces.all():
166                 self.assertTrue(interface in config.interfaces)
167
168         for host in netrelation_hosts:
169             self.assertTrue(host in booking_hosts)
170
171     def test_valid_hardware_configs(self):
172         job = Job.objects.get(booking=self.booking)
173         self.assertIsNotNone(job)
174
175         hrelations = HostHardwareRelation.objects.filter(job=job).all()
176
177         job_hosts = [r.host for r in hrelations]
178
179         booking_hosts = self.booking.resource.hosts.all()
180
181         self.assertEqual(len(booking_hosts), len(job_hosts))
182
183         for relation in hrelations:
184             self.assertTrue(relation.host in booking_hosts)
185             self.assertEqual(relation.status, JobStatus.NEW)
186             config = relation.config
187             host = relation.host
188             self.assertEqual(config.hostname, host.template.resource.name)
189
190     def test_valid_software_configs(self):
191         job = Job.objects.get(booking=self.booking)
192         self.assertIsNotNone(job)
193
194         srelation = SoftwareRelation.objects.filter(job=job).first()
195         self.assertIsNotNone(srelation)
196
197         sconfig = srelation.config
198         self.assertIsNotNone(sconfig)
199
200         oconfig = sconfig.opnfv
201         self.assertIsNotNone(oconfig)
202
203         # not onetoone in models, but first() is safe here based on how ConfigBundle and a matching OPNFVConfig are created
204         # this should, however, be made explicit
205         self.assertEqual(oconfig.installer, self.booking.config_bundle.opnfv_config.first().installer.name)
206         self.assertEqual(oconfig.scenario, self.booking.config_bundle.opnfv_config.first().scenario.name)
207
208         for host in oconfig.roles.all():
209             role_name = host.config.opnfvRole.name
210             if str(role_name) == "Jumphost":
211                 self.assertEqual(host.template.resource.name, self.jump_hostname)
212             elif str(role_name) == "Compute":
213                 self.assertTrue(host.template.resource.name in self.compute_hostnames)
214             else:
215                 self.fail(msg="Host with non-configured role name related to job: " + str(role_name))
216
217     def create_multinode_generic_booking(self):
218         topology = {}
219
220         compute_hostnames = ["cmp01", "cmp02", "cmp03"]
221
222         host_type = HostProfile.objects.first()
223
224         universal_networks = [
225             {"name": "public", "tagged": False, "public": True},
226             {"name": "admin", "tagged": True, "public": False}]
227         just_compute_networks = [{"name": "private", "tagged": True, "public": False}]
228         just_jumphost_networks = [{"name": "external", "tagged": True, "public": True}]
229
230         # generate a bunch of extra networks
231         for i in range(10):
232             net = {"tagged": False, "public": False}
233             net["name"] = "u_net" + str(i)
234             universal_networks.append(net)
235
236         jhost_info = {}
237         jhost_info["type"] = host_type
238         jhost_info["role"] = OPNFVRole.objects.get(name="Jumphost")
239         jhost_info["nets"] = self.make_networks(host_type, list(just_jumphost_networks + universal_networks))
240         jhost_info["image"] = self.image
241         topology["jump"] = jhost_info
242
243         for hostname in compute_hostnames:
244             host_info = {}
245             host_info["type"] = host_type
246             host_info["role"] = OPNFVRole.objects.get(name="Compute")
247             host_info["nets"] = self.make_networks(host_type, list(just_compute_networks + universal_networks))
248             host_info["image"] = self.image
249             topology[hostname] = host_info
250
251         booking = instantiate_booking(self.loginuser,
252                                       timezone.now(),
253                                       timezone.now() + timedelta(days=1),
254                                       "demobooking",
255                                       self.lab,
256                                       topology=topology,
257                                       installer=self.installer,
258                                       scenario=self.scenario)
259
260         if not booking.resource:
261             raise Exception("Booking does not have a resource when trying to pass to makeCompleteJob")
262         JobFactory.makeCompleteJob(booking)
263
264         return booking, compute_hostnames, "jump"
265
266     """
267     evenly distributes networks given across a given profile's interfaces
268     """
269     def make_networks(self, hostprofile, nets):
270         network_struct = []
271         count = hostprofile.interfaceprofile.all().count()
272         for i in range(count):
273             network_struct.append([])
274         while(nets):
275             index = len(nets) % count
276             network_struct[index].append(nets.pop())
277
278         return network_struct