hobo/hobo/agent/hobo/management/commands/hobo_deploy.py

160 lines
7.7 KiB
Python

from django.contrib.contenttypes.models import ContentType
from django.utils.timezone import now
from tenant_schemas.utils import tenant_context
from hobo.agent.common.management.commands import hobo_deploy
from hobo.deploy.signals import notify_agents
from hobo.environment.models import AVAILABLE_SERVICES, Hobo, Variable
from hobo.environment.utils import get_or_create_local_hobo
from hobo.multitenant.middleware import TenantMiddleware, TenantNotFound
from hobo.profile.models import AttributeDefinition
class Command(hobo_deploy.Command):
help = 'Deploy multitenant hobo service from hobo'
early_secondary_exit = False
def deploy_specifics(self, hobo_environment, tenant):
me = [x for x in hobo_environment.get('services') if x.get('this')][0]
if not me.get('secondary'):
super().deploy_specifics(hobo_environment, tenant)
with tenant_context(tenant):
services = hobo_environment.get('services')
if me.get('secondary'):
# check we are currently processing the primary hobo, we don't
# want to create secondary services on every branches.
if Hobo.objects.filter(secondary=False, local=False).count() == 0:
return
is_primary_hobo = True
# on the primary hobo, notify other primary services, this will
# get authentic to know about secondary services
propagate_notify = True
else:
is_primary_hobo = False
propagate_notify = False
for service_dict in services:
if service_dict.get('secondary'):
continue
if service_dict.get('base_url') == me['base_url']:
# URL might have changed, need to update local hobo
local_hobo = get_or_create_local_hobo()
if local_hobo and local_hobo.get_base_url_path() != service_dict.get('base_url'):
local_hobo.change_base_url(service_dict.get('base_url'))
local_hobo.save()
continue
for service_klass in AVAILABLE_SERVICES:
if service_klass.Extra.service_id == service_dict.get('service-id'):
break
else:
continue
if me.get('secondary') and service_dict.get('service-id') == 'hobo':
continue
if service_klass.objects.filter(secondary=False, base_url=service_dict['base_url']).count():
# make sure a real service is not secondaryed
continue
slug_prefix = '_interco_'
if is_primary_hobo:
# this is the primary hobo, receiving a notification
# because something changed in secondary hobo environment.
# mark services with ou-label/ou-slug
secondary_hobo = [
x for x in services if x['service-id'] == 'hobo' and not x.get('secondary')
][0]
slug_prefix = '_%s_' % hobo_environment['variables']['ou-slug']
service_slug = '%s%s' % (slug_prefix, service_dict['slug'])
service, created = None, False
for legacy_urls in service_dict.get('legacy_urls', []):
try:
service = service_klass.objects.get(base_url=legacy_urls['base_url'], secondary=True)
service.change_base_url(service_dict['base_url'])
break
except service_klass.DoesNotExist:
pass
if not service:
service, created = service_klass.objects.get_or_create(
base_url=service_dict['base_url'],
secondary=True,
defaults={
'title': service_dict['title'],
'slug': service_slug,
'secret_key': service_dict.get('secret_key'),
},
)
service.title = service_dict['title']
service.secret_key = service_dict.get('secret_key')
service.template_name = service_dict.get('template_name') or ''
service.slug = service_slug
service.use_as_idp_for_self = True
service.last_operational_check_timestamp = now()
service.last_operational_success_timestamp = service.last_operational_check_timestamp
service.save()
if is_primary_hobo:
# add variables to mark the service as a different
# organizational unit
service_type = ContentType.objects.get_for_model(service_klass)
variable, created = Variable.objects.get_or_create(
name='ou-label', auto=True, service_type=service_type, service_pk=service.id
)
variable.value = hobo_environment['variables']['ou-label']
variable.save()
variable, created = Variable.objects.get_or_create(
name='ou-slug', auto=True, service_type=service_type, service_pk=service.id
)
variable.value = hobo_environment['variables']['ou-slug']
variable.save()
if not is_primary_hobo:
# this is the secondary hobo, set service slug and label as
# global variables so they can later be used to identify
# this "organizational unit".
variable, created = Variable.objects.get_or_create(
name='ou-label', auto=True, service_pk=None
)
variable.value = me['title']
variable.save()
variable, created = Variable.objects.get_or_create(
name='ou-slug', auto=True, service_pk=None
)
variable.value = me['slug']
variable.save()
# and reproduce profile settings from primary
if 'profile' in hobo_environment:
seen = []
changes = False
for i, field in enumerate(hobo_environment['profile']['fields']):
attribute, created = AttributeDefinition.objects.get_or_create(
name=field['name'], defaults={'label': field['label']}
)
if created:
changes = True
for k, v in field.items():
if getattr(attribute, k, None) != v:
setattr(attribute, k, v)
changes = True
if attribute.order != (i + 1):
changes = True
attribute.order = i + 1
attribute.save()
seen.append(attribute.name)
removed, details_ = AttributeDefinition.objects.exclude(name__in=seen).delete()
if removed:
changes = True
if changes:
# if there were changes to profile fields, propagate them.
propagate_notify = True
if propagate_notify:
notify_agents(None)