Laas Dashboard Front End Improvements
[laas.git] / src / api / tests / test_models_unittest.py
1 # Copyright (c) 2019 Sawyer Bergeron, Parker Berberian, and others.
2 #
3 # All rights reserved. This program and the accompanying materials
4 # are made available under the terms of the Apache License, Version 2.0
5 # which accompanies this distribution, and is available at
6 # http://www.apache.org/licenses/LICENSE-2.0
7 ##############################################################################
8
9 from api.models import (
10     Job,
11     JobStatus,
12     JobFactory,
13     HostNetworkRelation,
14     HostHardwareRelation,
15     SoftwareRelation,
16     AccessConfig,
17     SnapshotRelation
18 )
19
20 from resource_inventory.models import (
21     OPNFVRole,
22     HostProfile,
23     ConfigState,
24 )
25
26 from django.test import TestCase, Client
27
28 from dashboard.testing_utils import (
29     make_host,
30     make_user,
31     make_user_profile,
32     make_lab,
33     make_installer,
34     make_image,
35     make_scenario,
36     make_os,
37     make_complete_host_profile,
38     make_booking,
39 )
40
41
42 class ValidBookingCreatesValidJob(TestCase):
43     @classmethod
44     def setUpTestData(cls):
45         cls.user = make_user(False, username="newtestuser", password="testpassword")
46         cls.userprofile = make_user_profile(cls.user)
47         cls.lab = make_lab()
48
49         cls.host_profile = make_complete_host_profile(cls.lab)
50         cls.scenario = make_scenario()
51         cls.installer = make_installer([cls.scenario])
52         os = make_os([cls.installer])
53         cls.image = make_image(cls.lab, 1, cls.user, os, cls.host_profile)
54         for i in range(30):
55             make_host(cls.host_profile, cls.lab, name="host" + str(i), labid="host" + str(i))
56         cls.client = Client()
57
58     def setUp(self):
59         self.booking, self.compute_hostnames, self.jump_hostname = self.create_multinode_generic_booking()
60
61     def create_multinode_generic_booking(self):
62         topology = {}
63
64         compute_hostnames = ["cmp01", "cmp02", "cmp03"]
65
66         host_type = HostProfile.objects.first()
67
68         universal_networks = [
69             {"name": "public", "tagged": False, "public": True},
70             {"name": "admin", "tagged": True, "public": False}]
71         compute_networks = [{"name": "private", "tagged": True, "public": False}]
72         jumphost_networks = [{"name": "external", "tagged": True, "public": True}]
73
74         # generate a bunch of extra networks
75         for i in range(10):
76             net = {"tagged": False, "public": False}
77             net["name"] = "net" + str(i)
78             universal_networks.append(net)
79
80         jumphost_info = {
81             "type": host_type,
82             "role": OPNFVRole.objects.get_or_create(name="Jumphost")[0],
83             "nets": self.make_networks(host_type, jumphost_networks + universal_networks),
84             "image": self.image
85         }
86         topology["jump"] = jumphost_info
87
88         for hostname in compute_hostnames:
89             host_info = {
90                 "type": host_type,
91                 "role": OPNFVRole.objects.get_or_create(name="Compute")[0],
92                 "nets": self.make_networks(host_type, compute_networks + universal_networks),
93                 "image": self.image
94             }
95             topology[hostname] = host_info
96
97         booking = make_booking(
98             owner=self.user,
99             lab=self.lab,
100             topology=topology,
101             installer=self.installer,
102             scenario=self.scenario
103         )
104
105         if not booking.resource:
106             raise Exception("Booking does not have a resource when trying to pass to makeCompleteJob")
107         return booking, compute_hostnames, "jump"
108
109     def make_networks(self, hostprofile, nets):
110         """
111         Distribute nets accross hostprofile's interfaces.
112
113         returns a 2D array
114         """
115         network_struct = []
116         count = hostprofile.interfaceprofile.all().count()
117         for i in range(count):
118             network_struct.append([])
119         while (nets):
120             index = len(nets) % count
121             network_struct[index].append(nets.pop())
122
123         return network_struct
124
125     #################################################################
126     # Complete Job Tests
127     #################################################################
128
129     def test_complete_job_makes_access_configs(self):
130         JobFactory.makeCompleteJob(self.booking)
131         job = Job.objects.get(booking=self.booking)
132         self.assertIsNotNone(job)
133
134         access_configs = AccessConfig.objects.filter(accessrelation__job=job)
135
136         vpn_configs = access_configs.filter(access_type="vpn")
137         ssh_configs = access_configs.filter(access_type="ssh")
138
139         self.assertFalse(AccessConfig.objects.exclude(access_type__in=["vpn", "ssh"]).exists())
140
141         all_users = list(self.booking.collaborators.all())
142         all_users.append(self.booking.owner)
143
144         for user in all_users:
145             self.assertTrue(vpn_configs.filter(user=user).exists())
146             self.assertTrue(ssh_configs.filter(user=user).exists())
147
148     def test_complete_job_makes_network_configs(self):
149         JobFactory.makeCompleteJob(self.booking)
150         job = Job.objects.get(booking=self.booking)
151         self.assertIsNotNone(job)
152
153         booking_hosts = self.booking.resource.hosts.all()
154
155         netrelations = HostNetworkRelation.objects.filter(job=job)
156         netconfigs = [r.config for r in netrelations]
157
158         netrelation_hosts = [r.host for r in netrelations]
159
160         for config in netconfigs:
161             for interface in config.interfaces.all():
162                 self.assertTrue(interface.host in booking_hosts)
163
164         # if no interfaces are referenced that shouldn't have vlans,
165         # and no vlans exist outside those accounted for in netconfigs,
166         # then the api is faithfully representing networks
167         # as netconfigs reference resource_inventory models directly
168
169         # this test relies on the assumption that
170         # every interface is configured, whether it does or does not have vlans
171         # if this is not true, the  test fails
172
173         for host in booking_hosts:
174             self.assertTrue(host in netrelation_hosts)
175             relation = HostNetworkRelation.objects.filter(job=job).get(host=host)
176
177             # do 2 direction matching that interfaces are one to one
178             config = relation.config
179             for interface in config.interfaces.all():
180                 self.assertTrue(interface in host.interfaces)
181             for interface in host.interfaces.all():
182                 self.assertTrue(interface in config.interfaces)
183
184         for host in netrelation_hosts:
185             self.assertTrue(host in booking_hosts)
186
187     def test_complete_job_makes_hardware_configs(self):
188         JobFactory.makeCompleteJob(self.booking)
189         job = Job.objects.get(booking=self.booking)
190         self.assertIsNotNone(job)
191
192         hardware_relations = HostHardwareRelation.objects.filter(job=job)
193
194         job_hosts = [r.host for r in hardware_relations]
195
196         booking_hosts = self.booking.resource.hosts.all()
197
198         self.assertEqual(len(booking_hosts), len(job_hosts))
199
200         for relation in hardware_relations:
201             self.assertTrue(relation.host in booking_hosts)
202             self.assertEqual(relation.status, JobStatus.NEW)
203             config = relation.config
204             host = relation.host
205             self.assertEqual(config.get_delta()["hostname"], host.template.resource.name)
206
207     def test_complete_job_makes_software_configs(self):
208         JobFactory.makeCompleteJob(self.booking)
209         job = Job.objects.get(booking=self.booking)
210         self.assertIsNotNone(job)
211
212         srelation = SoftwareRelation.objects.filter(job=job).first()
213         self.assertIsNotNone(srelation)
214
215         sconfig = srelation.config
216         self.assertIsNotNone(sconfig)
217
218         oconfig = sconfig.opnfv
219         self.assertIsNotNone(oconfig)
220
221         # not onetoone in models, but first() is safe here based on how ConfigBundle and a matching OPNFVConfig are created
222         # this should, however, be made explicit
223         self.assertEqual(oconfig.installer, self.booking.config_bundle.opnfv_config.first().installer.name)
224         self.assertEqual(oconfig.scenario, self.booking.config_bundle.opnfv_config.first().scenario.name)
225
226         for host in oconfig.roles.all():
227             role_name = host.config.host_opnfv_config.first().role.name
228             if str(role_name).lower() == "jumphost":
229                 self.assertEqual(host.template.resource.name, self.jump_hostname)
230             elif str(role_name).lower() == "compute":
231                 self.assertTrue(host.template.resource.name in self.compute_hostnames)
232             else:
233                 self.fail(msg="Host with non-configured role name related to job: " + str(role_name))
234
235     def test_make_snapshot_task(self):
236         host = self.booking.resource.hosts.first()
237         image = make_image(self.lab, -1, None, None, host.profile)
238
239         Job.objects.create(booking=self.booking)
240
241         JobFactory.makeSnapshotTask(image, self.booking, host)
242
243         snap_relation = SnapshotRelation.objects.get(job=self.booking.job)
244         config = snap_relation.config
245         self.assertEqual(host.id, config.host.id)
246         self.assertEqual(config.dashboard_id, image.id)
247         self.assertEqual(snap_relation.snapshot.id, image.id)
248
249     def test_make_hardware_configs(self):
250         hosts = self.booking.resource.hosts.all()
251         job = Job.objects.create(booking=self.booking)
252         JobFactory.makeHardwareConfigs(hosts=hosts, job=job)
253
254         hardware_relations = HostHardwareRelation.objects.filter(job=job)
255
256         self.assertEqual(hardware_relations.count(), hosts.count())
257
258         host_set = set([h.id for h in hosts])
259
260         for relation in hardware_relations:
261             try:
262                 host_set.remove(relation.host.id)
263             except KeyError:
264                 self.fail("Hardware Relation/Config not created for host " + str(relation.host))
265             # TODO: ConfigState needs to be fixed in factory methods
266             relation.config.state = ConfigState.NEW
267             self.assertEqual(relation.config.get_delta()["power"], "on")
268             self.assertTrue(relation.config.get_delta()["ipmi_create"])
269             # TODO: the rest of hwconf attrs
270
271         self.assertEqual(len(host_set), 0)