diff --git a/opennebula_api/models.py b/opennebula_api/models.py index 99c486fe..2d4a9f97 100644 --- a/opennebula_api/models.py +++ b/opennebula_api/models.py @@ -28,31 +28,30 @@ class VirtualMachineTemplate(models.Model): return price def get_name(self): - if self.manager is None: - self.manager = OpenNebulaManager() - template = self.manager._get_template(template_id=self.opennebula_id) + manager = OpenNebulaManager(create_user=False) + template = manager._get_template(template_id=self.opennebula_id) return template.name def get_cores(self): - if self.manager is None: - self.manager = OpenNebulaManager() - template = self.manager._get_template(template_id=self.opennebula_id).template + manager = OpenNebulaManager(create_user=False) + template = manager._get_template(template_id=self.opennebula_id).template return int(template.vcpu) def get_disk_size(self): - if self.manager is None: - self.manager = OpenNebulaManager() - template = self.manager._get_template(template_id=self.opennebula_id).template - return int(template.disk.size) / 1024 + manager = OpenNebulaManager(create_user=False) + template = manager._get_template(template_id=self.opennebula_id).template + disk_size = 0 + for disk in template.disks: + disk_size += int(disk.size) + return disk_size / 1024 def get_memory(self): - if self.manager is None: - self.manager = OpenNebulaManager() - template = self.manager._get_template(template_id=self.opennebula_id).template + manager = OpenNebulaManager(create_user=False) + template = manager._get_template(template_id=self.opennebula_id).template return int(template.memory) / 1024 class VirtualMachine(models.Model): @@ -133,7 +132,7 @@ class VirtualMachine(models.Model): vm = self.manager._get_vm(vm_id=self.opennebula_id) return self.VM_STATE.get(str(vm.state)) - def get_pirce(self) + def get_price(self): return 0.0 class OpenNebulaManager(): @@ -147,8 +146,7 @@ class OpenNebulaManager(): settings.OPENNEBULA_PASSWORD ) - - if not create_user: + if not create_user or email is None: return # Get or create oppenebula user using given credentials @@ -189,6 +187,7 @@ class OpenNebulaManager(): host=settings.OPENNEBULA_DOMAIN, protocol=settings.OPENNEBULA_PROTOCOL) ) + raise ConnectionRefusedError def _get_user_pool(self): try: user_pool = oca.UserPool(self.oneadmin_client) @@ -198,11 +197,30 @@ class OpenNebulaManager(): host=settings.OPENNEBULA_DOMAIN, protocol=settings.OPENNEBULA_PROTOCOL) ) + raise ConnectionRefusedError return user_pool - def create_virtualmachine(self, template_id): - template_pool = oca.VmTemplatePool(self.oneadmin_client) - template_pool.info() + def _get_vm_pool(self): + try: + vm_pool = oca.VmPool(self.oneadmin_client) + vm_pool.info() + except ConnectionRefusedError: + print('Could not connect to host: {host} via protocol {protocol}'.format( + host=settings.OPENNEBULA_DOMAIN, + protocol=settings.OPENNEBULA_PROTOCOL) + ) + raise ConnectionRefusedError + return vm_pool + + + def _get_vm(self, vm_id): + vm_pool = self._get_vm_pool() + # Get virtual machines from all users + vm_pool.info(filter=-2) + return vm_pool.get_by_id(vm_id) + + def create_vm(self, template_id): + template_pool = self._get_template_pool() template = template_pool.get_by_id(template_id) @@ -215,6 +233,28 @@ class OpenNebulaManager(): ) return vm_id + def delete_vm(self, vm_id): + vm = self._get_vm(vm_id) + vm.delete() + + def _get_template_pool(self): + try: + template_pool = oca.VmTemplatePool(self.oneadmin_client) + template_pool.info() + except ConnectionRefusedError: + print('Could not connect to host: {host} via protocol {protocol}'.format( + host=settings.OPENNEBULA_DOMAIN, + protocol=settings.OPENNEBULA_PROTOCOL) + ) + raise ConnectionRefusedError + return template_pool + + def _get_template(self, template_id): + template_pool = self._get_template_pool() + return template_pool.get_by_id(template_id) + + + def create_template(self, name, cores, memory, disk_size): """Create and add a new template to opennebula. :param name: A string representation describing the template. @@ -247,3 +287,9 @@ class OpenNebulaManager(): ) return template_id + + def delete_template(self, template_id): + self.oneadmin_client.call(oca.VmTemplate.METHODS['delete'], template_id, False) + + + diff --git a/opennebula_api/serializer.py b/opennebula_api/serializer.py deleted file mode 100644 index 98db0daa..00000000 --- a/opennebula_api/serializer.py +++ /dev/null @@ -1,32 +0,0 @@ -from res_framework import serializers -from .models import VirtualMachine, VirtualMachineTemplate - -class VirtualMachineSerializer(serializers.ModelSerializer): - """Serializer to map the virtual machine instance into JSON format.""" - - cores = serializers.IntegerField(read_only=True, source='get_cores') - name = serializers.CharField(read_only=True, source='get_name') - disk_size = serializers.IntegerField(read_only=True, source='get_disk_size') - memory = serializers.IntegerField(read_only=True, source='get_memory') - #TODO: See if we can change to IPAddressField - ip = serializers.CharField(read_only=True, source='get_ip') - deploy_id = serializers.IntegerField(read_only=True, source='get_deploy_id') - id = serializers.IntegerField(read_only=True, source='get_id') - state = serializers.CharField(read_only=True, source='get_state') - price = serializers.FloatField(read_only=True, source='get_price') - - class Meta: - model = VirtualMachine - - -class VirtualMachineTemplateSerializer(serializers.ModelSerializer): - """Serializer to map the virtual machine template instance into JSON format.""" - cores = serializers.IntegerField(read_only=True, source='get_cores') - name = serializers.CharField(read_only=True, source='get_name') - disk_size = serializers.IntegerField(read_only=True, source='get_disk_size') - memory = serializers.IntegerField(read_only=True, source='get_memory') - - class Meta: - model = VirtualMachineTemplate - fields = () - diff --git a/opennebula_api/serializers.py b/opennebula_api/serializers.py new file mode 100644 index 00000000..13f6d5ab --- /dev/null +++ b/opennebula_api/serializers.py @@ -0,0 +1,63 @@ +import oca + +from rest_framework import serializers + +from oca import OpenNebulaException + +from .models import VirtualMachine, VirtualMachineTemplate, OpenNebulaManager + +class VirtualMachineSerializer(serializers.ModelSerializer): + """Serializer to map the virtual machine instance into JSON format.""" + + #TODO: Maybe we can change to template.get_cores + cores = serializers.IntegerField(read_only=True, source='get_cores') + name = serializers.CharField(read_only=True, source='get_name') + disk_size = serializers.IntegerField(read_only=True, source='get_disk_size') + memory = serializers.IntegerField(read_only=True, source='get_memory') + #TODO: See if we can change to IPAddressField + ip = serializers.CharField(read_only=True, source='get_ip') + deploy_id = serializers.IntegerField(read_only=True, source='get_deploy_id') + vm_id = serializers.IntegerField(read_only=True, source='get_vm_id') + state = serializers.CharField(read_only=True, source='get_state') + price = serializers.FloatField(read_only=True, source='get_price') + + class Meta: + model = VirtualMachine + fields = ('id', 'opennebula_id', 'template', 'cores', 'name', + 'disk_size', 'memory', 'ip', 'deploy_id', 'state', 'vm_id', + 'price') + +class VirtualMachineTemplateSerializer(serializers.ModelSerializer): + """Serializer to map the virtual machine template instance into JSON format.""" + cores = serializers.IntegerField(source='get_cores') + name = serializers.CharField(source='get_name') + disk_size = serializers.IntegerField(source='get_disk_size') + memory = serializers.IntegerField(source='get_memory') + + class Meta: + model = VirtualMachineTemplate + fields = ('id', 'name', 'cores', 'memory', 'disk_size', 'base_price', + 'core_price', 'memory_price', 'disk_size_price', 'opennebula_id') + read_only_fields = ('opennebula_id', ) + + def validate(self, data): + # Create the opennebula model + cores = data.pop('get_cores') + name = data.pop('get_name') + disk_size = data.pop('get_disk_size') + memory = data.pop('get_memory') + + manager = OpenNebulaManager(create_user = False) + + try: + opennebula_id = manager.create_template(name=name, cores=cores, + memory=memory, + disk_size=disk_size) + data.update({'opennebula_id':opennebula_id}) + except OpenNebulaException as err: + raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err)) + + return data + + def create(self, validated_data): + return VirtualMachineTemplate.objects.create(**validated_data) diff --git a/opennebula_api/tests.py b/opennebula_api/tests.py index dbd78dc1..14694e6f 100644 --- a/opennebula_api/tests.py +++ b/opennebula_api/tests.py @@ -19,10 +19,10 @@ class OpenNebulaManagerTestCases(TestCase): def test_model_can_connect_to_server(self): """Test the opennebula manager model can connect to a server.""" try: - version = self.manager.version() + user_pool = self.manager._get_user_pool() except: - version = None - self.assertFalse(version is None) + user_pool = None + self.assertFalse(user_pool is None) def test_model_can_create_user(self): """Test the opennebula manager model can create a new user.""" @@ -30,7 +30,12 @@ class OpenNebulaManagerTestCases(TestCase): self.manager = OpenNebulaManager(email=self.email, password=self.password, create_user=True) - new_count = len(self.manager._get_user_pool()) + user_pool = self.manager._get_user_pool() + new_count = len(user_pool) + # Remove the user afterwards + user = user_pool.get_by_name(self.email) + user.delete() + self.assertNotEqual(old_count, new_count) @@ -67,6 +72,9 @@ class VirtualMachineTemplateTestCase(TestCase): old_count = VirtualMachineTemplate.objects.count() self.template.save() new_count = VirtualMachineTemplate.objects.count() + # Remove the template afterwards + template = self.manager._get_template(self.template.opennebula_id) + template.delete() self.assertNotEqual(old_count, new_count) def test_model_can_calculate_price(self): @@ -80,8 +88,26 @@ class VirtualMachineTemplateTestCase(TestCase): class VirtualMachineTestCase(TestCase): def setUp(self): """Define the test client and other test variables.""" - self.manager = OpenNebulaManager(email=None, password=None, create_user=False) - self.template = VirtualMachineTemplate.objects.first() + self.template_name = "Standard" + self.base_price = 0.0 + self.core_price = 5.0 + self.memory_price = 2.0 + self.disk_size_price = 0.6 + + self.cores = 1 + self.memory = 1 + self.disk_size = 10.0 + self.manager = OpenNebulaManager(email=None, password=None, create_user=False) + self.opennebula_id = self.manager.create_template(name=self.template_name, + cores=self.cores, + memory=self.memory, + disk_size=self.disk_size) + + self.template = VirtualMachineTemplate(opennebula_id=self.opennebula_id, + base_price=self.base_price, + memory_price=self.memory_price, + core_price=self.core_price, + disk_size_price=self.disk_size_price) self.template_id = self.template.opennebula_id() self.opennebula_id = self.manager.create_virtualmachine(template_id=self.template_id) @@ -95,6 +121,9 @@ class VirtualMachineTestCase(TestCase): new_count = VirtualMachine.objects.count() self.assertNotEqual(old_count, new_count) + def test_model_can_create_a_virtualmachine_for_user(self): + pass + def test_model_can_delete_a_virtualmachine(self): """Test the virtualmachine model can delete a virtualmachine.""" self.virtualmachine.save() diff --git a/opennebula_api/views.py b/opennebula_api/views.py index 91ea44a2..be0e1a24 100644 --- a/opennebula_api/views.py +++ b/opennebula_api/views.py @@ -1,3 +1,18 @@ -from django.shortcuts import render +from rest_framework import generics +from .serializers import VirtualMachineTemplateSerializer +from .models import VirtualMachineTemplate, OpenNebulaManager -# Create your views here. +class TemplateCreateView(generics.ListCreateAPIView): + """This class defines the create behavior of our rest api.""" + queryset = VirtualMachineTemplate.objects.all() + serializer_class = VirtualMachineTemplateSerializer + + def perform_create(self, serializer): + """Save the post data when creating a new template.""" + serializer.save() + +class TemplateDetailsView(generics.RetrieveUpdateDestroyAPIView): + """This class handles the http GET, PUT and DELETE requests.""" + + queryset = VirtualMachineTemplate.objects.all() + serializer_class = VirtualMachineTemplateSerializer