Skip to content
GitLab
Menu
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
Show whitespace changes
Inline
Side-by-side
django_backend/backend/admin.py
View file @
8aa8b7e6
...
@@ -21,8 +21,14 @@ class TypeFilter(admin.SimpleListFilter):
...
@@ -21,8 +21,14 @@ class TypeFilter(admin.SimpleListFilter):
class
ClientAdmin
(
UserAdmin
):
class
ClientAdmin
(
UserAdmin
):
list_filter
=
(
TypeFilter
,)
list_filter
=
(
TypeFilter
,)
admin
.
site
.
register
(
OIDCConfig
)
admin
.
site
.
register
(
models
.
RabbitMQInstance
)
admin
.
site
.
register
(
models
.
User
,
ClientAdmin
)
admin
.
site
.
register
(
models
.
User
,
ClientAdmin
)
admin
.
site
.
register
(
models
.
Site
)
admin
.
site
.
register
(
models
.
Site
)
admin
.
site
.
register
(
models
.
Service
)
admin
.
site
.
register
(
models
.
Service
)
admin
.
site
.
register
(
models
.
RabbitMQInstance
)
admin
.
site
.
register
(
models
.
SSHPublicKey
)
admin
.
site
.
register
(
OIDCConfig
)
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):
...
@@ -48,7 +48,7 @@ class AckView(views.APIView):
for
item
in
request
.
user
.
site
.
state_items
.
all
():
for
item
in
request
.
user
.
site
.
state_items
.
all
():
if
item
.
parent
.
id
==
int
(
state_id
):
if
item
.
parent
.
id
==
int
(
state_id
):
if
item
.
parent
.
state_target
==
'deployed'
:
if
item
.
parent
.
state_target
==
'deployed'
:
item
.
client_deployed
()
item
.
client_deployed
(
{}
)
else
:
else
:
item
.
client_removed
()
item
.
client_removed
()
return
Response
({})
return
Response
({})
...
@@ -79,7 +79,7 @@ class ResponseView(views.APIView):
...
@@ -79,7 +79,7 @@ class ResponseView(views.APIView):
if
state_item
is
not
None
:
if
state_item
is
not
None
:
if
status
==
'deployed'
:
if
status
==
'deployed'
:
state_item
.
client_deployed
(
state_item
.
client_deployed
(
credentials
=
output
.
get
(
'credentials'
,
None
),
credentials
=
output
.
get
(
'credentials'
,
{}
),
)
)
return
Response
({})
return
Response
({})
...
...
django_backend/backend/frontend/views.py
View file @
8aa8b7e6
...
@@ -7,7 +7,7 @@ from rest_framework.permissions import AllowAny
...
@@ -7,7 +7,7 @@ from rest_framework.permissions import AllowAny
from
rest_framework.response
import
Response
from
rest_framework.response
import
Response
from
rest_framework
import
status
from
rest_framework
import
status
from
.
import
serializers
from
.
import
serializers
from
..
import
models
from
..
import
models
,
serializers
as
model_serializers
LOGGER
=
logging
.
getLogger
(
__name__
)
LOGGER
=
logging
.
getLogger
(
__name__
)
...
@@ -88,7 +88,9 @@ class SSHPublicKeyView(views.APIView):
...
@@ -88,7 +88,9 @@ class SSHPublicKeyView(views.APIView):
# we do not delete ssh keys directly, as we need to keep track
# we do not delete ssh keys directly, as we need to keep track
# of them until all clients have also deleted them
# of them until all clients have also deleted them
key
.
delete_key
()
key
.
delete_key
()
return
_api_state_response
(
request
)
return
Response
({
'deleted'
:
True
,
})
elif
request
.
data
[
'type'
]
==
'add'
:
elif
request
.
data
[
'type'
]
==
'add'
:
if
'key'
in
request
.
data
:
if
'key'
in
request
.
data
:
key
=
models
.
SSHPublicKey
(
key
=
models
.
SSHPublicKey
(
...
@@ -97,7 +99,11 @@ class SSHPublicKeyView(views.APIView):
...
@@ -97,7 +99,11 @@ class SSHPublicKeyView(views.APIView):
key
=
request
.
data
[
'key'
][
'key'
],
key
=
request
.
data
[
'key'
][
'key'
],
)
)
key
.
save
()
key
.
save
()
return
_api_state_response
(
request
)
return
Response
(
model_serializers
.
SSHPublicKeySerializer
(
key
,
).
data
)
LOGGER
.
error
(
'SSHPublicKeyView: malformed request %s'
,
request
)
LOGGER
.
error
(
'SSHPublicKeyView: malformed request %s'
,
request
)
return
_api_error_response
(
"malformed request"
)
return
_api_error_response
(
"malformed request"
)
...
...
django_backend/backend/models.py
View file @
8aa8b7e6
...
@@ -256,6 +256,23 @@ class User(AbstractUser):
...
@@ -256,6 +256,23 @@ class User(AbstractUser):
editable
=
False
,
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
# returns the user as identified by userinfo and idp
# if the user does not exists
# if the user does not exists
@
classmethod
@
classmethod
...
@@ -476,17 +493,20 @@ class SSHPublicKey(models.Model):
...
@@ -476,17 +493,20 @@ class SSHPublicKey(models.Model):
editable
=
False
,
editable
=
False
,
)
)
def
states
(
self
):
@
property
states
=
[]
def
deployed_anywhere
(
self
):
for
state
in
self
.
states
.
all
():
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
# does not directly delete the key if the key is deployed or withdrawn
# somewhere
# somewhere
# the receiver 'delete_withdrawn_ssh_key' does the actual deletion
# the receiver 'delete_withdrawn_ssh_key' does the actual deletion
def
delete_key
(
self
):
def
delete_key
(
self
):
# if this key is not deployed anywhere we delete it now
# 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'
))
LOGGER
.
info
(
self
.
msg
(
'Direct deletion of key'
))
self
.
delete
()
self
.
delete
()
return
return
...
@@ -501,10 +521,19 @@ class SSHPublicKey(models.Model):
...
@@ -501,10 +521,19 @@ class SSHPublicKey(models.Model):
# when a key is withdrawn by a client we try to finally delete it
# when a key is withdrawn by a client we try to finally delete it
def
try_final_deletion
(
self
):
def
try_final_deletion
(
self
):
if
(
self
.
deleted
and
not
self
.
states
.
exists
()):
if
self
.
deleted
:
LOGGER
.
info
(
self
.
msg
(
'All clients have withdrawn this key. Final deletion'
))
if
not
self
.
deployed_anywhere
:
self
.
delete
()
return
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
):
def
__str__
(
self
):
if
self
.
deleted
:
if
self
.
deleted
:
...
@@ -526,7 +555,8 @@ class Deployment(models.Model):
...
@@ -526,7 +555,8 @@ class Deployment(models.Model):
user
=
models
.
ForeignKey
(
user
=
models
.
ForeignKey
(
User
,
User
,
related_name
=
'deployments'
,
related_name
=
'deployments'
,
on_delete
=
models
.
CASCADE
,
on_delete
=
models
.
SET_NULL
,
null
=
True
,
)
)
service
=
models
.
ForeignKey
(
service
=
models
.
ForeignKey
(
Service
,
Service
,
...
@@ -572,7 +602,6 @@ class Deployment(models.Model):
...
@@ -572,7 +602,6 @@ class Deployment(models.Model):
LOGGER
.
error
(
self
.
msg
(
'already active'
))
LOGGER
.
error
(
self
.
msg
(
'already active'
))
return
return
LOGGER
.
debug
(
self
.
msg
(
str
(
self
.
ssh_keys
.
all
())))
for
key
in
self
.
ssh_keys
.
all
():
for
key
in
self
.
ssh_keys
.
all
():
self
.
_deploy_key
(
key
)
self
.
_deploy_key
(
key
)
...
@@ -661,15 +690,7 @@ class DeploymentState(models.Model):
...
@@ -661,15 +690,7 @@ class DeploymentState(models.Model):
related_name
=
'states'
,
related_name
=
'states'
,
on_delete
=
models
.
CASCADE
,
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?
# which state do we currently want to reach?
state_target
=
models
.
CharField
(
state_target
=
models
.
CharField
(
max_length
=
50
,
max_length
=
50
,
...
@@ -677,6 +698,10 @@ class DeploymentState(models.Model):
...
@@ -677,6 +698,10 @@ class DeploymentState(models.Model):
default
=
'deployed'
,
default
=
'deployed'
,
)
)
@
property
def
user
(
self
):
return
self
.
deployment
.
user
@
property
@
property
def
states
(
self
):
def
states
(
self
):
return
[
item
.
state
for
item
in
self
.
state_items
.
all
()]
return
[
item
.
state
for
item
in
self
.
state_items
.
all
()]
...
@@ -708,7 +733,6 @@ class DeploymentState(models.Model):
...
@@ -708,7 +733,6 @@ class DeploymentState(models.Model):
# create new state if not
# create new state if not
state
=
cls
(
state
=
cls
(
deployment
=
deployment
,
deployment
=
deployment
,
user
=
deployment
.
user
,
key
=
key
,
key
=
key
,
)
)
state
.
save
()
state
.
save
()
...
@@ -718,7 +742,6 @@ class DeploymentState(models.Model):
...
@@ -718,7 +742,6 @@ class DeploymentState(models.Model):
for
site
in
deployment
.
service
.
site
.
all
():
for
site
in
deployment
.
service
.
site
.
all
():
deploy
=
DeploymentStateItem
(
deploy
=
DeploymentStateItem
(
parent
=
state
,
parent
=
state
,
user
=
deployment
.
user
,
site
=
site
,
site
=
site
,
)
)
deploy
.
save
()
deploy
.
save
()
...
@@ -786,15 +809,6 @@ class DeploymentStateItem(models.Model):
...
@@ -786,15 +809,6 @@ class DeploymentStateItem(models.Model):
site
=
models
.
ForeignKey
(
site
=
models
.
ForeignKey
(
Site
,
Site
,
related_name
=
'state_items'
,
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
,
on_delete
=
models
.
CASCADE
,
)
)
state
=
models
.
CharField
(
state
=
models
.
CharField
(
...
@@ -806,17 +820,17 @@ class DeploymentStateItem(models.Model):
...
@@ -806,17 +820,17 @@ class DeploymentStateItem(models.Model):
# questions for the user (needed for deployment
# questions for the user (needed for deployment
questionnaire
=
JSONField
(
questionnaire
=
JSONField
(
default
=
questionnaire_default
,
default
=
questionnaire_default
,
null
=
True
,
blank
=
True
,
)
)
# credentials for the service
# credentials for the service
# only valid when state == deployed
# only valid when state == deployed
credentials
=
JSONField
(
credentials
=
JSONField
(
default
=
credential_default
,
default
=
credential_default
,
null
=
True
,
blank
=
True
,
)
)
@
property
def
user
(
self
):
return
self
.
parent
.
user
@
property
@
property
def
service
(
self
):
def
service
(
self
):
return
self
.
parent
.
service
return
self
.
parent
.
service
...
@@ -865,8 +879,15 @@ class DeploymentStateItem(models.Model):
...
@@ -865,8 +879,15 @@ class DeploymentStateItem(models.Model):
# client: removed
# client: removed
def
client_removed
(
self
):
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'
)
self
.
_set_state
(
'not_deployed'
)
# this removal maybe was the last of out ssh key
self
.
key
.
try_final_deletion
()
# client: questionnaire
# client: questionnaire
def
client_questionnaire
(
self
,
questionnaire
=
None
):
def
client_questionnaire
(
self
,
questionnaire
=
None
):
self
.
questionnaire
=
questionnaire
self
.
questionnaire
=
questionnaire
...
...
django_backend/backend/serializers.py
View file @
8aa8b7e6
...
@@ -9,22 +9,35 @@ from .models import SSHPublicKey, AuthGroup
...
@@ -9,22 +9,35 @@ from .models import SSHPublicKey, AuthGroup
class
GroupSerializer
(
serializers
.
ModelSerializer
):
class
GroupSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
class
Meta
:
model
=
Group
model
=
Group
fields
=
[
'id'
,
'name'
]
fields
=
[
'id'
,
'name'
,
]
class
AuthGroupSerializer
(
serializers
.
ModelSerializer
):
class
AuthGroupSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
class
Meta
:
model
=
AuthGroup
model
=
AuthGroup
fields
=
[
'id'
,
'name'
]
fields
=
[
'id'
,
'name'
,
]
class
SSHPublicKeySerializer
(
serializers
.
ModelSerializer
):
class
SSHPublicKeySerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
class
Meta
:
model
=
SSHPublicKey
model
=
SSHPublicKey
fields
=
[
'id'
,
'name'
,
'key'
]
fields
=
[
'id'
,
'name'
,
'key'
,
]
class
SSHPublicKeyRefSerializer
(
serializers
.
ModelSerializer
):
class
SSHPublicKeyRefSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
class
Meta
:
model
=
SSHPublicKey
model
=
SSHPublicKey
fields
=
[
'id'
,
'name'
]
fields
=
[
'id'
,
'name'
,
]
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a 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