Commit 56172289 authored by Lukas Burgey's avatar Lukas Burgey
Browse files

Refactor Deployment/Task/Item logic

parent 762f7dd8
...@@ -42,7 +42,7 @@ class DeploymentsSerializer(serializers.Serializer): ...@@ -42,7 +42,7 @@ class DeploymentsSerializer(serializers.Serializer):
class DeploymentStateSerializer(serializers.Serializer): class DeploymentStateSerializer(serializers.Serializer):
id = serializers.IntegerField() id = serializers.IntegerField()
action = serializers.CharField() state_target = serializers.CharField()
user = UserSerializer() user = UserSerializer()
service = ServiceSerializer() service = ServiceSerializer()
key = backend_serializers.SSHPublicKeySerializer() key = backend_serializers.SSHPublicKeySerializer()
......
...@@ -13,12 +13,18 @@ LOGGER = logging.getLogger(__name__) ...@@ -13,12 +13,18 @@ LOGGER = logging.getLogger(__name__)
AUTHENTICATION_CLASSES = (BasicAuthentication, ) AUTHENTICATION_CLASSES = (BasicAuthentication, )
# The client fetches pending tasks
class DeploymentsView(generics.ListAPIView): class DeploymentsView(generics.ListAPIView):
authentication_classes = AUTHENTICATION_CLASSES authentication_classes = AUTHENTICATION_CLASSES
serializer_class = DeploymentStateSerializer serializer_class = DeploymentStateSerializer
def get_queryset(self): def get_queryset(self):
return self.request.user.site.states items = self.request.user.site.state_items.filter(
state='deployment_pending',
) | self.request.user.site.state_items.filter(
state='removal_pending',
)
return [item.tasks for item in items]
# the client has to fetch the configuration (like services etc.) here # the client has to fetch the configuration (like services etc.) here
...@@ -45,8 +51,11 @@ class AckView(views.APIView): ...@@ -45,8 +51,11 @@ class AckView(views.APIView):
def delete(self, request, state_id=None): def delete(self, request, state_id=None):
# find the corresponding state for this item # find the corresponding state for this item
for item in request.user.site.state_items.all(): for item in request.user.site.state_items.all():
if item.state.id == int(state_id): if item.parent.id == int(state_id):
item.success() if item.parent.state_target == 'deployed':
item.client_deployed()
else:
item.client_removed()
return Response({'ok': True}) return Response({'ok': True})
# this is no critical # this is no critical
...@@ -62,29 +71,37 @@ class ResponseView(views.APIView): ...@@ -62,29 +71,37 @@ class ResponseView(views.APIView):
status = output['status'] status = output['status']
state_id = request.data['id'] state_id = request.data['id']
LOGGER.debug('%s responded to state %s:\n%s', request.user, state_id, request.data) # LOGGER.debug('%s responded to state %s:\n%s', request.user, state_id, request.data)
# find the corresponding state for this item # find the corresponding state for this item
state_item = None state_item = None
for item in request.user.site.state_items.all(): for item in request.user.site.state_items.all():
if item.state.id == int(state_id): if item.parent.id == int(state_id):
state_item = item state_item = item
if state_item is not None: if state_item is not None:
if status == 'success': if status == 'deployed':
state_item.success( state_item.client_deployed(
credentials=request.data.output.get('credentials', None), credentials=output.get('credentials', None),
) )
return Response({}) return Response({})
elif status == 'fail': elif status == 'removed':
state_item.failed() state_item.client_removed()
return Response({}) return Response({})
elif status == 'reject': elif status == 'questionnaire':
state_item.rejected(output['questionnaire']) state_item.client_questionnaire(
output['questionnaire'],
)
return Response({}) return Response({})
LOGGER.error("Unrecognized response status from client: %s", status)
return Response(
data={'error': 'unknown status'},
status=500,
)
LOGGER.info('%s executed the obsolete state#%s', request.user, state_id) LOGGER.info('%s executed the obsolete state#%s', request.user, state_id)
return Response( return Response(
data={'error': 'obsolete_state'}, data={'error': 'obsolete_state'},
......
...@@ -29,7 +29,7 @@ class DeploymentStateItemSerializer(serializers.ModelSerializer): ...@@ -29,7 +29,7 @@ class DeploymentStateItemSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.DeploymentStateItem model = models.DeploymentStateItem
fields = [ fields = [
'action', 'state_target',
'key', 'key',
'service', 'service',
'site', 'site',
...@@ -45,7 +45,7 @@ class DeploymentStateSerializer(serializers.ModelSerializer): ...@@ -45,7 +45,7 @@ class DeploymentStateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.DeploymentState model = models.DeploymentState
fields = [ fields = [
'action', 'state_target',
'key', 'key',
'service', 'service',
'id', 'id',
...@@ -56,8 +56,8 @@ class DeploymentSerializer(serializers.Serializer): ...@@ -56,8 +56,8 @@ class DeploymentSerializer(serializers.Serializer):
service = ServiceSerializer() service = ServiceSerializer()
ssh_keys = backend_serializers.SSHPublicKeySerializer(many=True) ssh_keys = backend_serializers.SSHPublicKeySerializer(many=True)
ssh_keys_to_withdraw = backend_serializers.SSHPublicKeySerializer(many=True) ssh_keys_to_withdraw = backend_serializers.SSHPublicKeySerializer(many=True)
deploys = DeploymentStateSerializer(many=True) # deploys = DeploymentStateSerializer(many=True)
withdrawals = DeploymentStateSerializer(many=True) # removals = DeploymentStateSerializer(many=True)
class Meta: class Meta:
model = models.Deployment model = models.Deployment
......
...@@ -121,7 +121,7 @@ class DeploymentView(views.APIView): ...@@ -121,7 +121,7 @@ class DeploymentView(views.APIView):
if request_type == 'add': if request_type == 'add':
deployment.deploy_key(request_key) deployment.deploy_key(request_key)
elif request_type == 'remove': elif request_type == 'remove':
deployment.withdraw_key(request_key) deployment.remove_key(request_key)
else: else:
return _api_error_response() return _api_error_response()
......
This diff is collapsed.
...@@ -111,34 +111,35 @@ class DeploymentTest(TestCase): ...@@ -111,34 +111,35 @@ class DeploymentTest(TestCase):
key = models.SSHPublicKey.objects.get(name=TEST_NAME) key = models.SSHPublicKey.objects.get(name=TEST_NAME)
service = models.Service.objects.get(name=TEST_SERVICE) service = models.Service.objects.get(name=TEST_SERVICE)
deployment = models.Deployment.get_deployment(user, service) deployment = models.Deployment.get_deployment(
user,
service,
)
self.assertIsNotNone(deployment) self.assertIsNotNone(deployment)
# no states exist yet state = models.DeploymentState.get_state(
self.assertFalse(deployment.deploys.exists())
self.assertFalse(deployment.withdrawals.exists())
models.DeploymentState.construct_deployment_state(
deployment=deployment, deployment=deployment,
key=key, key=key,
) )
self.assertIsNotNone(state)
# one deploy should exist deployment.deploy_key(key)
self.assertTrue(deployment.deploys.exists())
self.assertFalse(deployment.withdrawals.exists())
models.DeploymentState.construct_withdrawal_state( self.assertFalse(state.target_reached)
deployment=deployment,
key=key, # execute deployment
) for item in state.state_items.all():
# one withdraw should exist item.client_deployed()
self.assertFalse(deployment.deploys.exists())
self.assertTrue(deployment.withdrawals.exists()) self.assertTrue(state.target_reached)
# start removal
state.remove()
self.assertFalse(state.target_reached)
# "execute" the withdrawals # execute removals
for state in deployment.withdrawals.all(): for item in state.state_items.all():
for item in state.state_items.all(): item.client_removed()
item.success()
self.assertFalse(deployment.deploys.exists()) self.assertTrue(state.target_reached)
self.assertFalse(deployment.withdrawals.exists())
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