Commit b1fc3c9d by Bodor Máté

Merge DEV to image_model_test

parents 44c637b3 3a808815
# IDEs
.vscode/ .vscode/
recircle/db.sqlite3
recircle/clouds.yaml
environment.sh
.idea/ .idea/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
example.py
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don’t work, or not
# install all needed dependencies.
#Pipfile.lock
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
environment.sh
# Cloud configure
clouds.yaml
...@@ -13,11 +13,11 @@ django-nose = "*" ...@@ -13,11 +13,11 @@ django-nose = "*"
[packages] [packages]
django = "*" django = "*"
djangorestframework = "*" djangorestframework = "*"
djoser = "*"
django-cors-headers = "*" django-cors-headers = "*"
openstacksdk = "*" openstacksdk = "*"
python-novaclient = "*" python-novaclient = "*"
keystoneauth1 = "*" keystoneauth1 = "*"
djoser = "*"
[requires] [requires]
python_version = "3.6" python_version = "3.6"
...@@ -121,11 +121,11 @@ ...@@ -121,11 +121,11 @@
}, },
"django": { "django": {
"hashes": [ "hashes": [
"sha256:4d23f61b26892bac785f07401bc38cbf8fa4cec993f400e9cd9ddf28fd51c0ea", "sha256:16a5d54411599780ac9dfe3b9b38f90f785c51259a584e0b24b6f14a7f69aae8",
"sha256:6e974d4b57e3b29e4882b244d40171d6a75202ab8d2402b8e8adbd182e25cf0c" "sha256:9a2f98211ab474c710fcdad29c82f30fc14ce9917c7a70c3682162a624de4035"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.2.3" "version": "==2.2.4"
}, },
"django-cors-headers": { "django-cors-headers": {
"hashes": [ "hashes": [
...@@ -272,11 +272,11 @@ ...@@ -272,11 +272,11 @@
}, },
"openstacksdk": { "openstacksdk": {
"hashes": [ "hashes": [
"sha256:dc1232a58e30876ed6b28ee7bf5fee281b70048b187e88acd8a53cc3b63f9d8a", "sha256:ae521b4083ecc3395e27b6a7d0f119a737cefb2f76277f16dc5b626a3c4d5c52",
"sha256:f6e045d2e0a111d3a8dd157d111a04f1354ad6cc7819f6c1db073426bea7734f" "sha256:e3a1346a238d57d4f398f345a79d03b6705e229a4453f8b73acdcd00d04e6328"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.31.2" "version": "==0.32.0"
}, },
"os-service-types": { "os-service-types": {
"hashes": [ "hashes": [
...@@ -308,10 +308,10 @@ ...@@ -308,10 +308,10 @@
}, },
"pbr": { "pbr": {
"hashes": [ "hashes": [
"sha256:0ca44dc9fd3b04a22297c2a91082d8df2894862e8f4c86a49dac69eae9e85ca0", "sha256:56e52299170b9492513c64be44736d27a512fa7e606f21942160b68ce510b4bc",
"sha256:4aed6c1b1fa5020def0f22aed663d87b81bb3235f112490b07d2643d7a98c5b5" "sha256:9b321c204a88d8ab5082699469f52cc94c5da45c51f114113d01b3d993c24cdf"
], ],
"version": "==5.4.1" "version": "==5.4.2"
}, },
"prettytable": { "prettytable": {
"hashes": [ "hashes": [
...@@ -344,26 +344,28 @@ ...@@ -344,26 +344,28 @@
}, },
"pytz": { "pytz": {
"hashes": [ "hashes": [
"sha256:303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", "sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32",
"sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141" "sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7"
], ],
"version": "==2019.1" "version": "==2019.2"
}, },
"pyyaml": { "pyyaml": {
"hashes": [ "hashes": [
"sha256:57acc1d8533cbe51f6662a55434f0dbecfa2b9eaf115bede8f6fd00115a0c0d3", "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9",
"sha256:588c94b3d16b76cfed8e0be54932e5729cc185caffaa5a451e7ad2f7ed8b4043", "sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4",
"sha256:68c8dd247f29f9a0d09375c9c6b8fdc64b60810ebf07ba4cdd64ceee3a58c7b7", "sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8",
"sha256:70d9818f1c9cd5c48bb87804f2efc8692f1023dac7f1a1a5c61d454043c1d265", "sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696",
"sha256:86a93cccd50f8c125286e637328ff4eef108400dd7089b46a7be3445eecfa391", "sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34",
"sha256:a0f329125a926876f647c9fa0ef32801587a12328b4a3c741270464e3e4fa778", "sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9",
"sha256:a3c252ab0fa1bb0d5a3f6449a4826732f3eb6c0270925548cac342bc9b22c225", "sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73",
"sha256:b4bb4d3f5e232425e25dda21c070ce05168a786ac9eda43768ab7f3ac2770955", "sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299",
"sha256:cd0618c5ba5bda5f4039b9398bb7fb6a317bb8298218c3de25c47c4740e4b95e", "sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b",
"sha256:ceacb9e5f8474dcf45b940578591c7f3d960e82f926c707788a570b51ba59190", "sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae",
"sha256:fe6a88094b64132c4bb3b631412e90032e8cfe9745a58370462240b8cb7553cd" "sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681",
], "sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41",
"version": "==5.1.1" "sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8"
],
"version": "==5.1.2"
}, },
"requests": { "requests": {
"hashes": [ "hashes": [
......
...@@ -86,7 +86,9 @@ class Image(models.Model): ...@@ -86,7 +86,9 @@ class Image(models.Model):
uploaded_by_user=False, uploaded_by_user=False,
description=description description=description
) )
return new_image for attr, value in new_image.__dict__.items():
setattr(remote_image, attr, value)
return remote_image
@classmethod @classmethod
def create_from_user(cls, description, def create_from_user(cls, description,
...@@ -102,4 +104,24 @@ class Image(models.Model): ...@@ -102,4 +104,24 @@ class Image(models.Model):
uploaded_by_user=True, uploaded_by_user=True,
description=description description=description
) )
return new_image for attr, value in new_image.__dict__.items():
setattr(remote_image, attr, value)
return remote_image
def delete(self):
interface = OpenstackImageManager(settings.CONNECTION)
if interface.delete(self.remote_id):
super().delete()
def get(self):
interface = OpenstackImageManager(settings.CONNECTION)
image = interface.get(self.remote_id)
for attr, value in self.__dict__.items():
setattr(image, attr, value)
return image
def update(self, data):
for (key, value) in data.items():
setattr(self, key, value)
self.save()
return self.get()
...@@ -3,9 +3,15 @@ from rest_framework import serializers ...@@ -3,9 +3,15 @@ from rest_framework import serializers
from .models import Image from .models import Image
class ImageUpdateSerializer(serializers.Serializer):
name = serializers.CharField(required=False)
description = serializers.CharField(required=False)
class ImageSerializer(serializers.ModelSerializer): class ImageSerializer(serializers.ModelSerializer):
image_file = serializers.FileField(write_only=True) image_file = serializers.FileField(write_only=True)
file_format = serializers.CharField(max_length=10, write_only=True) file_format = serializers.CharField(max_length=10)
size = serializers.IntegerField()
class Meta: class Meta:
model = Image model = Image
...@@ -18,5 +24,7 @@ class ImageSerializer(serializers.ModelSerializer): ...@@ -18,5 +24,7 @@ class ImageSerializer(serializers.ModelSerializer):
"created_at", "created_at",
"uploaded_by_user", "uploaded_by_user",
"created_by", "created_by",
"id",
"size",
) )
read_only_fields = ("created_at", "uploaded_by_user", "created_by", "remote_id", ) read_only_fields = ("created_at", "uploaded_by_user", "created_by", "remote_id", "size", )
# from django.shortcuts import render # from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ViewSet
from rest_framework.response import Response from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from rest_framework import status
from django.core.exceptions import ObjectDoesNotExist
from image.models import Image from image.models import Image
from image.serializers import ImageSerializer from image.serializers import ImageSerializer
from image.serializers import ImageUpdateSerializer
class ImageViewSet(ModelViewSet): class ImageViewSet(ViewSet):
serializer_class = ImageSerializer
queryset = Image.objects.all() def list(self, request):
# def list(self, request): image_list = []
# return HttpResponse("list") images = Image.objects.all()
for image in images:
image_list.append(image.get())
serializer = ImageSerializer(image_list, many=True)
return Response(serializer.data)
def create(self, request): def create(self, request):
serializer = ImageSerializer(data=request.data) serializer = ImageSerializer(data=request.data)
...@@ -26,14 +34,30 @@ class ImageViewSet(ModelViewSet): ...@@ -26,14 +34,30 @@ class ImageViewSet(ModelViewSet):
serializer = ImageSerializer(instance=new_image) serializer = ImageSerializer(instance=new_image)
return Response(serializer.data) return Response(serializer.data)
# def retrieve(self, request, pk=None): def retrieve(self, request, pk=None):
# return HttpResponse("retrive") queryset = Image.objects.all()
image = get_object_or_404(queryset, pk=pk)
serializer = ImageSerializer(instance=image)
image = image.get()
serializer = ImageSerializer(instance=image)
return Response(serializer.data)
# def update(self, request, pk=None): def update(self, request, pk=None):
# return HttpResponse("update") serializer = ImageUpdateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
queryset = Image.objects.all()
image = get_object_or_404(queryset, pk=pk)
image = image.update(serializer.validated_data)
serializer = ImageSerializer(instance=image)
return Response(serializer.data)
# def partial_update(self, request, pk=None): def partial_update(self, request, pk=None):
# return HttpResponse("patch") return self.update(request, pk)
# def destroy(self, request, pk=None): def destroy(self, request, pk=None):
# return HttpResponse("delete") try:
image = Image.objects.get(id=pk)
image.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except ObjectDoesNotExist:
return Response(status=status.HTTP_204_NO_CONTENT)
# Generated by Django 2.2.3 on 2019-07-15 09:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('instance', '0008_auto_20190704_1310'),
]
operations = [
migrations.AlterField(
model_name='instance',
name='flavor',
field=models.ForeignKey(help_text='Reasources given to the vm', on_delete='CASCADE', related_name='instances', to='instance.Flavor', verbose_name='flavor'),
),
migrations.AlterField(
model_name='instance',
name='lease',
field=models.ForeignKey(on_delete='CASCADE', related_name='instances', to='instance.Lease'),
),
]
# Generated by Django 2.2.3 on 2019-07-31 12:15 # Generated by Django 2.2.4 on 2019-08-08 10:41
from django.db import migrations from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('instance', '0009_auto_20190715_0929'), ('template', '0007_basetemplate_network_id'),
('instance', '0009_auto_20190715_1354'), ('instance', '0009_auto_20190715_1354'),
] ]
operations = [ operations = [
migrations.AddField(
model_name='instance',
name='template',
field=models.ForeignKey(help_text='The base image of the vm', null=True, on_delete='DO_NOTHING', related_name='vm', to='template.ImageTemplate'),
),
] ]
...@@ -15,6 +15,17 @@ ACCESS_METHODS = tuple( ...@@ -15,6 +15,17 @@ ACCESS_METHODS = tuple(
[(key, val[0]) for key, val in settings.VM_ACCESS_PROTOCOLS.items()] [(key, val[0]) for key, val in settings.VM_ACCESS_PROTOCOLS.items()]
) )
interface = OSVirtualMachineManager(settings.CONNECTION)
ACTIONS = {
"start": interface.start_vm,
"stop": interface.stop_vm,
"suspend": interface.suspend_vm,
"wake_up": interface.wake_up_vm,
"reset": interface.reset_vm,
"reboot": interface.reboot_vm,
}
class Lease(models.Model): class Lease(models.Model):
""" Users can use the virtual machine until the lease dates. """ Users can use the virtual machine until the lease dates.
...@@ -44,7 +55,6 @@ class Flavor(models.Model): ...@@ -44,7 +55,6 @@ class Flavor(models.Model):
@classmethod @classmethod
def create(cls, name, description, ram=0, vcpu=0, def create(cls, name, description, ram=0, vcpu=0,
initial_disk=0, priority=0): initial_disk=0, priority=0):
interface = OSVirtualMachineManager(settings.CONNECTION)
try: try:
remote_flavor = interface.create_flavor(name, ram, vcpu, initial_disk) remote_flavor = interface.create_flavor(name, ram, vcpu, initial_disk)
...@@ -55,12 +65,22 @@ class Flavor(models.Model): ...@@ -55,12 +65,22 @@ class Flavor(models.Model):
return flavor return flavor
except Exception as e: except Exception as e:
logger.error(str(e)) logger.error(str(e))
raise ValueError("Couldn't create Flavor in remote cloud.") raise ValueError("Can't create Flavor in remote cloud.")
def delete(self):
interface = OSVirtualMachineManager(settings.CONNECTION)
try:
interface.delete_flavor(self.remote_id)
super(Flavor, self).delete()
except Exception as e:
if e.OpenStackError:
logger.error("Can not delete the flavor in remote cloud")
class Instance(models.Model): class Instance(models.Model):
"""Virtual machine instance. """Virtual machine instance.
""" """
from template.models import ImageTemplate
name = models.CharField(max_length=100, name = models.CharField(max_length=100,
help_text="Human readable name of instance") help_text="Human readable name of instance")
...@@ -92,11 +112,9 @@ class Instance(models.Model): ...@@ -92,11 +112,9 @@ class Instance(models.Model):
default=False, default=False,
) )
# image = models.ForeignKey(TemplateImage, related_name="vm", null=True, template = models.ForeignKey(ImageTemplate, related_name="vm", null=True,
# help_text="The base image of the vm") help_text="The base image of the vm",
# on_delete="DO_NOTHING")
# snapshot = models.ForeignKey(Snapshot, related_name="vm", null=True,
# help_text="The base snapshot of the vm")
disks = models.ManyToManyField(Disk, related_name="instance", disks = models.ManyToManyField(Disk, related_name="instance",
help_text="Disks attached to instance", help_text="Disks attached to instance",
...@@ -110,9 +128,11 @@ class Instance(models.Model): ...@@ -110,9 +128,11 @@ class Instance(models.Model):
related_name='instances') related_name='instances')
@classmethod @classmethod
def create(cls, lease, owner, flavor, remote_id, params): def create(cls, lease, owner, flavor, template, remote_id, params):
params["password"] = cls.generate_password()
inst = cls(lease=lease, flavor=flavor, owner=owner, inst = cls(lease=lease, flavor=flavor, owner=owner,
remote_id=remote_id, **params) remote_id=remote_id, template=template, **params)
inst.full_clean()
inst.save() inst.save()
...@@ -123,19 +143,18 @@ class Instance(models.Model): ...@@ -123,19 +143,18 @@ class Instance(models.Model):
def create_instance_from_template(cls, params, template, owner, lease, def create_instance_from_template(cls, params, template, owner, lease,
disks, networks, flavor): disks, networks, flavor):
# TODO: attach disks when the remote instance created # TODO: attach disks when the remote instance created
interface = OSVirtualMachineManager(settings.CONNECTION)
try: try:
remote_inst = interface.create_vm_from_template(params["name"], remote_id = interface.create_vm_from_template(params["name"],
template.remote_ID, template.image.remote_id,
flavor.remote_id, flavor.remote_id,
networks, networks,
) )
remote_id = remote_inst.id new_inst = cls.create(lease, owner, flavor, template,
new_inst = cls.create(lease, owner, flavor, remote_id, params) remote_id, params)
return new_inst return new_inst
except Exception as e: except Exception as e:
logger.error(str(e)) logger.error(str(e))
raise ValueError("Couldn't create Flavor in remote cloud." raise ValueError("Can't create Instance in remote cloud."
"Search the logs for more detail.") "Search the logs for more detail.")
def clean(self, *args, **kwargs): def clean(self, *args, **kwargs):
...@@ -153,3 +172,26 @@ class Instance(models.Model): ...@@ -153,3 +172,26 @@ class Instance(models.Model):
timezone.now() + timedelta( timezone.now() + timedelta(
seconds=lease.delete_interval_in_sec) seconds=lease.delete_interval_in_sec)
) )
def delete(self):
try:
interface.destroy_vm(self.remote_id)
super(Instance, self).delete()
except Exception as e:
if e.OpenStackError:
logger.error("Can not delete the instance in remote cloud")
def execute_common_action(self, action):
if ACTIONS[action]:
return ACTIONS[action](self.remote_id)
else:
raise ValueError("This action is not supported!")
def get_remote_instance(self):
return interface.get_vm(self.remote_id)
@classmethod
def generate_password(self):
return User.objects.make_random_password(
allowed_chars='abcdefghijklmnopqrstuvwx'
'ABCDEFGHIJKLMNOPQRSTUVWX123456789')
from rest_framework import serializers from rest_framework import serializers
from .models import Flavor, Instance from .models import Flavor, Instance, Lease
class InstanceSerializer(serializers.ModelSerializer): class InstanceSerializer(serializers.ModelSerializer):
...@@ -8,10 +8,26 @@ class InstanceSerializer(serializers.ModelSerializer): ...@@ -8,10 +8,26 @@ class InstanceSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Instance model = Instance
fields = ("name", "description", "system", "lease", "flavor") fields = (
"name",
"description",
"system",
"lease",
"flavor",
"password",
"template",
"time_of_suspend",
"time_of_delete")
read_only_fields = ("password", "template", "time_of_suspend", "time_of_delete")
class FlavorSerializer(serializers.ModelSerializer): class FlavorSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Flavor model = Flavor
fields = "__all__" fields = "__all__"
class LeaseSerializer(serializers.ModelSerializer):
class Meta:
model = Lease
fields = '__all__'
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from instance import views from instance import views
from rest_framework import routers
urlpatterns = [ router = routers.SimpleRouter()
path("instances/", views.InstanceList.as_view()), router.register(r'instances', views.InstanceViewSet, basename='instance')
path("instances/<int:pk>/", views.InstanceDetail.as_view()), router.register(r'flavors', views.FlavorViewSet, basename='flavor')
# path('instances/<int:pk>/action/', views.InstanceAction.as_view()) router.register(r'leases', views.LeaseViewSet, basename='lease')
path("flavors/", views.FlavorListView.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
urlpatterns = router.urls
from instance.serializers import InstanceSerializer, FlavorSerializer, LeaseSerializer
from django.http import Http404 from django.http import Http404
from django.conf import settings from rest_framework.viewsets import ViewSet, ModelViewSet
from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import status from rest_framework import status
from rest_framework.decorators import action
from interface_openstack.implementation.vm.instance import ( from template.serializers import InstanceFromTemplateSerializer
OSVirtualMachineManager
)
from instance.models import Instance, Flavor, Lease from instance.models import Instance, Flavor, Lease
from instance.serializers import InstanceSerializer, FlavorSerializer
from template.models import ImageTemplate from template.models import ImageTemplate
from template.serializers import ImageTemplateModelSerializer
class InstanceList(APIView): class InstanceViewSet(ViewSet):
def get(self, request, format=None):
def get_object(self, pk):
try:
return Instance.objects.get(pk=pk)
except Instance.DoesNotExist:
raise Http404
def list(self, request):
instances = Instance.objects.all() instances = Instance.objects.all()
return Response(InstanceSerializer(instances, many=True).data) return Response(InstanceSerializer(instances, many=True).data)
def post(self, request, format=None): def create(self, request):
data = request.data data = request.data
template = ImageTemplate.objects.get(pk=data["template"]) template = ImageTemplate.objects.get(pk=data["template"])
flavor = Flavor.objects.get(pk=data["flavor"])
lease = Lease.objects.get(pk=data["lease"]) # TODO: if the user can select anouther lease and flavor
# That will be applied, not from the template
# flavor = Flavor.objects.get(pk=data["flavor"])
# lease = Lease.objects.get(pk=data["lease"])
newInstance = Instance.create_instance_from_template( newInstance = Instance.create_instance_from_template(
params={"name": data["name"], params={"name": data["name"],
...@@ -29,40 +39,26 @@ class InstanceList(APIView): ...@@ -29,40 +39,26 @@ class InstanceList(APIView):
"access_method": data["access"], "access_method": data["access"],
"system": data["system"], "system": data["system"],
}, },
lease=lease, lease=template.lease,
networks=template.networks, networks=[{"uuid": template.network_id}],
template=template, template=template,
flavor=flavor, flavor=template.flavor,
owner=request.user, owner=request.user,
disks=template.disks disks=None
) )
return Response(newInstance.pk) return Response(newInstance.pk)
def retrieve(self, request, pk):
class InstanceDetail(APIView):
"""
Retrieve, update or delete a snippet instance.
"""
def get_object(self, pk):
try:
return Instance.objects.get(pk=pk)
except Instance.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
instance = self.get_object(pk) instance = self.get_object(pk)
instanceDict = InstanceSerializer(instance).data instanceDict = InstanceSerializer(instance).data
remoteInstance = instance.get_remote_instance()
interface = OSVirtualMachineManager(settings.CONNECTION)
remoteInstance = interface.get_vm(instance.remote_id)
remoteInstanceDict = remoteInstance.__dict__ remoteInstanceDict = remoteInstance.__dict__
merged_dict = {**instanceDict, **remoteInstanceDict} merged_dict = {**instanceDict, **remoteInstanceDict}
return Response(merged_dict) return Response(merged_dict)
def put(self, request, pk, format=None): def update(self, request, pk, format=None):
instance = self.get_object(pk) instance = self.get_object(pk)
serializer = InstanceSerializer(instance, data=request.data) serializer = InstanceSerializer(instance, data=request.data)
if serializer.is_valid(): if serializer.is_valid():
...@@ -70,22 +66,48 @@ class InstanceDetail(APIView): ...@@ -70,22 +66,48 @@ class InstanceDetail(APIView):
return Response(serializer.data) return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None): def destroy(self, request, pk, format=None):
instance = self.get_object(pk) instance = self.get_object(pk)
instance.delete() instance.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)
@action(detail=True, methods=["post"])
def template(self, request, pk):
instance = self.get_object(pk)
serializer = InstanceFromTemplateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
data = serializer.validated_data
new_template = ImageTemplate.create_from_instance(data["name"],
data["description"],
instance,
request.user)
serializer = ImageTemplateModelSerializer(instance=new_template)
return Response(serializer.data)
@action(detail=True, methods=["POST"])
def actions(self, request, pk):
instance = self.get_object(pk)
success = instance.execute_common_action(action=request.data["action"])
class FlavorListView(APIView): return Response(success)
class FlavorViewSet(ViewSet):
""" """
Create, update or delete a flavor. Create, update or delete a flavor.
""" """
def get(self, request, format=None): def get_object(self, pk):
try:
return Flavor.objects.get(pk=pk)
except Flavor.DoesNotExist:
raise Http404
def list(self, request, format=None):
flavors = Flavor.objects.all() flavors = Flavor.objects.all()
return Response(FlavorSerializer(flavors, many=True).data) return Response(FlavorSerializer(flavors, many=True).data)
def post(self, request, format=None): def create(self, request, format=None):
data = request.data data = request.data
new_flavor = Flavor.create(name=data["name"], new_flavor = Flavor.create(name=data["name"],
description=data["description"], description=data["description"],
...@@ -95,3 +117,19 @@ class FlavorListView(APIView): ...@@ -95,3 +117,19 @@ class FlavorListView(APIView):
priority=data["priority"]) priority=data["priority"])
return Response(new_flavor.pk) return Response(new_flavor.pk)
def update(self, request, pk):
return Response(status=status.HTTP_400_BAD_REQUEST)
def partial_update(self, request, pk):
return Response(status=status.HTTP_400_BAD_REQUEST)
def destroy(self, request, pk):
flavor = self.get_object(pk)
flavor.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class LeaseViewSet(ModelViewSet):
queryset = Lease.objects.all()
serializer_class = LeaseSerializer
Subproject commit e01d873c78ac17fed0438936f979de3cbaca6a5e Subproject commit 1a19e4355f4af1abb49a3f6e07dc3a6c3f8bdf47
# Generated by Django 2.2.3 on 2019-08-07 12:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('template', '0006_auto_20190719_1416'),
]
operations = [
migrations.AddField(
model_name='basetemplate',
name='network_id',
field=models.CharField(blank=True, help_text='The new instance will be in this network.', max_length=100, null=True, verbose_name='network_id'),
),
]
...@@ -2,10 +2,8 @@ from django.db import models ...@@ -2,10 +2,8 @@ from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.conf import settings from django.conf import settings
from image.models import Disk from image.models import Disk, Image
from image.models import Image from instance.models import Lease, Flavor
from instance.models import Lease
from instance.models import Flavor
from interface_openstack.implementation.storage.openstack_snapshot_manager import SnapshotManager from interface_openstack.implementation.storage.openstack_snapshot_manager import SnapshotManager
...@@ -46,6 +44,13 @@ class BaseTemplate(models.Model): ...@@ -46,6 +44,13 @@ class BaseTemplate(models.Model):
related_name='templates') related_name='templates')
lease = models.ForeignKey(Lease, on_delete="CASCADE", lease = models.ForeignKey(Lease, on_delete="CASCADE",
related_name='templates') related_name='templates')
network_id = models.CharField(
max_length=100,
verbose_name="network_id",
help_text="The new instance will be in this network.",
null=True,
blank=True
)
class DiskTemplate(BaseTemplate): class DiskTemplate(BaseTemplate):
......
# from django.shortcuts import render # from django.shortcuts import render
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from rest_framework.decorators import action
from template.serializers import InstanceFromTemplateSerializer
from template.serializers import ImageTemplateModelSerializer from template.serializers import ImageTemplateModelSerializer
from template.models import ImageTemplate from template.models import ImageTemplate
...@@ -38,14 +35,3 @@ class ImageTemplateViewSet(ModelViewSet): ...@@ -38,14 +35,3 @@ class ImageTemplateViewSet(ModelViewSet):
request.data.pop(key, None) request.data.pop(key, None)
return super(ImageTemplateViewSet, self).update(request, partial=True) return super(ImageTemplateViewSet, self).update(request, partial=True)
@action(detail=True, methods=["post"])
def template(self, request, pk):
instance = self.get_object(pk)
serializer = InstanceFromTemplateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
data = serializer.validated_data
new_template = ImageTemplate.create_from_instance(data["name"], data["description"],
instance, request.user)
serializer = ImageTemplateModelSerializer(instance=new_template)
return Response(serializer.data)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment