From 899e1a4baa95d0bc6f0eef34de66f0e257174878 Mon Sep 17 00:00:00 2001 From: Parker Berberian Date: Tue, 12 Nov 2019 12:54:20 -0500 Subject: Begin Resource Refactor Begins the Resource Refactor by creating new interfaces to the resources through a Resource super class and using that new interface in the api Change-Id: I15a8179bfe915d2cde6d658d056e11cbd2c70e43 Signed-off-by: Parker Berberian --- src/api/migrations/0010_auto_20191219_2004.py | 23 ++++ src/api/models.py | 161 +++++++++----------------- src/api/tests/test_models_unittest.py | 11 +- 3 files changed, 83 insertions(+), 112 deletions(-) create mode 100644 src/api/migrations/0010_auto_20191219_2004.py (limited to 'src/api') diff --git a/src/api/migrations/0010_auto_20191219_2004.py b/src/api/migrations/0010_auto_20191219_2004.py new file mode 100644 index 0000000..ec48584 --- /dev/null +++ b/src/api/migrations/0010_auto_20191219_2004.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2 on 2019-12-19 20:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0009_merge_20190508_1317'), + ] + + operations = [ + migrations.AddField( + model_name='taskconfig', + name='delta_keys_list', + field=models.CharField(default='[]', max_length=200), + ), + migrations.AddField( + model_name='taskconfig', + name='state', + field=models.IntegerField(default=200), + ), + ] diff --git a/src/api/models.py b/src/api/models.py index 682785b..520e747 100644 --- a/src/api/models.py +++ b/src/api/models.py @@ -27,7 +27,8 @@ from resource_inventory.models import ( Interface, HostOPNFVConfig, RemoteInfo, - OPNFVConfig + OPNFVConfig, + ConfigState ) from resource_inventory.idf_templater import IDFTemplater from resource_inventory.pdf_templater import PDFTemplater @@ -294,32 +295,12 @@ class Job(models.Model): def to_dict(self): d = {} - j = {} - j['id'] = self.id - for relation in AccessRelation.objects.filter(job=self): - if 'access' not in d: - d['access'] = {} - d['access'][relation.task_id] = relation.config.to_dict() - for relation in SoftwareRelation.objects.filter(job=self): - if 'software' not in d: - d['software'] = {} - d['software'][relation.task_id] = relation.config.to_dict() - for relation in HostHardwareRelation.objects.filter(job=self): - if 'hardware' not in d: - d['hardware'] = {} - d['hardware'][relation.task_id] = relation.config.to_dict() - for relation in HostNetworkRelation.objects.filter(job=self): - if 'network' not in d: - d['network'] = {} - d['network'][relation.task_id] = relation.config.to_dict() - for relation in SnapshotRelation.objects.filter(job=self): - if 'snapshot' not in d: - d['snapshot'] = {} - d['snapshot'][relation.task_id] = relation.config.to_dict() - - j['payload'] = d - - return j + for relation in self.get_tasklist(): + if relation.job_key not in d: + d[relation.job_key] = {} + d[relation.job_key][relation.task_id] = relation.config.to_dict() + + return {"id": self.id, "payload": d} def get_tasklist(self, status="all"): tasklist = [] @@ -351,48 +332,54 @@ class Job(models.Model): def get_delta(self, status): d = {} - j = {} - j['id'] = self.id - for relation in AccessRelation.objects.filter(job=self).filter(status=status): - if 'access' not in d: - d['access'] = {} - d['access'][relation.task_id] = relation.config.get_delta() - for relation in SoftwareRelation.objects.filter(job=self).filter(status=status): - if 'software' not in d: - d['software'] = {} - d['software'][relation.task_id] = relation.config.get_delta() - for relation in HostHardwareRelation.objects.filter(job=self).filter(status=status): - if 'hardware' not in d: - d['hardware'] = {} - d['hardware'][relation.task_id] = relation.config.get_delta() - for relation in HostNetworkRelation.objects.filter(job=self).filter(status=status): - if 'network' not in d: - d['network'] = {} - d['network'][relation.task_id] = relation.config.get_delta() - for relation in SnapshotRelation.objects.filter(job=self).filter(status=status): - if 'snapshot' not in d: - d['snapshot'] = {} - d['snapshot'][relation.task_id] = relation.config.get_delta() - - j['payload'] = d - return j + for relation in self.get_tasklist(status=status): + if relation.job_key not in d: + d[relation.job_key] = {} + d[relation.job_key][relation.task_id] = relation.config.get_delta() + + return {"id": self.id, "payload": d} def to_json(self): return json.dumps(self.to_dict()) class TaskConfig(models.Model): + state = models.IntegerField(default=ConfigState.CLEAN) + + keys = set() # TODO: This needs to be an instance variable, not a class variable + delta_keys_list = models.CharField(max_length=200, default="[]") + + @property + def delta_keys(self): + return list(set(json.loads(self.delta_keys_list))) + + @delta_keys.setter + def delta_keys(self, keylist): + self.delta_keys_list = json.dumps(keylist) + def to_dict(self): - pass + raise NotImplementedError def get_delta(self): - pass + raise NotImplementedError + + def format_delta(self, config, token): + delta = {k: config[k] for k in self.delta_keys} + delta['lab_token'] = token + return delta def to_json(self): return json.dumps(self.to_dict()) def clear_delta(self): - self.delta = '{}' + self.delta_keys = [] + + def set(self, *args): + dkeys = self.delta_keys + for arg in args: + if arg in self.keys: + dkeys.append(arg) + self.delta_keys = dkeys class BridgeConfig(models.Model): @@ -606,55 +593,12 @@ class HardwareConfig(TaskConfig): ipmi_create = models.BooleanField(default=False) delta = models.TextField() - def to_dict(self): - d = {} - d['image'] = self.image - d['power'] = self.power - d['hostname'] = self.hostname - d['ipmi_create'] = str(self.ipmi_create) - d['id'] = self.hosthardwarerelation.host.labid - return d - - def to_json(self): - return json.dumps(self.to_dict()) + keys = set(["id", "image", "power", "hostname", "ipmi_create"]) def get_delta(self): - if not self.delta: - self.delta = self.to_json() - self.save() - d = json.loads(self.delta) - d['lab_token'] = self.hosthardwarerelation.lab_token - return d - - def clear_delta(self): - d = {} - d["id"] = self.hosthardwarerelation.host.labid - d["lab_token"] = self.hosthardwarerelation.lab_token - self.delta = json.dumps(d) - - def set_image(self, image): - self.image = image - d = json.loads(self.delta) - d['image'] = self.image - self.delta = json.dumps(d) - - def set_power(self, power): - self.power = power - d = json.loads(self.delta) - d['power'] = power - self.delta = json.dumps(d) - - def set_hostname(self, hostname): - self.hostname = hostname - d = json.loads(self.delta) - d['hostname'] = hostname - self.delta = json.dumps(d) - - def set_ipmi_create(self, ipmi_create): - self.ipmi_create = ipmi_create - d = json.loads(self.delta) - d['ipmi_create'] = ipmi_create - self.delta = json.dumps(d) + return self.format_delta( + self.hosthardwarerelation.host.get_configuration(self.state), + self.hosthardwarerelation.lab_token) class NetworkConfig(TaskConfig): @@ -781,6 +725,8 @@ class TaskRelation(models.Model): lab_token = models.CharField(default="null", max_length=50) message = models.TextField(default="") + job_key = None + def delete(self, *args, **kwargs): self.config.delete() return super(self.__class__, self).delete(*args, **kwargs) @@ -794,6 +740,7 @@ class TaskRelation(models.Model): class AccessRelation(TaskRelation): config = models.OneToOneField(AccessConfig, on_delete=models.CASCADE) + job_key = "access" def type_str(self): return "Access Task" @@ -805,6 +752,7 @@ class AccessRelation(TaskRelation): class SoftwareRelation(TaskRelation): config = models.OneToOneField(SoftwareConfig, on_delete=models.CASCADE) + job_key = "software" def type_str(self): return "Software Configuration Task" @@ -817,6 +765,7 @@ class SoftwareRelation(TaskRelation): class HostHardwareRelation(TaskRelation): host = models.ForeignKey(Host, on_delete=models.CASCADE) config = models.OneToOneField(HardwareConfig, on_delete=models.CASCADE) + job_key = "hardware" def type_str(self): return "Hardware Configuration Task" @@ -832,6 +781,7 @@ class HostHardwareRelation(TaskRelation): class HostNetworkRelation(TaskRelation): host = models.ForeignKey(Host, on_delete=models.CASCADE) config = models.OneToOneField(NetworkConfig, on_delete=models.CASCADE) + job_key = "network" def type_str(self): return "Network Configuration Task" @@ -844,6 +794,7 @@ class HostNetworkRelation(TaskRelation): class SnapshotRelation(TaskRelation): snapshot = models.ForeignKey(Image, on_delete=models.CASCADE) config = models.OneToOneField(SnapshotConfig, on_delete=models.CASCADE) + job_key = "snapshot" def type_str(self): return "Snapshot Task" @@ -960,11 +911,7 @@ class JobFactory(object): relation.config = relation.config relation.save() - hardware_config.clear_delta() - hardware_config.set_image(host.config.image.lab_id) - hardware_config.set_hostname(host.template.resource.name) - hardware_config.set_power("on") - hardware_config.set_ipmi_create(True) + hardware_config.set("image", "hostname", "power", "ipmi_create") hardware_config.save() @classmethod diff --git a/src/api/tests/test_models_unittest.py b/src/api/tests/test_models_unittest.py index e6f97a6..2ecbe42 100644 --- a/src/api/tests/test_models_unittest.py +++ b/src/api/tests/test_models_unittest.py @@ -1,4 +1,3 @@ -############################################################################## # Copyright (c) 2019 Sawyer Bergeron, Parker Berberian, and others. # # All rights reserved. This program and the accompanying materials @@ -21,6 +20,7 @@ from api.models import ( from resource_inventory.models import ( OPNFVRole, HostProfile, + ConfigState, ) from django.test import TestCase, Client @@ -201,7 +201,7 @@ class ValidBookingCreatesValidJob(TestCase): self.assertEqual(relation.status, JobStatus.NEW) config = relation.config host = relation.host - self.assertEqual(config.hostname, host.template.resource.name) + self.assertEqual(config.get_delta()["hostname"], host.template.resource.name) def test_complete_job_makes_software_configs(self): JobFactory.makeCompleteJob(self.booking) @@ -261,9 +261,10 @@ class ValidBookingCreatesValidJob(TestCase): host_set.remove(relation.host.id) except KeyError: self.fail("Hardware Relation/Config not created for host " + str(relation.host)) - - self.assertEqual(relation.config.power, "on") - self.assertTrue(relation.config.ipmi_create) + # TODO: ConfigState needs to be fixed in factory methods + relation.config.state = ConfigState.NEW + self.assertEqual(relation.config.get_delta()["power"], "on") + self.assertTrue(relation.config.get_delta()["ipmi_create"]) # TODO: the rest of hwconf attrs self.assertEqual(len(host_set), 0) -- cgit 1.2.3-korg