Commit 736b1c95 by Bodor Máté

Merge DEV to template

parents 183bc1db ee5bcf00
......@@ -2,3 +2,4 @@
recircle/db.sqlite3
recircle/clouds.yaml
environment.sh
.idea/
\ No newline at end of file
......@@ -4,19 +4,18 @@ stages:
- lint
- test
before_script:
- pip install pipenv
- pipenv install -d
- git submodule sync --recursive
- git submodule update --init --recursive
flake8:
before_script:
- pip install flake8
stage: lint
script:
- flake8 --max-line-length=125 --exclude=migrations
- pipenv run flake8
test:
before_script:
- pip install pipenv
- pipenv install -d
- git submodule sync --recursive
- git submodule update --init --recursive
script:
- cd recircle
- pipenv run python manage.py test
- cd recircle
- pipenv run python manage.py test
......@@ -7,6 +7,7 @@ verify_ssl = true
httpie = "*"
flake8 = "*"
django-rest-swagger = "*"
coverage = "*"
[packages]
django = "*"
......
......@@ -458,6 +458,43 @@
],
"version": "==0.0.4"
},
"coverage": {
"hashes": [
"sha256:3684fabf6b87a369017756b551cef29e505cb155ddb892a7a29277b978da88b9",
"sha256:39e088da9b284f1bd17c750ac672103779f7954ce6125fd4382134ac8d152d74",
"sha256:3c205bc11cc4fcc57b761c2da73b9b72a59f8d5ca89979afb0c1c6f9e53c7390",
"sha256:465ce53a8c0f3a7950dfb836438442f833cf6663d407f37d8c52fe7b6e56d7e8",
"sha256:48020e343fc40f72a442c8a1334284620f81295256a6b6ca6d8aa1350c763bbe",
"sha256:5296fc86ab612ec12394565c500b412a43b328b3907c0d14358950d06fd83baf",
"sha256:5f61bed2f7d9b6a9ab935150a6b23d7f84b8055524e7be7715b6513f3328138e",
"sha256:68a43a9f9f83693ce0414d17e019daee7ab3f7113a70c79a3dd4c2f704e4d741",
"sha256:6b8033d47fe22506856fe450470ccb1d8ba1ffb8463494a15cfc96392a288c09",
"sha256:7ad7536066b28863e5835e8cfeaa794b7fe352d99a8cded9f43d1161be8e9fbd",
"sha256:7bacb89ccf4bedb30b277e96e4cc68cd1369ca6841bde7b005191b54d3dd1034",
"sha256:839dc7c36501254e14331bcb98b27002aa415e4af7ea039d9009409b9d2d5420",
"sha256:8f9a95b66969cdea53ec992ecea5406c5bd99c9221f539bca1e8406b200ae98c",
"sha256:932c03d2d565f75961ba1d3cec41ddde00e162c5b46d03f7423edcb807734eab",
"sha256:988529edadc49039d205e0aa6ce049c5ccda4acb2d6c3c5c550c17e8c02c05ba",
"sha256:998d7e73548fe395eeb294495a04d38942edb66d1fa61eb70418871bc621227e",
"sha256:9de60893fb447d1e797f6bf08fdf0dbcda0c1e34c1b06c92bd3a363c0ea8c609",
"sha256:9e80d45d0c7fcee54e22771db7f1b0b126fb4a6c0a2e5afa72f66827207ff2f2",
"sha256:a545a3dfe5082dc8e8c3eb7f8a2cf4f2870902ff1860bd99b6198cfd1f9d1f49",
"sha256:a5d8f29e5ec661143621a8f4de51adfb300d7a476224156a39a392254f70687b",
"sha256:aca06bfba4759bbdb09bf52ebb15ae20268ee1f6747417837926fae990ebc41d",
"sha256:bb23b7a6fd666e551a3094ab896a57809e010059540ad20acbeec03a154224ce",
"sha256:bfd1d0ae7e292105f29d7deaa9d8f2916ed8553ab9d5f39ec65bcf5deadff3f9",
"sha256:c62ca0a38958f541a73cf86acdab020c2091631c137bd359c4f5bddde7b75fd4",
"sha256:c709d8bda72cf4cd348ccec2a4881f2c5848fd72903c185f363d361b2737f773",
"sha256:c968a6aa7e0b56ecbd28531ddf439c2ec103610d3e2bf3b75b813304f8cb7723",
"sha256:df785d8cb80539d0b55fd47183264b7002077859028dfe3070cf6359bf8b2d9c",
"sha256:f406628ca51e0ae90ae76ea8398677a921b36f0bd71aab2099dfed08abd0322f",
"sha256:f46087bbd95ebae244a0eda01a618aff11ec7a069b15a3ef8f6b520db523dcf1",
"sha256:f8019c5279eb32360ca03e9fac40a12667715546eed5c5eb59eb381f2f501260",
"sha256:fc5f4d209733750afd2714e9109816a29500718b32dd9a5db01c0cb3a019b96a"
],
"index": "pypi",
"version": "==4.5.3"
},
"django-rest-swagger": {
"hashes": [
"sha256:48f6aded9937e90ae7cbe9e6c932b9744b8af80cc4e010088b3278c700e0685b",
......
# Generated by Django 2.2.3 on 2019-07-15 13:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('image', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Image',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(help_text='Human readable name of image.', max_length=100, verbose_name='name')),
('description', models.TextField(blank=True, help_text='Description of the image.', verbose_name='description')),
('remote_ID', models.CharField(help_text='ID, which helps access the image.', max_length=40, unique=True, verbose_name='remote_ID')),
('created_at', models.DateTimeField(auto_now_add=True, help_text='Date, when the image created.')),
],
),
]
......@@ -6,7 +6,7 @@ from django.conf import settings
from image.serializers import DiskSerializer
from image.models import Disk
from interface_openstack.implementation.image.openstack_image_manager import (
OpenstackImageManager,
OpenstackImageManager
)
......
from django.contrib import admin
from instance.models import Instance
from instance.models import Instance, Flavor, Lease
admin.site.register(Instance)
admin.site.register(Flavor)
admin.site.register(Lease)
# Generated by Django 2.2.1 on 2019-07-04 11:54
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('image', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('instance', '0005_auto_20190513_1203'),
]
operations = [
migrations.CreateModel(
name='Flavor',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(blank=True, max_length=100)),
('description', models.CharField(blank=True, max_length=200)),
('remote_id', models.CharField(help_text='ID of the instance on the backend', max_length=100)),
('ram', models.IntegerField(blank=True, null=True)),
('vcpu', models.IntegerField(blank=True, null=True)),
('initial_disk', models.IntegerField(blank=True, null=True)),
('priority', models.IntegerField(blank=True, null=True)),
],
),
migrations.CreateModel(
name='Lease',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(blank=True, max_length=100)),
('description', models.CharField(blank=True, max_length=100)),
('suspend_interval_in_sec', models.IntegerField(blank=True, null=True)),
('delete_interval_in_sec', models.IntegerField(blank=True, null=True)),
],
),
migrations.AddField(
model_name='instance',
name='disks',
field=models.ManyToManyField(help_text='Disks attached to instance', related_name='instance', to='image.Disk', verbose_name='disks'),
),
migrations.AddField(
model_name='instance',
name='owner',
field=models.ForeignKey(default=None, on_delete='CASCADE', to=settings.AUTH_USER_MODEL),
preserve_default=False,
),
migrations.AlterField(
model_name='instance',
name='lease',
field=models.ForeignKey(on_delete='CASCADE', to='instance.Lease'),
),
migrations.AddField(
model_name='instance',
name='flavor',
field=models.ForeignKey(default=None, help_text='Reasources given to the vm', on_delete='CASCADE', to='instance.Flavor', verbose_name='flavor'),
preserve_default=False,
),
]
# Generated by Django 2.2.1 on 2019-07-04 12:56
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('instance', '0006_auto_20190704_1154'),
]
operations = [
migrations.AlterField(
model_name='instance',
name='owner',
field=models.ForeignKey(null=True, on_delete='CASCADE', to=settings.AUTH_USER_MODEL),
),
]
# Generated by Django 2.2.1 on 2019-07-04 13:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('instance', '0007_auto_20190704_1256'),
]
operations = [
migrations.AlterField(
model_name='instance',
name='time_of_delete',
field=models.DateTimeField(blank=True, help_text='After this point in time, the instance will be deleted!'),
),
migrations.AlterField(
model_name='instance',
name='time_of_suspend',
field=models.DateTimeField(blank=True, help_text='After this point in time, the instance will be suspended'),
),
]
# Generated by Django 2.2.3 on 2019-07-15 13:54
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'),
),
]
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.utils import timezone
from datetime import timedelta
from image.models import Disk
from interface_openstack.implementation.vm.instance import (
OSVirtualMachineManager
)
ACCESS_METHODS = tuple(
[(key, val[0]) for key, val in settings.VM_ACCESS_PROTOCOLS.items()]
)
# Later stored in database
LEASE_TYPES = tuple(
[(val["name"], val["verbose_name"]) for val in settings.LEASE_TYPES]
)
class Lease(models.Model):
""" Users can use the virtual machine until the lease dates.
After suspend interval the vm suspends and after delete it will be
destroyed
"""
name = models.CharField(blank=True, max_length=100)
description = models.CharField(blank=True, max_length=100)
suspend_interval_in_sec = models.IntegerField(blank=True, null=True)
delete_interval_in_sec = models.IntegerField(blank=True, null=True)
class Flavor(models.Model):
""" Flavors are reasource packages, contains all information about
resources accociated with the virtual machine
"""
name = models.CharField(blank=True, max_length=100)
description = models.CharField(blank=True, max_length=200)
remote_id = models.CharField(
max_length=100, help_text="ID of the instance on the backend"
)
ram = models.IntegerField(blank=True, null=True)
vcpu = models.IntegerField(blank=True, null=True)
initial_disk = models.IntegerField(blank=True, null=True)
priority = models.IntegerField(blank=True, null=True)
@classmethod
def create(cls, name, description, ram=0, vcpu=0,
initial_disk=0, priority=0):
interface = OSVirtualMachineManager(settings.CONNECTION)
remote_flavor = interface.create_flavor(name, ram, vcpu, initial_disk)
flavor = cls(name=name, description=description,
remote_id=remote_flavor.id, ram=ram, vcpu=vcpu,
initial_disk=initial_disk, priority=priority)
flavor.save()
return flavor
class Instance(models.Model):
name = models.CharField(max_length=100, help_text="Human readable name of instance")
"""Virtual machine instance.
"""
name = models.CharField(max_length=100,
help_text="Human readable name of instance")
remote_id = models.CharField(
max_length=100, help_text="ID of the instance on the backend"
)
......@@ -21,25 +66,79 @@ class Instance(models.Model):
blank=True, help_text="The description of the instance"
)
access_method = models.CharField(
max_length=10, choices=ACCESS_METHODS, help_text="Primary remote access method"
max_length=10, choices=ACCESS_METHODS,
help_text="Primary remote access method"
)
system = models.CharField(max_length=50, help_text="Operating system type")
password = models.CharField(
max_length=50, help_text="Original password of the instance"
)
lease = models.CharField(
max_length=50, choices=LEASE_TYPES, help_text="Expiration method"
)
time_of_suspend = models.DateTimeField(
blank=True,
help_text="After this point in time, the instance will be suspended"
)
time_of_delete = models.DateTimeField(
blank=True,
help_text="After this point in time, the instance will be deleted!"
)
deleted = models.BooleanField(
help_text="Indicates if the instance is ready for garbage collection",
default=False,
)
# template
# disks
# owner
# image = models.ForeignKey(TemplateImage, related_name="vm", null=True,
# help_text="The base image of the vm")
#
# snapshot = models.ForeignKey(Snapshot, related_name="vm", null=True,
# help_text="The base snapshot of the vm")
disks = models.ManyToManyField(Disk, related_name="instance",
help_text="Disks attached to instance",
verbose_name="disks")
owner = models.ForeignKey(User, on_delete="CASCADE", null=True)
flavor = models.ForeignKey(Flavor, help_text="Reasources given to the vm",
verbose_name="flavor", on_delete="CASCADE",
related_name='instances')
lease = models.ForeignKey(Lease, on_delete="CASCADE",
related_name='instances')
@classmethod
def create(cls, lease, owner, flavor, remote_id, params):
inst = cls(lease=lease, flavor=flavor, owner=owner,
remote_id=remote_id, **params)
inst.full_clean()
inst.save()
return inst
@classmethod
def create_instance_from_template(cls, params, template, owner, lease,
disks, networks, flavor):
# TODO: attach disks when the remote instance created
interface = OSVirtualMachineManager(settings.CONNECTION)
remote_inst = interface.create_vm_from_template(params["name"],
template.remote_ID,
flavor.remote_id,
networks,
)
remote_id = remote_inst.id
new_inst = cls.create(lease, owner, flavor, remote_id, params)
return new_inst
def clean(self, *args, **kwargs):
self.time_of_suspend, self.time_of_delete = self.get_renew_times()
super(Instance, self).clean(*args, **kwargs)
def get_renew_times(self, lease=None):
"""Returns new suspend and delete times if renew would be called.
"""
if lease is None:
lease = self.lease
return (
timezone.now() + timedelta(
seconds=lease.suspend_interval_in_sec),
timezone.now() + timedelta(
seconds=lease.delete_interval_in_sec)
)
from rest_framework import serializers
from .models import Instance
class InstanceSerializer(serializers.ModelSerializer):
class Meta:
model = Instance
fields = "__all__"
from rest_framework import serializers
from .models import Flavor, Instance
class InstanceSerializer(serializers.ModelSerializer):
lease = serializers.PrimaryKeyRelatedField(read_only=True)
flavor = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Instance
fields = ("name", "description", "system", "lease", "flavor")
class FlavorSerializer(serializers.ModelSerializer):
class Meta:
model = Flavor
fields = "__all__"
from django.dispatch import receiver
from django.db.models.signals import pre_delete
from django.conf import settings
from .models import Instance
from interface_openstack.implementation.vm.instance import (
OSVirtualMachineManager
)
@receiver(pre_delete, sender=Instance)
def delete_remote_instance(sender, instance, **kwargs):
interface = OSVirtualMachineManager(settings.CONNECTION)
interface.destroy_vm(instance.remote_id)
......@@ -6,6 +6,7 @@ urlpatterns = [
path("instances/", views.InstanceList.as_view()),
path("instances/<int:pk>/", views.InstanceDetail.as_view()),
# path('instances/<int:pk>/action/', views.InstanceAction.as_view())
path("flavors/", views.FlavorListView.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
from instance.models import Instance
from instance.serializers import InstanceSerializer
from instance.serializers import InstanceSerializer, FlavorSerializer
from django.http import Http404
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
import datetime
from interface_openstack.implementation.vm.instance import OSVirtualMachineManager
from django.conf import settings
from interface_openstack.implementation.vm.instance import (
OSVirtualMachineManager
)
from template.models import PureTemplate
from instance.models import Instance, Flavor, Lease
class InstanceList(APIView):
......@@ -17,26 +18,23 @@ class InstanceList(APIView):
def post(self, request, format=None):
data = request.data
interface = OSVirtualMachineManager(settings.CONNECTION)
imageId = "da51253f-867c-472d-8ce0-81e7b7126d60"
flavorId = "1"
networks = [{"uuid": "c03d0d4b-413e-4cc6-9ebe-c0b5ca0dac3a"}]
newBackendInstance = interface.create_vm_from_template(
"Integration test vm 2", imageId, flavorId, networks
)
newInstance = Instance(
name=data["name"],
remote_id=newBackendInstance.id,
description=data["description"],
access_method="ssh",
system=data["system"],
password="12345678",
lease=data["lease"],
time_of_suspend=datetime.datetime.now(),
time_of_delete=datetime.datetime.now(),
deleted=False,
template = InstanceTemplate.objects.get(pk=data["template"])
flavor = Flavor.objects.get(pk=data["flavor"])
lease = Lease.objects.get(pk=data["lease"])
newInstance = Instance.create_instance_from_template(
params={"name": data["name"],
"description": data["description"],
"access_method": data["access"],
"system": data["system"],
},
lease=lease,
networks=template.networks,
template=template,
flavor=flavor,
owner=request.user,
disks=template.disks
)
newInstance.save()
return Response(newInstance.pk)
......@@ -75,3 +73,24 @@ class InstanceDetail(APIView):
instance = self.get_object(pk)
instance.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class FlavorListView(APIView):
"""
Create, update or delete a flavor.
"""
def get(self, request, format=None):
flavors = Flavor.objects.all()
return Response(FlavorSerializer(flavors, many=True).data)
def post(self, request, format=None):
data = request.data
new_flavor = Flavor.create(name=data["name"],
description=data["description"],
ram=data["ram"],
vcpu=data["vcpu"],
initial_disk=data["initial_disk"],
priority=data["priority"])
return Response(new_flavor.pk)
Subproject commit e01d873c78ac17fed0438936f979de3cbaca6a5e
Subproject commit 7b2647531e54da62fcf1db4c61a5e0530e977da4
# Generated by Django 2.2.3 on 2019-07-15 13:54
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('image', '0002_image'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('template', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='basetemplate',
name='created_by',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.DO_NOTHING, related_name='created_templates', to=settings.AUTH_USER_MODEL),
preserve_default=False,
),
migrations.CreateModel(
name='PureTemplate',
fields=[
('basetemplate_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='template.BaseTemplate')),
('images', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='templates', to='image.Image')),
],
bases=('template.basetemplate',),
),
]
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from template import views
urlpatterns = [
path("template/", views.TemplateList.as_view()),
# path("template/<int:pk>/", views.TemplateDetail.as_view()),
# path('instances/<int:pk>/action/', views.InstanceAction.as_view())
]
urlpatterns = format_suffix_patterns(urlpatterns)
\ No newline at end of file
[flake8]
exclude =
# No need to traverse our git directory
.git,
# No need to flake8 the other repo
recircle/interface_openstack
# No need to check migrations
migrations
max-line-length = 100
\ No newline at end of file
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