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
f3029375
Commit
f3029375
authored
Feb 22, 2018
by
Lukas Burgey
Browse files
Merge two files for convenience
parent
aaaaa0b0
Changes
6
Hide whitespace changes
Inline
Side-by-side
django_backend/backend/admin.py
View file @
f3029375
...
...
@@ -6,4 +6,5 @@ from .auth.v1.models import OIDCConfig
admin
.
site
.
register
(
models
.
User
)
admin
.
site
.
register
(
models
.
Site
)
admin
.
site
.
register
(
models
.
Service
)
admin
.
site
.
register
(
models
.
RabbitMQInstance
)
admin
.
site
.
register
(
OIDCConfig
)
django_backend/backend/clientapi/models.py
View file @
f3029375
...
...
@@ -3,7 +3,6 @@ from django.dispatch import receiver
from
..
import
models
from
.serializers
import
DeploymentSerializer
import
json
from
.pubsub
import
PubSubConnection
class
Deployments
:
...
...
@@ -17,7 +16,7 @@ def publish_deployment(sender, instance=None, created=False, **kwargs):
message
=
json
.
dumps
(
DeploymentSerializer
(
instance
).
data
)
confirmed
,
online_sites
=
PubSubConnection
().
publish_by_service
(
confirmed
,
online_sites
=
models
.
rabbitmq_instance
().
publish_by_service
(
instance
.
service
,
message
)
if
confirmed
:
# delivery successful
...
...
django_backend/backend/clientapi/pubsub.py
deleted
100644 → 0
View file @
aaaaa0b0
import
pika
from
..rabbitmq
import
RabbitMQInstance
class
PubSubConnection
:
def
__init__
(
self
):
self
.
host
=
'localhost'
self
.
exchange_name
=
'deployments'
self
.
properties
=
pika
.
BasicProperties
(
delivery_mode
=
1
,
)
def
delivery_callback
(
method
):
print
(
str
(
method
))
def
connect
(
self
):
self
.
connection
=
pika
.
BlockingConnection
(
pika
.
ConnectionParameters
(
host
=
self
.
host
))
self
.
channel
=
self
.
connection
.
channel
()
self
.
channel
.
exchange_declare
(
exchange
=
self
.
exchange_name
,
durable
=
True
,
exchange_type
=
'topic'
)
self
.
channel
.
confirm_delivery
()
# self.channel.confirm_delivery(
# callback=self.delivery_callback,
# )
def
disconnect
(
self
):
self
.
connection
.
close
()
def
service_routing_key
(
self
,
service
):
return
'service.'
+
service
.
name
def
online_clients
(
self
,
service
):
rabbitmq
=
RabbitMQInstance
()
return
[
site
for
site
in
service
.
site
.
all
()
if
rabbitmq
.
is_client_connected
(
site
)]
def
publish_by_service
(
self
,
service
,
message
):
online_clients
=
self
.
online_clients
(
service
)
if
online_clients
:
print
(
"Online clients for service {}: {}"
.
format
(
service
,
online_clients
,
))
else
:
print
(
"No clients online for service {}"
.
format
(
service
))
return
False
,
[]
self
.
connect
()
print
(
'Sent deployment update for service {}'
.
format
(
service
))
# True if all the clients acked the message
delivery_confirmed
=
self
.
channel
.
basic_publish
(
exchange
=
self
.
exchange_name
,
routing_key
=
self
.
service_routing_key
(
service
),
body
=
message
,
properties
=
self
.
properties
,
)
self
.
disconnect
()
return
delivery_confirmed
,
online_clients
django_backend/backend/clientapi/views.py
View file @
f3029375
from
rest_framework
import
generics
from
rest_framework.authentication
import
TokenAuthentication
from
..
import
rabbitmq
from
..
models
import
rabbitmq
_instance
from
.
import
serializers
,
models
# authentication class for the client api
...
...
@@ -44,5 +44,5 @@ class ConfigurationView(generics.ListAPIView):
# we update the rabbitmq permission here, so the
# client can access all of his services, even new ones
rabbitmq
.
RabbitMQI
nstance
().
update_site
(
site
)
rabbitmq
_i
nstance
().
update_site
(
site
)
return
site
.
services
.
all
()
django_backend/backend/models.py
View file @
f3029375
...
...
@@ -7,12 +7,249 @@ from rest_framework.authtoken.models import Token
from
django.db.models.signals
import
post_save
,
pre_delete
# from django.db.models.signals import m2m_changed
from
datetime
import
datetime
from
.rabbitmq
import
RabbitMQInstance
import
requests
from
requests.auth
import
HTTPBasicAuth
import
pika
deployment_change
=
Signal
(
providing_args
=
[
'instance'
])
# clients are registerred at rabbitmq, when they are assigned to a site
# (because we only then know what services they provide)
class
RabbitMQInstance
(
models
.
Model
):
host
=
models
.
CharField
(
max_length
=
150
,
default
=
'localhost'
,
)
exchange
=
models
.
CharField
(
max_length
=
150
,
default
=
'deployments'
,
)
port
=
models
.
IntegerField
(
default
=
15672
)
path
=
models
.
CharField
(
max_length
=
150
,
default
=
'api'
,
)
username
=
models
.
CharField
(
max_length
=
150
,
default
=
'guest'
,
)
password
=
models
.
CharField
(
max_length
=
150
,
default
=
'guest'
,
)
enabled
=
models
.
BooleanField
(
default
=
False
,
)
def
__str__
(
self
):
return
self
.
host
def
print
(
self
,
msg
):
print
(
'[RabbitMQ:{}] {}'
.
format
(
self
.
host
,
msg
))
@
property
def
api
(
self
):
return
'http://{}:{}/{}'
.
format
(
self
.
host
,
self
.
port
,
self
.
path
,
)
@
property
def
auth
(
self
):
return
HTTPBasicAuth
(
self
.
username
,
self
.
password
)
@
property
def
vhost
(
self
):
return
'%2f'
def
get_uri
(
self
,
path
):
return
'{}/{}'
.
format
(
self
.
api
,
path
)
def
rest_get
(
self
,
api_path
):
r
=
requests
.
get
(
self
.
get_uri
(
api_path
),
auth
=
self
.
auth
)
r
.
raise_for_status
()
return
r
.
json
()
# send a rest call with path and data to the rest interface of
# the rabbitmq instance
def
rest_put
(
self
,
api_path
,
data
):
r
=
requests
.
put
(
self
.
get_uri
(
api_path
),
json
=
data
,
auth
=
self
.
auth
)
r
.
raise_for_status
()
return
r
def
rest_del
(
self
,
api_path
):
r
=
requests
.
delete
(
self
.
get_uri
(
api_path
),
auth
=
self
.
auth
)
r
.
raise_for_status
()
return
r
def
set_topic_permissions
(
self
,
site
):
username
=
site
.
client
.
username
path
=
'topic-permissions/{}/{}/'
.
format
(
self
.
vhost
,
username
,
)
# set permissions for the correct topics
# we construct a regex to match the services of the site
services
=
''
omitBar
=
True
for
service
in
site
.
services
.
all
():
prefix
=
'|'
if
omitBar
:
prefix
=
''
omitBar
=
False
services
=
services
+
prefix
+
service
.
name
set_topic_permission_data
=
{
'exchange'
:
self
.
exchange
,
'write'
:
'^$'
,
'read'
:
'^service\.({})$'
.
format
(
services
),
}
return
self
.
rest_put
(
path
,
set_topic_permission_data
)
# set permissions for the user
def
set_permissions
(
self
,
site
):
username
=
site
.
client
.
username
path
=
'permissions/{}/{}/'
.
format
(
self
.
vhost
,
username
,
)
permission
=
'^(amq\.gen.*|{})'
.
format
(
self
.
exchange
)
set_permission_data
=
{
'configure'
:
permission
,
'write'
:
permission
,
'read'
:
permission
,
}
return
self
.
rest_put
(
path
,
set_permission_data
)
# create user at the rabbitmq instance
def
create_user
(
self
,
site
):
username
=
site
.
client
.
username
path
=
'users/{}/'
.
format
(
username
)
user_creation_data
=
{
'password'
:
str
(
site
.
client
.
auth_token
.
key
),
'tags'
:
''
,
}
return
self
.
rest_put
(
path
,
user_creation_data
)
# delete user at the rabbitmq instance
def
delete_user
(
self
,
site
):
username
=
site
.
client
.
username
path
=
'users/{}/'
.
format
(
username
)
return
self
.
rest_del
(
path
)
# PUBLIC API
def
register_site
(
self
,
site
):
self
.
print
(
'register: {} / {}'
.
format
(
site
.
name
,
site
.
client
.
username
))
self
.
create_user
(
site
)
self
.
set_permissions
(
site
)
self
.
set_topic_permissions
(
site
)
def
update_site
(
self
,
site
):
self
.
print
(
'update: {} / {}'
.
format
(
site
.
name
,
site
.
client
.
username
))
self
.
set_topic_permissions
(
site
)
def
deregister_site
(
self
,
site
):
self
.
print
(
'deregister: {} / {}'
.
format
(
site
.
name
,
site
.
client
.
username
))
self
.
delete_user
(
site
)
def
is_client_connected
(
self
,
site
):
connections
=
self
.
rest_get
(
"connections/"
)
clients_for_site
=
[
c
for
c
in
connections
if
c
[
'user'
]
==
site
.
client
.
username
]
return
len
(
clients_for_site
)
>
0
def
connect
(
self
):
self
.
connection_properties
=
pika
.
ConnectionParameters
(
host
=
self
.
host
,
)
self
.
connection
=
pika
.
BlockingConnection
(
self
.
connection_properties
)
self
.
channel
=
self
.
connection
.
channel
()
self
.
channel
.
exchange_declare
(
exchange
=
self
.
exchange
,
durable
=
True
,
exchange_type
=
'topic'
)
self
.
channel
.
confirm_delivery
()
def
disconnect
(
self
):
self
.
connection
.
close
()
def
service_routing_key
(
self
,
service
):
return
'service.'
+
service
.
name
def
online_clients
(
self
,
service
):
return
[
site
for
site
in
service
.
site
.
all
()
if
self
.
is_client_connected
(
site
)]
def
publish_by_service
(
self
,
service
,
message
):
online_clients
=
self
.
online_clients
(
service
)
if
online_clients
:
self
.
print
(
"Online clients for service {}: {}"
.
format
(
service
,
online_clients
,
))
self
.
connect
()
self
.
print
(
'Sent deployment update for service {}'
.
format
(
service
))
# True if all the clients acked the message
delivery_confirmed
=
self
.
channel
.
basic_publish
(
exchange
=
self
.
exchange
,
routing_key
=
self
.
service_routing_key
(
service
),
body
=
message
,
properties
=
pika
.
BasicProperties
(
delivery_mode
=
1
,
),
)
if
delivery_confirmed
:
self
.
print
(
'Delivery confirmed'
)
else
:
self
.
print
(
'Delivery unconfirmed'
)
self
.
disconnect
()
else
:
self
.
print
(
"No clients online for service {}"
.
format
(
service
))
delivery_confirmed
=
False
return
delivery_confirmed
,
online_clients
def
rabbitmq_instance
():
return
RabbitMQInstance
.
objects
.
get
(
enabled
=
True
)
class
User
(
AbstractUser
):
TYPE_CHOICES
=
(
(
'apiclient'
,
'API-Client'
),
...
...
@@ -34,12 +271,6 @@ class User(AbstractUser):
return
self
.
_ssh_keys
.
filter
(
deleted
=
False
)
@
receiver
(
post_save
,
sender
=
settings
.
AUTH_USER_MODEL
)
def
create_auth_token
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
instance
.
user_type
==
'apiclient'
and
created
:
Token
.
objects
.
create
(
user
=
instance
)
def
construct_user
(
user_info
):
return
User
(
sub
=
user_info
[
'sub'
],
...
...
@@ -102,22 +333,6 @@ class Site(models.Model):
return
deployments
@
receiver
(
post_save
,
sender
=
Site
)
def
register_at_rabbitmq
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
not
created
:
return
RabbitMQInstance
().
register_site
(
instance
)
@
receiver
(
pre_delete
,
sender
=
Site
)
def
deregister_at_rabbitmq
(
sender
,
instance
=
None
,
**
kwargs
):
RabbitMQInstance
().
deregister_site
(
instance
)
class
Service
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
150
,
unique
=
True
)
description
=
models
.
TextField
(
max_length
=
300
,
blank
=
True
)
...
...
@@ -286,3 +501,25 @@ class DeploymentUpdate(models.Model):
def
__str__
(
self
):
return
str
(
self
.
user
)
+
':'
+
str
(
self
.
service
)
+
'@'
+
str
(
self
.
site
)
@
receiver
(
post_save
,
sender
=
settings
.
AUTH_USER_MODEL
)
def
create_auth_token
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
instance
.
user_type
==
'apiclient'
and
created
:
Token
.
objects
.
create
(
user
=
instance
)
@
receiver
(
post_save
,
sender
=
Site
)
def
register_at_rabbitmq
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
not
created
:
return
RabbitMQInstance
().
register_site
(
instance
)
@
receiver
(
pre_delete
,
sender
=
Site
)
def
deregister_at_rabbitmq
(
sender
,
instance
=
None
,
**
kwargs
):
RabbitMQInstance
().
deregister_site
(
instance
)
django_backend/backend/rabbitmq.py
deleted
100644 → 0
View file @
aaaaa0b0
import
requests
from
requests.auth
import
HTTPBasicAuth
# clients are registerred at rabbitmq, when they are assigned to a site
# (because we only then know what services they provide)
class
RabbitMQInstance
:
def
__init__
(
self
):
self
.
api
=
'http://localhost:15672/api'
# %2f: url encoded '/' as this is the vhost we use
self
.
vhost
=
'%2f'
self
.
exchange
=
'deployments'
# guest only works on the localhost
self
.
auth
=
HTTPBasicAuth
(
'guest'
,
'guest'
)
def
get_uri
(
self
,
path
):
return
'{}/{}'
.
format
(
self
.
api
,
path
)
def
rest_get
(
self
,
api_path
):
r
=
requests
.
get
(
self
.
get_uri
(
api_path
),
auth
=
self
.
auth
)
r
.
raise_for_status
()
return
r
.
json
()
# send a rest call with path and data to the rest interface of
# the rabbitmq instance
def
rest_put
(
self
,
api_path
,
data
):
r
=
requests
.
put
(
self
.
get_uri
(
api_path
),
json
=
data
,
auth
=
self
.
auth
)
r
.
raise_for_status
()
return
r
def
rest_del
(
self
,
api_path
):
r
=
requests
.
delete
(
self
.
get_uri
(
api_path
),
auth
=
self
.
auth
)
r
.
raise_for_status
()
return
r
def
set_topic_permissions
(
self
,
site
):
username
=
site
.
client
.
username
path
=
'topic-permissions/{}/{}/'
.
format
(
self
.
vhost
,
username
,
)
# set permissions for the correct topics
# we construct a regex to match the services of the site
services
=
''
omitBar
=
True
for
service
in
site
.
services
.
all
():
prefix
=
'|'
if
omitBar
:
prefix
=
''
omitBar
=
False
services
=
services
+
prefix
+
service
.
name
set_topic_permission_data
=
{
'exchange'
:
self
.
exchange
,
'write'
:
'^$'
,
'read'
:
'^service\.({})$'
.
format
(
services
),
}
return
self
.
rest_put
(
path
,
set_topic_permission_data
)
# set permissions for the user
def
set_permissions
(
self
,
site
):
username
=
site
.
client
.
username
path
=
'permissions/{}/{}/'
.
format
(
self
.
vhost
,
username
,
)
permission
=
'^(amq\.gen.*|{})'
.
format
(
self
.
exchange
)
set_permission_data
=
{
'configure'
:
permission
,
'write'
:
permission
,
'read'
:
permission
,
}
return
self
.
rest_put
(
path
,
set_permission_data
)
# create user at the rabbitmq instance
def
create_user
(
self
,
site
):
username
=
site
.
client
.
username
path
=
'users/{}/'
.
format
(
username
)
user_creation_data
=
{
'password'
:
str
(
site
.
client
.
auth_token
.
key
),
'tags'
:
''
,
}
return
self
.
rest_put
(
path
,
user_creation_data
)
# delete user at the rabbitmq instance
def
delete_user
(
self
,
site
):
username
=
site
.
client
.
username
path
=
'users/{}/'
.
format
(
username
)
return
self
.
rest_del
(
path
)
# PUBLIC API
def
register_site
(
self
,
site
):
print
(
'RabbitMQ: register: {} / {}'
.
format
(
site
.
name
,
site
.
client
.
username
))
self
.
create_user
(
site
)
self
.
set_permissions
(
site
)
self
.
set_topic_permissions
(
site
)
def
update_site
(
self
,
site
):
print
(
'RabbitMQ: update: {} / {}'
.
format
(
site
.
name
,
site
.
client
.
username
))
self
.
set_topic_permissions
(
site
)
def
deregister_site
(
self
,
site
):
print
(
'RabbitMQ: deregister: {} / {}'
.
format
(
site
.
name
,
site
.
client
.
username
))
self
.
delete_user
(
site
)
def
is_client_connected
(
self
,
site
):
connections
=
self
.
rest_get
(
"connections/"
)
clients_for_site
=
[
c
for
c
in
connections
if
c
[
'user'
]
==
site
.
client
.
username
]
return
len
(
clients_for_site
)
>
0
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