clients.py 5.6 KB
Newer Older
1

2
import logging
3
from django.contrib.auth.models import Group
4
from rest_framework import generics, views
5
from rest_framework.authentication import BasicAuthentication
6
from rest_framework.response import Response
Lukas Burgey's avatar
Lukas Burgey committed
7
8
9
10
11


from ..models.brokers import RabbitMQInstance
from ..models.serializers.webpage import DeploymentStateSerializer
from ..models.serializers.clients import RabbitMQInstanceSerializer
12
from .. import models
13

14
15
16
LOGGER = logging.getLogger(__name__)


17
# authentication class for the client api
18
AUTHENTICATION_CLASSES = (BasicAuthentication, )
19

20

21
# The client fetches pending tasks
22
class DeploymentsView(generics.ListAPIView):
Lukas Burgey's avatar
Lukas Burgey committed
23
    authentication_classes = AUTHENTICATION_CLASSES
Lukas Burgey's avatar
Lukas Burgey committed
24
    serializer_class = DeploymentStateSerializer
25

26
    def get_queryset(self):
Lukas Burgey's avatar
Lukas Burgey committed
27
        return self.request.user.site.pending_tasks
28
29


30
# the client has to fetch the configuration (like services etc.) here
31
class ConfigurationView(views.APIView):
Lukas Burgey's avatar
Lukas Burgey committed
32
    authentication_classes = AUTHENTICATION_CLASSES
33

34
    def put(self, request):
Lukas Burgey's avatar
Lukas Burgey committed
35
        #services = request.data.get('services', None)
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
        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

89
90
91
92
        response = {
            'rabbitmq_config': RabbitMQInstanceSerializer(
                RabbitMQInstance.load(),
            ).data,
Lukas Burgey's avatar
Lukas Burgey committed
93
            'site': request.user.site.name,
94
95
        }
        return Response(response)
96
97


98
99
100
101
102
103
104
def response_view_error(err):
    return Response(
        data={'error': err},
        status=500,
    )


105
106
107
108
class ResponseView(views.APIView):
    authentication_classes = AUTHENTICATION_CLASSES

    def post(self, request):
109
        client_site = request.user.site
110
111
        output = request.data.get('output', {})
        state_id = request.data.get('id', None)
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
        _service = request.data.get('service', {})

        service = None
        service_query = client_site.services.filter(
            name=_service['name'],
        )
        #LOGGER.debug("[ResponseView]services: %s %s", service_query, len(service_query))
        if service_query.exists() and len(service_query) == 1:
            service = service_query.first()
        else:
            LOGGER.error(
                '[ResponseView] Unknown service %s from %s',
                _service['name'],
                request.user,
            )
            return response_view_error('unable to determine service')
128

129
130
131
        if state_id is None:
            err = 'no state id'
            LOGGER.error('Error parsing response from %s: %s', request.user, err)
132
            return response_view_error(err)
133

134
        # find the corresponding DeploymentStateItem for this response
Lukas Burgey's avatar
Lukas Burgey committed
135
        state_item = None
136
137
138
139
140
141
142
143
144
145
146
147
148
149
        query = client_site.state_items.filter(
            parent__id=int(state_id),
            site=client_site,
            service=service,
        )
        if query.exists():
            if len(query) == 1:
                state_item = query.first()
            else:
                LOGGER.error('[ResponseView] ambiguous DStateItem')
                return response_view_error('ambiguous DeploymentStateItem')
        else:
            LOGGER.error('[ResponseView] No matching DStateItem')
            return response_view_error('no matching DeploymentStateItem')
150

Lukas Burgey's avatar
Lukas Burgey committed
151
        if state_item is not None:
152
153
            err = state_item.client_response(output)
            if err is not None:
154
155
                LOGGER.error('[ResponseView] Error parsing response from %s: %s', request.user, err)
                return response_view_error(err)
156
            return Response({})
157

158
159
        LOGGER.info('[ResponseView] %s executed the obsolete state#%s', request.user, state_id)
        return response_view_error('obsolete state')