Commit c307f65b authored by Lukas Burgey's avatar Lukas Burgey

Make deployment by vo work again

parent f20e7cfc
......@@ -2,15 +2,69 @@
# pylint: disable=abstract-method
from rest_framework import serializers
from rest_polymorphic.serializers import PolymorphicSerializer
from .. import OIDCConfig
from ..vo import VO, Group, Entitlement, EntitlementNameSpace
class OIDCConfigSerializer(serializers.ModelSerializer):
class Meta:
model = OIDCConfig
fields = ['name', 'id']
fields = (
'name',
'id',
)
class AuthInfoSerializer(serializers.Serializer):
idps = OIDCConfigSerializer(many=True)
default = serializers.IntegerField()
class EntitlementNameSpaceSerializer(serializers.ModelSerializer):
class Meta:
model = EntitlementNameSpace
fields = (
'name',
)
# polymorphic serializer
VO_FIELDS = (
'id',
'name',
'pretty_name',
'description',
)
class AbstractVOSerializer(serializers.ModelSerializer):
class Meta:
model = VO
fields = VO_FIELDS
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = VO_FIELDS
class EntitlementSerializer(serializers.ModelSerializer):
name_space = EntitlementNameSpaceSerializer()
class Meta:
model = Entitlement
fields = VO_FIELDS + (
'name_space',
'group_authority',
)
class VOSerializer(PolymorphicSerializer):
model_serializer_mapping = {
VO: AbstractVOSerializer,
Group: GroupSerializer,
Entitlement: EntitlementSerializer,
}
......@@ -13,10 +13,7 @@ class EntitlementNameSpaceSerializer(serializers.ModelSerializer):
# polymorphic serializer
VO_FIELDS = (
'id',
'name',
'pretty_name',
'description',
)
......
......@@ -6,7 +6,7 @@ from django.db import models
# these imports are exports!
from ..auth.v1.models.vo import VO
from .brokers import RabbitMQInstance
from .users import User
from .users import User, SSHPublicKey
LOGGER = getLogger(__name__)
......@@ -36,10 +36,9 @@ class Site(models.Model):
blank=True,
)
# tasks is what we send to the clients. the are the serialization of a deployment
@property
def pending_tasks(self):
tasks = {}
def pending_deployments(self):
deployments = {}
# ignores orphaned deployment states
dep_states = [
......@@ -50,11 +49,11 @@ class Site(models.Model):
) and state.parent is not None
]
# make the tasks unique here
# make the deployments unique here
for item in dep_states:
tasks[item.parent.id] = item.parent
deployments[item.parent.id] = item.parent
return tasks.values()
return deployments.values()
def __str__(self):
return self.name
......
......@@ -152,6 +152,14 @@ class RabbitMQInstance(SingletonModel):
def initialize(self):
self._connection
def publish(self, deployment, msg):
self._publish(
deployment.broker_exchange,
deployment.routing_key,
msg,
)
def publish_by_service(self, service, msg):
self._publish(
'services',
......
......@@ -48,6 +48,19 @@ def credential_default():
return {}
def get_deployment(user, vo=None, service=None):
if vo is not None and service is not None:
raise ValueError('Cannot create deployment for both vo and service')
if vo is not None:
return VODeployment.get_deployment(user, vo)
if service is not None:
return ServiceDeployment.get_deployment(user, service)
raise ValueError('Need vo or service to create deployment')
class Deployment(PolymorphicModel):
user = models.ForeignKey(
User,
......@@ -91,14 +104,14 @@ class Deployment(PolymorphicModel):
return self.state_target == self.state
def _set_target(self, target):
LOGGER.debug(self.msg('Target changed to '+target))
self.state_target = target
for credential_state in CredentialState.objects.filter(
target__parent=self,
):
credential_state.set_target(target)
LOGGER.debug(self.msg('Target changed to '+target))
self.save()
def user_deploy(self):
......@@ -129,26 +142,23 @@ class Deployment(PolymorphicModel):
self.publish()
def publish_to_client(self):
# avoiding circular dependencies here
# from .serializers.clients import DeploymentSerializer
# data = DeploymentSerializer(self).data
# msg = dumps(data)
from .serializers import clients
data = clients.DeploymentSerializer(self).data
msg = dumps(data)
# # backend.RabbitMQInstance.load().publish_by_vo(
# self.vo,
# msg,
# )
pass
RabbitMQInstance.load().publish(
self,
msg,
)
# sends a state update via RabbitMQ / STOMP to the users webpage instance
def publish_to_user(self):
if self.user is None:
return
# avoiding circular dependencies here
from .serializers.webpage import DeploymentSerializer
from . import serializers
msg = dumps({
'deployment': DeploymentSerializer(self).data,
'deployment': serializers.DeploymentSerializer(self).data,
})
RabbitMQInstance.load().publish_to_user(
self.user,
......@@ -180,14 +190,21 @@ class VODeployment(Deployment):
def services(self):
return self.vo.services.all()
@property
def broker_exchange(self):
return self.vo.broker_exchange
@property
def routing_key(self):
return self.vo.name
def create_state_items(self):
for service in self.services:
LOGGER.debug('create_state_items: creating DeploymentState for service %s at site %s', service, service.site)
DeploymentState.get_state_item(
parent=self,
user=self.user,
site=service.site,
service=service,
self,
self.user,
service.site,
service,
)
@classmethod
......@@ -210,15 +227,16 @@ class VODeployment(Deployment):
deployment.save()
deployment.create_state_items()
LOGGER.debug(deployment.msg('created'))
LOGGER.debug(deployment.msg('Created'))
return deployment
def service_added(self, service):
LOGGER.debug(self.msg('Adding service {}'.format(service)))
item = DeploymentState.get_state_item(
parent=self,
site=service.site,
service=service,
self,
self.user,
service.site,
service,
)
if self.state_target == 'deployed':
item.user_deploy()
......@@ -230,17 +248,6 @@ class VODeployment(Deployment):
def msg(self, msg):
return '{} - {}'.format(self, msg)
def _set_target(self, target):
self.state_target = target
for credential_state in CredentialState.objects.filter(
target__parent=self,
):
credential_state.set_target(target)
LOGGER.debug(self.msg('Target changed to '+target))
self.save()
def __str__(self):
return 'VO-Dep: ({}:{})#{}'.format(
self.vo,
......@@ -256,13 +263,21 @@ class ServiceDeployment(Deployment):
on_delete=models.CASCADE,
)
@property
def broker_exchange(self):
return 'services'
@property
def routing_key(self):
return self.service.name
def create_state_item(self):
LOGGER.debug('create_state_item: creating DeploymentState for service %s at site %s', self.service, self.service.site)
DeploymentState.get_state_item(
parent=self,
user=self.user,
site=self.service.site,
service=self.service,
self,
self.user,
self.service.site,
self.service,
)
@classmethod
......@@ -272,7 +287,7 @@ class ServiceDeployment(Deployment):
user=user,
service=service,
)
deployment.create_state_items()
deployment.create_state_item()
return deployment
......@@ -285,37 +300,12 @@ class ServiceDeployment(Deployment):
deployment.save()
deployment.create_state_item()
LOGGER.debug(deployment.msg('created'))
LOGGER.debug(deployment.msg('Created'))
return deployment
def service_added(self, service):
LOGGER.debug(self.msg('Adding service {}'.format(service)))
item = DeploymentState.get_state_item(
parent=self,
site=service.site,
service=service,
)
if self.state_target == 'deployed':
item.user_deploy()
def service_removed(self, service):
LOGGER.debug(self.msg('Removing service {}'.format(service)))
LOGGER.debug('TODO implement service removal')
def msg(self, msg):
return '{} - {}'.format(self, msg)
def _set_target(self, target):
self.state_target = target
for credential_state in CredentialState.objects.filter(
target__parent=self,
):
credential_state.set_target(target)
LOGGER.debug(self.msg('Target changed to '+target))
self.save()
def __str__(self):
return 'Service-Dep: ({}:{})#{}'.format(
self.service,
......@@ -405,15 +395,8 @@ class DeploymentState(models.Model):
def user_credentials(self):
return self.user.credentials
@property
def vo(self):
if self.parent is not None:
return self.parent.vo
else:
raise self.parentless
@classmethod
def get_state_item(cls, parent=None, user=None, site=None, service=None):
def get_state_item(cls, parent, user, site, service):
try:
item = cls.objects.get(
parent=parent,
......@@ -432,7 +415,7 @@ class DeploymentState(models.Model):
)
item.save()
LOGGER.debug('get_state_item: created %s', item)
LOGGER.debug(item.msg('Created'))
return item
# starts tracking this the credential for this item
......
......@@ -2,15 +2,12 @@
from rest_framework import serializers
from rest_polymorphic.serializers import PolymorphicSerializer
from feudal.backend.auth.v1.models.serializers.vo import VOSerializer
from feudal.backend.auth.v1.models.serializers import VOSerializer
from ...models import Site, Service
from ..users import User, SSHPublicKey
from ..deployments import CredentialState, DeploymentState, Deployment, VODeployment, ServiceDeployment
# export
from .clients import RabbitMQInstanceSerializer
class SSHPublicKeySerializer(serializers.ModelSerializer):
class Meta:
......@@ -31,23 +28,6 @@ class SSHPublicKeyRefSerializer(serializers.ModelSerializer):
]
class CredentialSerializer(serializers.ModelSerializer):
class Meta:
model = SSHPublicKey
fields = [
'id',
'name',
'value',
]
CREDENTIAL_SERIALIZER = serializers.DictField(
child=serializers.ListField(
child=CredentialSerializer()
)
)
class CredentialStateSerializer(serializers.ModelSerializer):
credential = SSHPublicKeyRefSerializer()
......@@ -61,7 +41,6 @@ class CredentialStateSerializer(serializers.ModelSerializer):
]
class SiteSerializer(serializers.ModelSerializer):
class Meta:
model = Site
......@@ -88,7 +67,6 @@ class DeploymentStateSerializer(serializers.ModelSerializer):
site = SiteSerializer()
questionnaire = serializers.JSONField()
credentials = serializers.JSONField()
vo = VOSerializer()
credential_states = CredentialStateSerializer(many=True)
class Meta:
......@@ -100,7 +78,6 @@ class DeploymentStateSerializer(serializers.ModelSerializer):
'questionnaire',
'credentials',
'service',
'vo',
'message',
'credential_states',
'is_credential_pending',
......@@ -109,16 +86,13 @@ class DeploymentStateSerializer(serializers.ModelSerializer):
DEPLOYMENT_FIELDS = (
'id',
'state_target',
'id',
'state_items',
'credentials',
)
class AbstractDeploymentSerializer(serializers.ModelSerializer):
credentials = CredentialSerializer
state_items = DeploymentStateSerializer(many=True)
class Meta:
......@@ -127,6 +101,10 @@ class AbstractDeploymentSerializer(serializers.ModelSerializer):
class VODeploymentSerializer(serializers.ModelSerializer):
state_items = DeploymentStateSerializer(many=True)
vo = VOSerializer()
services = ServiceSerializer(many=True)
class Meta:
model = VODeployment
fields = DEPLOYMENT_FIELDS + (
......@@ -136,7 +114,8 @@ class VODeploymentSerializer(serializers.ModelSerializer):
class ServiceDeploymentSerializer(serializers.ModelSerializer):
state_items = DeploymentStateSerializer(many=True)
service = ServiceSerializer()
class Meta:
model = ServiceDeployment
fields = DEPLOYMENT_FIELDS + (
......@@ -160,16 +139,15 @@ class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = [
'profile_name',
'vos',
'id',
'profile_name',
'ssh_keys',
'userinfo',
'vos',
]
class UserStateSerializer(serializers.ModelSerializer):
vos = VOSerializer(many=True)
ssh_keys = SSHPublicKeySerializer(many=True)
deployments = DeploymentSerializer(many=True)
......@@ -179,10 +157,15 @@ class UserStateSerializer(serializers.ModelSerializer):
model = User
fields = [
'deployments',
'profile_name',
'vos',
'id',
'profile_name',
'services',
'ssh_keys',
'userinfo',
'services',
'vos',
]
class StateSerializer(serializers.Serializer):
error = serializers.CharField(allow_blank=True, required=False)
user = UserStateSerializer()
......@@ -3,36 +3,100 @@
from django_mysql.models import JSONField
from rest_framework import serializers
from rest_polymorphic.serializers import PolymorphicSerializer
from feudal.backend.auth.v1.models.serializers.vo import VOSerializer
from feudal.backend.auth.v1.models.serializers.clients import VOSerializer
from ... import models
from .. import Service, SSHPublicKey, User, RabbitMQInstance, deployments
class ServiceSerializer(serializers.ModelSerializer):
class Meta:
model = models.Service
model = Service
fields = [
'name',
]
class CredentialSerializer(serializers.ModelSerializer):
class Meta:
model = SSHPublicKey
fields = [
'id',
'name',
'value',
]
class UserSerializer(serializers.ModelSerializer):
vos = VOSerializer(many=True)
userinfo = JSONField()
credentials = serializers.DictField(
child=serializers.ListField(
child=CredentialSerializer()
)
)
class Meta:
model = models.User
model = User
fields = [
'credentials',
'email',
'vos',
'userinfo',
'vos',
]
class RabbitMQInstanceSerializer(serializers.ModelSerializer):
class Meta:
model = models.RabbitMQInstance
model = RabbitMQInstance
fields = [
'vhost',
]
DEPLOYMENT_FIELDS = (
'id',
'state_target',
'user',
)
class AbstractDeploymentSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = deployments.Deployment
fields = DEPLOYMENT_FIELDS
class VODeploymentSerializer(serializers.ModelSerializer):
user = UserSerializer()
vo = VOSerializer()
services = ServiceSerializer(many=True)
class Meta:
model = deployments.VODeployment
fields = DEPLOYMENT_FIELDS + (
'vo',
'services',
)
class ServiceDeploymentSerializer(serializers.ModelSerializer):
user = UserSerializer()
service = ServiceSerializer()
class Meta:
model = deployments.ServiceDeployment
fields = DEPLOYMENT_FIELDS + (
'service',
)
class DeploymentSerializer(PolymorphicSerializer):
model_serializer_mapping = {
deployments.Deployment: AbstractDeploymentSerializer,
deployments.VODeployment: VODeploymentSerializer,
deployments.ServiceDeployment: ServiceDeploymentSerializer,
}
......@@ -11,8 +11,7 @@ from feudal.backend.auth.v1.models.vo import VO, Group, Entitlement
from ..models import Site, Service
from ..models.brokers import RabbitMQInstance
from ..models.deployments import DeploymentState
from ..models.serializers import RabbitMQInstanceSerializer, DeploymentSerializer
from ..models.serializers import clients
LOGGER = logging.getLogger(__name__)
......@@ -24,10 +23,10 @@ AUTHENTICATION_CLASSES = (BasicAuthentication, )
# The client fetches pending tasks
class DeploymentsView(generics.ListAPIView):
authentication_classes = AUTHENTICATION_CLASSES
serializer_class = DeploymentSerializer
serializer_class = clients.DeploymentSerializer
def get_queryset(self):
return self.request.user.site.pending_tasks
return self.request.user.site.pending_deployments
class ResponseView(views.APIView):
......@@ -159,7 +158,7 @@ class ConfigurationView(views.APIView):
broker.initialize()
response = {
'rabbitmq_config': RabbitMQInstanceSerializer(
'rabbitmq_config': clients.RabbitMQInstanceSerializer(
broker,
).data,
'site': request.user.site.name,
......
......@@ -3,8 +3,7 @@ import logging
from django.contrib.auth import logout
from django.shortcuts import get_object_or_404
from rest_framework import status
from rest_framework import views
from rest_framework import status, views, generics
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
......@@ -12,6 +11,7 @@ from feudal.backend.auth.v1.models.vo import VO
from .. import models
from ..models import serializers
from ..models import deployments
LOGGER = logging.getLogger(__name__)
......@@ -21,13 +21,11 @@ def _api_error_response(error):
def state_view_data(request):
data = {}
data = {
'user': None,
}
if request.user.is_authenticated:
data['user'] = serializers.UserStateSerializer(
request.user,
).data
else:
data['user'] = None
data['user'] = request.user
if 'error' in request.session:
data['error'] = request.session['error']
......@@ -37,11 +35,12 @@ def state_view_data(request):
return data
class StateView(views.APIView):
class StateView(generics.RetrieveAPIView):
permission_classes = (AllowAny,)
serializer_class = serializers.StateSerializer
def get(self, request):
return Response(state_view_data(request))
def get_object(self):
return state_view_data(self.request)
class SSHPublicKeyView(views.APIView):
......@@ -107,7 +106,7 @@ class DeploymentView(views.APIView):
def post(self, request):
if (
'type' not in request.data or
'vo' not in request.data
('vo' not in request.data and 'service' not in request.data)
):
LOGGER.error("VODeployment api got malformed request %s: request misses fields (should have: 'type', and 'vo')", request.data)
return _api_error_response('malformed request')
......@@ -117,12 +116,20 @@ class DeploymentView(views.APIView):
deployment = None
if 'vo' in request.data:
try:
deployment = VODeployment.get_deployment(
deployment = deployments.get_deployment(
request.user,
VO.objects.get(id=request.data['vo']),
vo=VO.objects.get(id=request.data['vo']),
)
except VO.DoesNotExist:
return _api_error_response("invalid value of field 'vo': does not exist")
if 'service' in request.data:
try:
deployment = deployments.get_deployment(
request.user,
service=models.Service.objects.get(id=request.data['service']),
)
except models.Service.DoesNotExist:
return _api_error_response("invalid value of field 'service': does not exist")
if request_type == 'add':
deployment.user_deploy()
......
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 to comment