Commit 7d080bdc authored by Lukas Burgey's avatar Lukas Burgey

Implement the config sync with the client

parent 221a1896
import json
import logging
from django.contrib.auth.models import Group
from rest_framework import generics, views
from rest_framework.authentication import BasicAuthentication
from rest_framework.response import Response
from .serializers import DeploymentStateSerializer, ServiceSerializer, RabbitMQInstanceSerializer
from ..models import RabbitMQInstance
from .. import models
LOGGER = logging.getLogger(__name__)
......@@ -26,12 +29,62 @@ class DeploymentsView(generics.ListAPIView):
class ConfigurationView(views.APIView):
authentication_classes = AUTHENTICATION_CLASSES
def get(self, request):
def put(self, request):
services = request.data.get('services', None)
group_to_services = request.data.get('group_to_services', None)
# TODO check if client has new services
#if services is not None:
# for service in services:
# pass
if group_to_services is not None:
for group_name, group_service_list in group_to_services.items():
group = None
try:
group = Group.objects.get(name=group_name)
except Group.DoesNotExist:
LOGGER.info("Group %s does not exist. Creating it", group_name)
group = Group(
name=group_name,
)
group.save()
for group_service in group_service_list:
name = group_service.get('name', None)
description = group_service.get('description', None)
service = None
try:
service = models.Service.objects.get(name=name)
# update description if needed
if service.description != description:
LOGGER.info("Updating service description")
service.description = description
service.save()
# test if service has the group
try:
service.groups.get(name=group_name)
except Group.DoesNotExist:
service.groups.add(group)
except models.Service.DoesNotExist:
LOGGER.info("Site %s pushed new service %s", request.user.site, name)
service = models.Service(
name=name,
description=description,
)
service.save()
service.groups.add(group)
service.site.add(request.user.site)
service.handle_group_deployments()
# TODO deactivate vanished services
response = {
'services': ServiceSerializer(
request.user.site.services.all(),
many=True,
).data,
'rabbitmq_config': RabbitMQInstanceSerializer(
RabbitMQInstance.load(),
).data,
......
......@@ -429,7 +429,6 @@ class User(AbstractUser):
if 'sub' not in userinfo:
raise Exception('Missing attribute in userinfo: sub')
sub = userinfo['sub']
groups = userinfo.get('groups', [])
# FIXME probably inefficient
......@@ -528,6 +527,24 @@ class Service(models.Model):
return self.name
def handle_group_deployments(self):
for group in self.groups.all():
# users that have group deployments for this group
for user in User.objects.filter(
deployments__group=group,
).distinct():
LOGGER.debug(user.msg("New service for group. Adding to deployment"))
# all group deployments have the same keys
# TODO check that assumption
deployment = user.deployments.filter(group=group)
if deployment.exists():
deployment.first().service_added(self)
class SSHPublicKey(models.Model):
name = models.CharField(
max_length=150,
......@@ -734,6 +751,15 @@ class Deployment(models.Model):
self._deploy_key(key)
def service_added(self, service):
# a new service for this group was added and we may have to deploy some keys
LOGGER.debug(self.msg("Adding service {}".format(service)))
for state in self.states.all():
state.service_added(service)
# remove key and track changes in the key lists
def remove_key(self, key):
if not self.is_active:
......@@ -869,6 +895,19 @@ class DeploymentState(models.Model):
return state
def service_added(self, service):
LOGGER.debug(self.msg("Adding service {}".format(service)))
for site in service.site.all():
# create new DeploymentStateItems
item = DeploymentStateItem.get_state_item(
parent=self,
site=site,
service=service,
)
item.save()
if self.state_target == 'deployed':
item.user_deploy()
def deploy(self):
self._set_target('deployed')
for item in self.state_items.all():
......@@ -923,12 +962,14 @@ class DeploymentState(models.Model):
def __str__(self):
if self.service is not None:
return "{}#{}".format(
return "{}:{}#{}".format(
self.service,
self.key.name,
self.id,
)
return "{}#{}".format(
return "{}:{}#{}".format(
self.group,
self.key.name,
self.id,
)
......@@ -957,6 +998,12 @@ class DeploymentStateItem(models.Model):
default='deployment_pending',
)
# message for the user
message = models.TextField(
max_length=300,
blank=True,
)
# questions for the user (needed for deployment
questionnaire = JSONField(
default=questionnaire_default,
......@@ -1001,6 +1048,8 @@ class DeploymentStateItem(models.Model):
site=site,
service=service,
)
item.save()
LOGGER.debug(item.msg('created'))
return item
......@@ -1049,7 +1098,11 @@ class DeploymentStateItem(models.Model):
# returns None on success, or a string describing an error
def client_response(self, output):
status = output.get('status', 'undefined')
status = output.get('state', 'undefined')
self.message = output.get('message', '')
self.save()
if status != 'undefined':
# update values
if status == 'deployed':
......@@ -1091,15 +1144,17 @@ class DeploymentStateItem(models.Model):
def __str__(self):
if self.group is not None:
return "{}:{}@{}#{}".format(
return "{}:{}@{}:{}#{}".format(
self.group,
self.service,
self.site,
self.key.name,
self.id,
)
return "{}:@{}#{}".format(
return "{}:@{}:{}#{}".format(
self.service,
self.site,
self.key.name,
self.id,
)
......
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