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
226df6a3
Commit
226df6a3
authored
Nov 07, 2018
by
Lukas Burgey
Browse files
Implement new credential tracking
A large step towards solving
#7
parent
6f1b9c1c
Changes
2
Hide whitespace changes
Inline
Side-by-side
feudal/backend/models/__init__.py
View file @
226df6a3
...
...
@@ -290,19 +290,17 @@ class NewDeployment(models.Model):
self
.
publish_to_client
()
# each state item publishes its state to the user
# some parts of the user object / the credentials have changed
# we have to update them at the clients
def
user_credential
s_changed
(
self
):
LOGGER
.
debug
(
'User object of %s changed'
,
self
.
user
)
# TODO implement
def
user_credential_added
(
self
,
key
):
for
item
in
self
.
state_items
.
all
():
item
.
user_credential
_added
(
key
)
self
.
publish
()
# Currently out of scope
# def user_credential_added(self, key
):
#
raise Exception('user_credentialis currently out of scope and therefore not implemented'
)
def
user_credential_removed
(
self
,
key
):
for
item
in
self
.
state_items
.
all
(
):
item
.
user_credential_removed
(
key
)
# Currently out of scope
# def user_credential_removed(self, key):
# raise Exception('user_credential_removed is currently out of scope and therefore not implemented')
self
.
publish
()
def
service_added
(
self
,
service
):
LOGGER
.
debug
(
self
.
msg
(
'Adding service {}'
.
format
(
service
)))
...
...
@@ -338,7 +336,7 @@ class NewDeployment(models.Model):
LOGGER
.
error
(
'Deployment has neither a group or a service'
)
raise
ValueError
(
'Deployment has neither a group or a service'
)
#
update the state of the remote webpag
e
#
sends a state update via RabbitMQ / STOMP to the users webpage instanc
e
def
publish_to_user
(
self
):
if
self
.
user
is
not
None
:
# mitigating circular dependencies here
...
...
@@ -351,12 +349,16 @@ class NewDeployment(models.Model):
msg
,
)
def
publish
(
self
):
self
.
publish_to_user
()
self
.
publish_to_client
()
def
msg
(
self
,
msg
):
return
'
[
{}
]
{}'
.
format
(
self
,
msg
)
return
'{}
-
{}'
.
format
(
self
,
msg
)
def
_set_target
(
self
,
target
):
self
.
state_target
=
target
LOGGER
.
debug
(
self
.
msg
(
'
t
arget
is now:
'
+
target
))
LOGGER
.
debug
(
self
.
msg
(
'
T
arget
changed to
'
+
target
))
self
.
save
()
def
__str__
(
self
):
...
...
@@ -427,23 +429,6 @@ class NewDeploymentStateItem(models.Model):
def
group
(
self
):
return
self
.
parent
.
group
# starts tracking this the credential for this item
def
add_credential
(
self
,
credential
):
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
'add_credential: %s %s'
,
self
,
credential
)
CredentialState
.
get_credential_state
(
credential
,
self
,
)
def
remove_credential
(
self
,
credential
):
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
'remove_credential: %s %s'
,
self
,
credential
)
# TODO implement
# what is needs to be done here?
pass
@
classmethod
def
get_state_item
(
cls
,
parent
=
None
,
site
=
None
,
service
=
None
):
try
:
...
...
@@ -463,13 +448,31 @@ class NewDeploymentStateItem(models.Model):
)
item
.
save
()
# start tracking the states of the users ssh keys
for
key
in
parent
.
user
.
ssh_keys
.
all
():
item
.
add_credential
(
key
)
LOGGER
.
debug
(
'get_state_item: created %s'
,
item
)
return
item
# starts tracking this the credential for this item
def
user_credential_added
(
self
,
credential
):
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
'user_credential_added: %s %s'
,
self
,
credential
)
credential_state
=
CredentialState
.
get_credential_state
(
credential
,
self
,
)
def
user_credential_removed
(
self
,
credential
):
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
'user_credential_removed: %s %s'
,
self
,
credential
)
try
:
credential_state
=
self
.
credential_states
.
get
(
credential
=
credential
)
credential_state
.
credential_deleted
()
self
.
parent
.
publish
()
except
CredentialState
.
DoesNotExist
:
LOGGER
.
error
(
self
.
msg
(
'Credential {} has no CredentialState'
.
format
(
credential
)))
# STATE TRANSITIONS
# user: provisioning requested
...
...
@@ -482,6 +485,9 @@ class NewDeploymentStateItem(models.Model):
LOGGER
.
info
(
self
.
msg
(
'ignoring invalid state transition user_deploy'
))
return
for
credential_state
in
self
.
credential_states
.
all
():
credential_state
.
set_target
(
DEPLOYED
)
self
.
_set_state
(
DEPLOYMENT_PENDING
,
publish
=
False
,
# the post response already contains the update
...
...
@@ -509,6 +515,9 @@ class NewDeploymentStateItem(models.Model):
self
.
_set_state
(
NOT_DEPLOYED
)
return
for
credential_state
in
self
.
credential_states
.
all
():
credential_state
.
set_target
(
DEPLOYED
)
self
.
_set_state
(
REMOVAL_PENDING
,
publish
=
False
,
# the post response already contains the update
...
...
@@ -521,19 +530,19 @@ class NewDeploymentStateItem(models.Model):
self
.
parent
.
publish_to_client
()
def
client_credential_states
(
self
,
credential_states
):
LOGGER
.
debug
(
'client_credential_states: %s'
,
credential_states
)
# maps ssh key names to their state
ssh_key_states
=
credential_states
.
get
(
'ssh_key'
,
None
)
if
ssh_key_states
is
not
None
:
for
key_name
in
ssh_key_states
:
try
:
credential_state
=
self
.
credential_states
.
get
(
credential__name
=
key_name
)
LOGGER
.
debug
(
'RECEIVED update to credential state %s'
,
credential_state
)
credential_state
.
set
(
ssh_key_states
[
key_name
])
except
CredentialState
.
DoesNotExist
:
LOGGER
.
error
(
'Credential state for key %s and item %s does not exist'
,
key_name
,
self
)
LOGGER
.
error
(
'selfs states: %s'
,
self
.
credential_states
.
all
())
# ASSUMPTION:
# if we hear nothing about a credential we assume it got deprovisioned!
for
credential_state
in
self
.
credential_states
.
all
():
if
(
ssh_key_states
is
not
None
and
credential_state
.
credential
.
name
in
ssh_key_states
):
credential_state
.
set
(
ssh_key_states
[
credential_state
.
credential
.
name
])
else
:
credential_state
.
set
(
NOT_DEPLOYED
)
# returns None on success, or a string describing an error
def
client_response
(
self
,
output
):
...
...
@@ -580,35 +589,34 @@ class NewDeploymentStateItem(models.Model):
self
.
_set_state
(
state
)
return
None
# the credentials which are currently being deployed / removed
def
get_onroute_credential_states
(
self
):
return
self
.
credential_states
.
filter
(
state
=
self
.
state
,
)
def
set_onroute_credential_states
(
self
,
state
):
for
credential_state
in
self
.
get_onroute_credential_states
().
all
():
credential_state
.
set
(
state
)
# resets all client sent values
def
_reset
(
self
):
self
.
credentials
=
credential_default
()
self
.
questionnaire
=
questionnaire_default
()
self
.
message
=
''
def
msg
(
self
,
msg
):
return
'[{}] {}'
.
format
(
self
,
msg
)
def
_set_state
(
self
,
state
,
publish
=
True
):
self
.
set_onroute_credential_states
(
state
)
# assure all user credentials have a state
for
key
in
self
.
parent
.
user
.
ssh_keys
.
all
():
try
:
CredentialState
.
get_credential_state
(
credential
=
key
,
target
=
self
,
)
except
CredentialState
.
DoesNotExist
:
LOGGER
.
error
(
'CredentialState.DoesNotExist in _set_state'
)
self
.
state
=
state
self
.
save
()
LOGGER
.
debug
(
self
.
msg
(
'State changed to '
+
self
.
state
))
if
publish
:
self
.
parent
.
publish_to_user
()
def
msg
(
self
,
msg
):
return
'{} - {}'
.
format
(
self
,
msg
)
def
__str__
(
self
):
return
'Item: ({}:{}:{})#{}'
.
format
(
return
'
DS
Item: ({}:{}:{})#{}'
.
format
(
self
.
parent
.
id
,
self
.
service
,
self
.
site
,
...
...
@@ -658,44 +666,59 @@ class CredentialState(models.Model):
credential
=
credential
,
target
=
target
,
state
=
NOT_DEPLOYED
,
state_target
=
target
.
parent
.
state_target
,
)
new_state
.
save
()
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
new_state
.
msg
(
'
State c
reated'
))
LOGGER
.
debug
(
new_state
.
msg
(
'
C
reated'
))
return
new_state
def
set_target
(
self
,
target
):
# state_target is locked, since we are marked for deletion
if
self
.
_credential_deleted
:
LOGGER
.
debug
(
self
.
msg
(
'Unable to change state_target of credential marked for deletion'
))
return
self
.
state_target
=
target
self
.
save
()
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
self
.
msg
(
'
State t
arget changed to {}'
.
format
(
target
)))
LOGGER
.
debug
(
self
.
msg
(
'
T
arget changed to {}'
.
format
(
target
)))
def
set
(
self
,
state
):
if
state
==
NOT_DEPLOYED
and
self
.
_credential_deleted
:
self
.
_delete_state
()
if
state
==
self
.
state
:
return
self
.
state
=
state
self
.
save
()
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
self
.
msg
(
'State changed to {}'
.
format
(
state
)))
def
credential_deleted
(
self
):
if
self
.
state
==
NOT_DEPLOYED
:
self
.
_delete_state
()
self
.
state_target
=
NOT_DEPLOYED
self
.
_credential_deleted
=
True
self
.
save
()
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
self
.
msg
(
'Credential marked as deleted'
))
LOGGER
.
debug
(
self
.
msg
(
'Marked as deleted'
))
def
_delete_state
(
self
):
LOGGER
.
debug
(
self
.
msg
(
'Deleted'
))
self
.
delete
()
def
msg
(
self
,
message
):
return
self
.
target
.
msg
(
'Credential {}:
{}'
.
format
(
self
.
credential
,
message
)
)
return
'{} -
{}'
.
format
(
self
,
message
)
def
__str__
(
self
):
return
'{}@{}'
.
format
(
return
'CState: ({}:{})#{}'
.
format
(
self
.
target
.
id
,
self
.
credential
,
self
.
target
,
self
.
id
,
)
feudal/backend/models/users.py
View file @
226df6a3
...
...
@@ -300,14 +300,15 @@ class User(AbstractUser):
try
:
key
=
self
.
_ssh_keys
.
get
(
name
=
unity_key_name
)
# is the idp key still present?
if
idp_key_name
not
in
userinfo
:
self
.
user_changed_key_changed
(
key
)
key
.
delete_key
()
self
.
user_changed_key_removed
(
key
)
return
True
# is the idp key changed?
if
key
.
key
!=
unity_key_value
:
key
.
delete_key
()
key
=
SSHPublicKey
(
name
=
unity_key_name
,
...
...
@@ -366,27 +367,6 @@ class User(AbstractUser):
LOGGER
.
info
(
'user_changed'
)
pass
def
sanity_check
(
self
):
for
dep
in
self
.
deployments
.
all
():
LOGGER
.
debug
(
'User has a deployment %s with target %s'
,
dep
,
dep
.
state_target
)
for
state_item
in
dep
.
state_items
.
all
():
LOGGER
.
debug
(
'User has a state item for %s'
,
state_item
.
service
)
for
credential_state
in
state_item
.
credential_states
.
all
():
if
credential_state
.
credential
is
None
:
LOGGER
.
debug
(
'Credential state exists for null key -> we have to update the deployment so the according key is deleted'
)
else
:
LOGGER
.
debug
(
'User has a credential state for %s'
,
credential_state
.
credential
)
for
ssh_key
in
self
.
ssh_keys
.
all
():
try
:
state_item
.
credential_states
.
get
(
key
=
ssh_key
,
)
except
:
LOGGER
.
debug
(
'ssh key %s has no credential_state! -> we possibly need to deploy this key'
,
ssh_key
)
# TODO implement all user_changed_ triggers
# The user_changed methods are triggerd in user_changed
# They serve to assure the correct state at the backend and clients
...
...
@@ -395,7 +375,7 @@ class User(AbstractUser):
LOGGER
.
debug
(
'user_changed_key_added: %s %s'
,
self
,
key
)
for
dep
in
self
.
deployments
.
all
():
LOGGER
.
debug
(
'user_changed_key_added: need to add key to deployment %s'
,
dep
)
dep
.
user_credential_added
(
key
)
def
user_changed_key_changed
(
self
,
key
):
LOGGER
.
debug
(
'user_changed_key_changed: %s %s'
,
self
,
key
)
...
...
@@ -406,9 +386,8 @@ class User(AbstractUser):
def
user_changed_key_removed
(
self
,
key
):
LOGGER
.
debug
(
'user_changed_key_removed: %s %s'
,
self
,
key
)
for
credential_state
in
key
.
credential_states
.
all
():
LOGGER
.
debug
(
'user_changed_key_removed: need to handle credential state %s'
,
credential_state
)
# delete accordingly
for
dep
in
self
.
deployments
.
all
():
dep
.
user_credential_removed
(
key
)
def
user_changed_group_added
(
self
,
group
):
LOGGER
.
debug
(
'user_changed_group_added: %s %s'
,
self
,
group
)
...
...
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