Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
feudal
feudalBackend
Commits
8aa8b7e6
Commit
8aa8b7e6
authored
Jun 21, 2018
by
Lukas Burgey
Browse files
Fix deletion of ssh keys
parent
7fd2ac35
Changes
5
Hide whitespace changes
Inline
Side-by-side
django_backend/backend/admin.py
View file @
8aa8b7e6
...
...
@@ -21,8 +21,14 @@ class TypeFilter(admin.SimpleListFilter):
class
ClientAdmin
(
UserAdmin
):
list_filter
=
(
TypeFilter
,)
admin
.
site
.
register
(
OIDCConfig
)
admin
.
site
.
register
(
models
.
RabbitMQInstance
)
admin
.
site
.
register
(
models
.
User
,
ClientAdmin
)
admin
.
site
.
register
(
models
.
Site
)
admin
.
site
.
register
(
models
.
Service
)
admin
.
site
.
register
(
models
.
RabbitMQInstance
)
admin
.
site
.
register
(
OIDCConfig
)
admin
.
site
.
register
(
models
.
SSHPublicKey
)
admin
.
site
.
register
(
models
.
Deployment
)
admin
.
site
.
register
(
models
.
DeploymentState
)
admin
.
site
.
register
(
models
.
DeploymentStateItem
)
django_backend/backend/clientapi/views.py
View file @
8aa8b7e6
...
...
@@ -48,7 +48,7 @@ class AckView(views.APIView):
for
item
in
request
.
user
.
site
.
state_items
.
all
():
if
item
.
parent
.
id
==
int
(
state_id
):
if
item
.
parent
.
state_target
==
'deployed'
:
item
.
client_deployed
()
item
.
client_deployed
(
{}
)
else
:
item
.
client_removed
()
return
Response
({})
...
...
@@ -79,7 +79,7 @@ class ResponseView(views.APIView):
if
state_item
is
not
None
:
if
status
==
'deployed'
:
state_item
.
client_deployed
(
credentials
=
output
.
get
(
'credentials'
,
None
),
credentials
=
output
.
get
(
'credentials'
,
{}
),
)
return
Response
({})
...
...
django_backend/backend/frontend/views.py
View file @
8aa8b7e6
...
...
@@ -7,7 +7,7 @@ from rest_framework.permissions import AllowAny
from
rest_framework.response
import
Response
from
rest_framework
import
status
from
.
import
serializers
from
..
import
models
from
..
import
models
,
serializers
as
model_serializers
LOGGER
=
logging
.
getLogger
(
__name__
)
...
...
@@ -88,7 +88,9 @@ class SSHPublicKeyView(views.APIView):
# we do not delete ssh keys directly, as we need to keep track
# of them until all clients have also deleted them
key
.
delete_key
()
return
_api_state_response
(
request
)
return
Response
({
'deleted'
:
True
,
})
elif
request
.
data
[
'type'
]
==
'add'
:
if
'key'
in
request
.
data
:
key
=
models
.
SSHPublicKey
(
...
...
@@ -97,7 +99,11 @@ class SSHPublicKeyView(views.APIView):
key
=
request
.
data
[
'key'
][
'key'
],
)
key
.
save
()
return
_api_state_response
(
request
)
return
Response
(
model_serializers
.
SSHPublicKeySerializer
(
key
,
).
data
)
LOGGER
.
error
(
'SSHPublicKeyView: malformed request %s'
,
request
)
return
_api_error_response
(
"malformed request"
)
...
...
django_backend/backend/models.py
View file @
8aa8b7e6
...
...
@@ -256,6 +256,23 @@ class User(AbstractUser):
editable
=
False
,
)
@
property
def
deployment_states
(
self
):
states
=
[]
for
deployment
in
self
.
deployments
.
all
():
for
state
in
deployment
.
states
.
all
():
states
.
append
(
state
)
return
states
@
property
def
deployment_state_items
(
self
):
items
=
[]
for
state
in
self
.
deployment_states
:
for
item
in
state
.
state_items
.
all
():
items
.
append
(
item
)
return
items
# returns the user as identified by userinfo and idp
# if the user does not exists
@
classmethod
...
...
@@ -476,17 +493,20 @@ class SSHPublicKey(models.Model):
editable
=
False
,
)
def
states
(
self
):
states
=
[]
@
property
def
deployed_anywhere
(
self
):
for
state
in
self
.
states
.
all
():
states
.
append
(
state
.
states
)
for
item
in
state
.
state_items
.
all
():
if
item
.
state
==
'deployed'
or
item
.
state
==
'removal_pending'
:
return
True
return
False
# does not directly delete the key if the key is deployed or withdrawn
# somewhere
# the receiver 'delete_withdrawn_ssh_key' does the actual deletion
def
delete_key
(
self
):
# if this key is not deployed anywhere we delete it now
if
analyze_states
(
self
.
states
.
all
())
==
'not_deployed'
:
if
not
self
.
deployed_anywhere
:
LOGGER
.
info
(
self
.
msg
(
'Direct deletion of key'
))
self
.
delete
()
return
...
...
@@ -501,10 +521,19 @@ class SSHPublicKey(models.Model):
# when a key is withdrawn by a client we try to finally delete it
def
try_final_deletion
(
self
):
if
(
self
.
deleted
and
not
self
.
states
.
exists
()):
LOGGER
.
info
(
self
.
msg
(
'All clients have withdrawn this key. Final deletion'
))
self
.
delete
()
return
if
self
.
deleted
:
if
not
self
.
deployed_anywhere
:
LOGGER
.
info
(
self
.
msg
(
'All clients have withdrawn this key. Final deletion'
))
self
.
_final_deletion
()
def
_final_deletion
(
self
):
_self
=
self
for
state
in
self
.
states
.
all
():
#for item in state.state_items.all():
# item.delete()
state
.
delete
()
_self
.
delete
()
def
__str__
(
self
):
if
self
.
deleted
:
...
...
@@ -526,7 +555,8 @@ class Deployment(models.Model):
user
=
models
.
ForeignKey
(
User
,
related_name
=
'deployments'
,
on_delete
=
models
.
CASCADE
,
on_delete
=
models
.
SET_NULL
,
null
=
True
,
)
service
=
models
.
ForeignKey
(
Service
,
...
...
@@ -572,7 +602,6 @@ class Deployment(models.Model):
LOGGER
.
error
(
self
.
msg
(
'already active'
))
return
LOGGER
.
debug
(
self
.
msg
(
str
(
self
.
ssh_keys
.
all
())))
for
key
in
self
.
ssh_keys
.
all
():
self
.
_deploy_key
(
key
)
...
...
@@ -661,15 +690,7 @@ class DeploymentState(models.Model):
related_name
=
'states'
,
on_delete
=
models
.
CASCADE
,
)
# TODO is this relation needed?
# State does relate to Deployment which relates to User
user
=
models
.
ForeignKey
(
User
,
related_name
=
'deployment_states'
,
# TODO deleting the user leaves us without references about its deployments
# we _HAVE_ to remove all deployments prior to deleting site user
on_delete
=
models
.
CASCADE
,
)
# which state do we currently want to reach?
state_target
=
models
.
CharField
(
max_length
=
50
,
...
...
@@ -677,6 +698,10 @@ class DeploymentState(models.Model):
default
=
'deployed'
,
)
@
property
def
user
(
self
):
return
self
.
deployment
.
user
@
property
def
states
(
self
):
return
[
item
.
state
for
item
in
self
.
state_items
.
all
()]
...
...
@@ -708,7 +733,6 @@ class DeploymentState(models.Model):
# create new state if not
state
=
cls
(
deployment
=
deployment
,
user
=
deployment
.
user
,
key
=
key
,
)
state
.
save
()
...
...
@@ -718,7 +742,6 @@ class DeploymentState(models.Model):
for
site
in
deployment
.
service
.
site
.
all
():
deploy
=
DeploymentStateItem
(
parent
=
state
,
user
=
deployment
.
user
,
site
=
site
,
)
deploy
.
save
()
...
...
@@ -786,15 +809,6 @@ class DeploymentStateItem(models.Model):
site
=
models
.
ForeignKey
(
Site
,
related_name
=
'state_items'
,
# TODO deleting the site leaves us without references about its deployments
# we _HAVE_ to remove all deployments prior to deleting a site
on_delete
=
models
.
CASCADE
,
)
user
=
models
.
ForeignKey
(
User
,
related_name
=
'deployment_state_items'
,
# TODO deleting the user leaves us without references about its deployments
# we _HAVE_ to remove all deployments prior to deleting site user
on_delete
=
models
.
CASCADE
,
)
state
=
models
.
CharField
(
...
...
@@ -806,17 +820,17 @@ class DeploymentStateItem(models.Model):
# questions for the user (needed for deployment
questionnaire
=
JSONField
(
default
=
questionnaire_default
,
null
=
True
,
blank
=
True
,
)
# credentials for the service
# only valid when state == deployed
credentials
=
JSONField
(
default
=
credential_default
,
null
=
True
,
blank
=
True
,
)
@
property
def
user
(
self
):
return
self
.
parent
.
user
@
property
def
service
(
self
):
return
self
.
parent
.
service
...
...
@@ -865,8 +879,15 @@ class DeploymentStateItem(models.Model):
# client: removed
def
client_removed
(
self
):
# TODO check if all values are reset correctly
self
.
credentials
=
credential_default
()
self
.
questionnaire
=
questionnaire_default
()
self
.
_set_state
(
'not_deployed'
)
# this removal maybe was the last of out ssh key
self
.
key
.
try_final_deletion
()
# client: questionnaire
def
client_questionnaire
(
self
,
questionnaire
=
None
):
self
.
questionnaire
=
questionnaire
...
...
django_backend/backend/serializers.py
View file @
8aa8b7e6
...
...
@@ -9,22 +9,35 @@ from .models import SSHPublicKey, AuthGroup
class
GroupSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Group
fields
=
[
'id'
,
'name'
]
fields
=
[
'id'
,
'name'
,
]
class
AuthGroupSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
AuthGroup
fields
=
[
'id'
,
'name'
]
fields
=
[
'id'
,
'name'
,
]
class
SSHPublicKeySerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
SSHPublicKey
fields
=
[
'id'
,
'name'
,
'key'
]
fields
=
[
'id'
,
'name'
,
'key'
,
]
class
SSHPublicKeyRefSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
SSHPublicKey
fields
=
[
'id'
,
'name'
]
fields
=
[
'id'
,
'name'
,
]
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment