Skip to content

Commit

Permalink
Implemented the API
Browse files Browse the repository at this point in the history
  • Loading branch information
miha-plesko authored and matejart committed Mar 21, 2016
1 parent 58b88e9 commit 832a235
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 47 deletions.
27 changes: 27 additions & 0 deletions dice_deploy_django/cfy_wrapper/migrations/0002_container.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-03-10 09:41
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion
import uuid


class Migration(migrations.Migration):

dependencies = [
('cfy_wrapper', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='Container',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('blueprint', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='cfy_wrapper.Blueprint')),
],
options={
'abstract': False,
},
),
]
34 changes: 34 additions & 0 deletions dice_deploy_django/cfy_wrapper/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.db import models
from rest_framework.exceptions import NotFound
from enum import Enum
from django.db import IntegrityError


class Base(models.Model):
Expand Down Expand Up @@ -42,3 +43,36 @@ def cfy_id(self):
@property
def state_name(self):
return Blueprint.State(self.state).name

def pipe_deploy_blueprint(self):
""" Defines and starts async pipeline for deploying blueprint to cloudify """
from cfy_wrapper import tasks
pipe = (
tasks.upload_blueprint.si(self.cfy_id) |
tasks.create_deployment.si(self.cfy_id) |
tasks.install.si(self.cfy_id)
)
pipe.apply_async()

def pipe_undeploy_blueprint(self):
""" Defines and starts async pipeline for undeploying blueprint from cloudify """
from cfy_wrapper import tasks
pipe = (
tasks.uninstall.si(self.cfy_id) |
tasks.delete_deployment.si(self.cfy_id) |
tasks.delete_blueprint.si(self.cfy_id)
)
pipe.apply_async()


class Container(Base):
# Fields
id = models.UUIDField(
primary_key=True, default=uuid.uuid4, editable=False
)
blueprint = models.ForeignKey(Blueprint, null=True)

def delete(self, using=None, keep_parents=False):
if self.blueprint is not None:
raise IntegrityError('Cannot delete container with existing blueprint')
super(Container, self).delete(using, keep_parents)
10 changes: 9 additions & 1 deletion dice_deploy_django/cfy_wrapper/serializers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
from rest_framework import serializers

from .models import Blueprint
from .models import Blueprint, Container


class BlueprintSerializer(serializers.ModelSerializer):
class Meta:
model = Blueprint
fields = ("state_name", "cfy_id")


class ContainerSerializer(serializers.ModelSerializer):
blueprint = BlueprintSerializer()

class Meta:
model = Container
fields = ("id", "blueprint")
11 changes: 11 additions & 0 deletions dice_deploy_django/cfy_wrapper/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,24 @@
DebugView,
BlueprintsView,
BlueprintIdView,
ContainersView,
ContainerIdView,
ContainerBlueprint
)

urlpatterns = [
url(r"^debug/?$",
DebugView.as_view(), name="debug"),
# blueprint
url(r"^blueprints/?$",
BlueprintsView.as_view(), name="blueprints"),
url(r"^blueprints/(?P<blueprint_id>[0-9a-f-]+)/?$",
BlueprintIdView.as_view(), name="blueprint_id"),
# container
url(r"^containers/?$",
ContainersView.as_view(), name="containers"),
url(r"^containers/(?P<container_id>[0-9a-f-]+)/?$",
ContainerIdView.as_view(), name="container_id"),
url(r"^containers/(?P<container_id>[0-9a-f-]+)/blueprints?$",
ContainerBlueprint.as_view(), name="container_blueprint"),
]
103 changes: 76 additions & 27 deletions dice_deploy_django/cfy_wrapper/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.parsers import MultiPartParser, FileUploadParser
from rest_framework import status
from django.db import IntegrityError

from . import tasks
from .models import Blueprint
from .serializers import BlueprintSerializer
from .models import Blueprint, Container
from .serializers import BlueprintSerializer, ContainerSerializer

logger = logging.getLogger("views")

Expand All @@ -23,43 +25,90 @@ class BlueprintsView(APIView):

def get(self, request):
"""
# List all available blueprints
List all available blueprints
"""
s = BlueprintSerializer(Blueprint.objects.all(), many=True)
return Response(s.data)

def put(self, request):
"""
# Upload new blueprint archive
"""
b = Blueprint.objects.create(archive=request.data["file"])
s = BlueprintSerializer(b)
pipe = (
tasks.upload_blueprint.si(b.cfy_id) |
tasks.create_deployment.si(b.cfy_id) |
tasks.install.si(b.cfy_id)
)
pipe.apply_async()
return Response(s.data, status=201)


class BlueprintIdView(APIView):
def get(self, request, blueprint_id):
"""
# Return selected blueprint details
Return selected blueprint details
"""
s = BlueprintSerializer(Blueprint.get(blueprint_id))
return Response(s.data)

def delete(self, request, blueprint_id):
"""
# Delete selected blueprint
Delete selected blueprint
"""
blueprint = Blueprint.get(blueprint_id)
blueprint.pipe_undeploy_blueprint()
return Response(status=status.HTTP_202_ACCEPTED)


class ContainersView(APIView):
def get(self, request):
"""
List all virtual containers and their status information
"""
contaiers = Container.objects.all()
s = ContainerSerializer(contaiers, many=True)
return Response(data=s.data)

def post(self, request):
container = Container()
container.save() # all default is good
s = ContainerSerializer(container)
return Response(data=s.data, status=status.HTTP_201_CREATED)


class ContainerIdView(APIView):
def get(self, request, container_id):
"""
Display the status information about the selected virtual container
"""
container = Container.get(container_id)
s = ContainerSerializer(container)
return Response(s.data)

def delete(self, request, container_id):
"""
Remove virtual container and undeploy its blueprint.
"""
b = Blueprint.get(blueprint_id)
pipe = (
tasks.uninstall.si(b.cfy_id) |
tasks.delete_deployment.si(b.cfy_id) |
tasks.delete_blueprint.si(b.cfy_id)
)
pipe.apply_async()
return Response(status=202)
container = Container.get(container_id)
try:
container.delete()
except IntegrityError, e:
return Response({'msg': e.message}, status=status.HTTP_400_BAD_REQUEST)

return Response(status=status.HTTP_204_NO_CONTENT)


class ContainerBlueprint(APIView):
def post(self, request, container_id):
cont = Container.get(container_id)
blueprint_old = cont.blueprint
blueprint_new = Blueprint.objects.create(archive=request.data["file"])

# bind new blueprint to this container
cont.blueprint = blueprint_new
cont.save()

# deploy the new blueprint
blueprint_new.pipe_deploy_blueprint()

# undeploy the old blueprint
if blueprint_old:
# TODO: keep container-blueprint binding to old blueprint until cloudify undeploys it
blueprint_old.pipe_undeploy_blueprint()

cont_ser = ContainerSerializer(cont).data
return Response(cont_ser, status=status.HTTP_202_ACCEPTED)






1 change: 1 addition & 0 deletions dice_deploy_django/requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ cloudify_rest_client
celery
enum34
flower
django-factory-boy
15 changes: 13 additions & 2 deletions dice_deploy_django/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,25 @@
#
amqp==1.4.7 # via kombu
anyjson==0.3.3 # via kombu
babel==2.2.0 # via flower
backports.ssl-match-hostname==3.5.0.1 # via tornado
billiard==3.3.0.20 # via celery
celery==3.1.18
certifi==2016.2.28 # via tornado
cloudify-rest-client==3.2.1
django-factory-boy==1.0.0
django==1.9.4
djangorestframework==3.2.4
enum34==1.0.4
factory-boy==2.6.1 # via django-factory-boy
fake-factory==0.5.7 # via factory-boy
flower==0.8.4
futures==3.0.5 # via flower
ipaddress==1.0.16 # via fake-factory
kombu==3.0.28 # via celery
markdown==2.6.2
pytz==2015.6 # via celery
python-dateutil==2.5.0 # via fake-factory
pytz==2015.7 # via babel, celery, flower
requests==2.7.0 # via cloudify-rest-client
flower==0.8.4
six==1.10.0 # via fake-factory, python-dateutil
tornado==4.2.0 # via flower
34 changes: 34 additions & 0 deletions dice_deploy_django/unit_tests/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import factory
from cfy_wrapper.models import Container, Blueprint
from django.conf import settings


class BlueprintPendingFactory(factory.DjangoModelFactory):
state = Blueprint.State.pending.value
archive = factory.django.FileField(from_path=settings.TEST_FILE_BLUEPRINT_EXAMPLE)

class Meta:
model = Blueprint


class BlueprintDeployedFactory(factory.DjangoModelFactory):
state = Blueprint.State.deployed.value
archive = factory.django.FileField(from_path=settings.TEST_FILE_BLUEPRINT_EXAMPLE)

class Meta:
model = Blueprint


class ContainerEmptyFactory(factory.DjangoModelFactory):
class Meta:
model = Container


class ContainerFullFactory(factory.DjangoModelFactory):
blueprint = factory.SubFactory(BlueprintDeployedFactory)

class Meta:
model = Container



Loading

0 comments on commit 832a235

Please sign in to comment.