1 ##############################################################################
2 # Copyright (c) 2019 Sawyer Bergeron, Parker Berberian, and others.
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 ##############################################################################
11 from datetime import timedelta
12 from django.utils import timezone
14 from booking.models import Booking
15 from api.models import (
25 from resource_inventory.models import (
30 from django.test import TestCase, Client
32 from dashboard.testing_utils import (
35 instantiate_userprofile,
37 instantiate_installer,
42 instantiate_opnfvrole,
43 instantiate_publicnet,
48 class ValidBookingCreatesValidJob(TestCase):
50 def setUpTestData(cls):
51 cls.loginuser = instantiate_user(False, username="newtestuser", password="testpassword")
52 cls.userprofile = instantiate_userprofile(cls.loginuser)
54 lab_user = instantiate_user(True)
55 cls.lab = instantiate_lab(lab_user)
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)
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)
70 cls.lab_selected = 'lab_' + str(cls.lab.lab_user.id) + '_selected'
71 cls.host_selected = 'host_' + str(cls.host_profile.id) + '_selected'
73 cls.post_data = cls.build_post_data()
79 username=self.loginuser.username, password="testpassword")
80 self.booking, self.compute_hostnames, self.jump_hostname = self.create_multinode_generic_booking()
83 def build_post_data(cls):
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)
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)
103 def generate_booking(self):
105 return Booking.objects.first()
107 def test_valid_access_configs(self):
108 job = Job.objects.get(booking=self.booking)
109 self.assertIsNotNone(job)
111 access_configs = [r.config for r in AccessRelation.objects.filter(job=job).all()]
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)
122 self.fail(msg="Undefined accessconfig: " + config.access_type + " found")
125 user_set.append(self.booking.owner)
126 user_set += self.booking.collaborators.all()
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)
133 def test_valid_network_configs(self):
134 job = Job.objects.get(booking=self.booking)
135 self.assertIsNotNone(job)
137 booking_hosts = self.booking.resource.hosts.all()
139 netrelation_set = HostNetworkRelation.objects.filter(job=job)
140 netconfig_set = [r.config for r in netrelation_set]
142 netrelation_hosts = [r.host for r in netrelation_set]
144 for config in netconfig_set:
145 for interface in config.interfaces.all():
146 self.assertTrue(interface.host in booking_hosts)
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
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
157 for host in booking_hosts:
158 self.assertTrue(host in netrelation_hosts)
159 relation = HostNetworkRelation.objects.filter(job=job).get(host=host)
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)
168 for host in netrelation_hosts:
169 self.assertTrue(host in booking_hosts)
171 def test_valid_hardware_configs(self):
172 job = Job.objects.get(booking=self.booking)
173 self.assertIsNotNone(job)
175 hrelations = HostHardwareRelation.objects.filter(job=job).all()
177 job_hosts = [r.host for r in hrelations]
179 booking_hosts = self.booking.resource.hosts.all()
181 self.assertEqual(len(booking_hosts), len(job_hosts))
183 for relation in hrelations:
184 self.assertTrue(relation.host in booking_hosts)
185 self.assertEqual(relation.status, JobStatus.NEW)
186 config = relation.config
188 self.assertEqual(config.hostname, host.template.resource.name)
190 def test_valid_software_configs(self):
191 job = Job.objects.get(booking=self.booking)
192 self.assertIsNotNone(job)
194 srelation = SoftwareRelation.objects.filter(job=job).first()
195 self.assertIsNotNone(srelation)
197 sconfig = srelation.config
198 self.assertIsNotNone(sconfig)
200 oconfig = sconfig.opnfv
201 self.assertIsNotNone(oconfig)
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)
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)
215 self.fail(msg="Host with non-configured role name related to job: " + str(role_name))
217 def create_multinode_generic_booking(self):
220 compute_hostnames = ["cmp01", "cmp02", "cmp03"]
222 host_type = HostProfile.objects.first()
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}]
230 # generate a bunch of extra networks
232 net = {"tagged": False, "public": False}
233 net["name"] = "u_net" + str(i)
234 universal_networks.append(net)
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
243 for hostname in compute_hostnames:
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
251 booking = instantiate_booking(self.loginuser,
253 timezone.now() + timedelta(days=1),
257 installer=self.installer,
258 scenario=self.scenario)
260 if not booking.resource:
261 raise Exception("Booking does not have a resource when trying to pass to makeCompleteJob")
262 JobFactory.makeCompleteJob(booking)
264 return booking, compute_hostnames, "jump"
267 evenly distributes networks given across a given profile's interfaces
269 def make_networks(self, hostprofile, nets):
271 count = hostprofile.interfaceprofile.all().count()
272 for i in range(count):
273 network_struct.append([])
275 index = len(nets) % count
276 network_struct[index].append(nets.pop())
278 return network_struct