add custom management commands

This commit is contained in:
Frédéric Péters 2021-02-26 12:27:42 +01:00
parent b2c0f10899
commit 9872cf7347
4 changed files with 318 additions and 0 deletions

14
combo/has_role.py Normal file
View File

@ -0,0 +1,14 @@
import sys
from django.contrib.auth.models import Group
from django.core.management.base import BaseCommand
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('role_name')
def handle(self, role_name, *args, **options):
if Group.objects.filter(name=role_name).exists():
sys.exit(0)
sys.exit(1)

112
hobo/imio_indus_deploy.py Normal file
View File

@ -0,0 +1,112 @@
import json
import os
import subprocess
import time
import urllib.parse
from django.core.management.base import BaseCommand
from django.db import connection
from hobo.multitenant.management.commands import InteractiveTenantOption
from hobo.environment.models import Authentic, Combo, Passerelle, Wcs
from hobo.agent.worker import settings as agent_settings
class Command(InteractiveTenantOption, BaseCommand):
def add_arguments(self, parser):
super().add_arguments(parser)
parser.add_argument('--directory', dest='directory')
def handle(self, *args, **options):
tenant = self.get_tenant_from_options_or_interactive(**options)
connection.set_tenant(tenant)
self.directory = options['directory']
self.authentic = Authentic.objects.all().first()
self.combos = list(Combo.objects.filter(secondary=False))
self.passerelle = Passerelle.objects.filter(secondary=False).first()
self.wcs = Wcs.objects.filter(secondary=False).first()
for service in [self.authentic, self.passerelle, self.wcs] + self.combos:
service.tenant_name = urllib.parse.urlparse(service.base_url).netloc
self.env = {k: v for k, v in os.environ.items() if k.endswith('_SETTINGS_FILE')}
if not self.wait_for_roles(nowait=True):
self.import_roles()
self.wait_for_roles()
self.import_wcs()
self.import_combos()
self.import_passerelle()
def import_roles(self):
cmd = agent_settings.AUTHENTIC_MANAGE_COMMAND.split()
subprocess.run(
cmd
+ [
'tenant_command',
'import_site',
'-d',
urllib.parse.urlparse(self.authentic.base_url).netloc,
os.path.join(self.directory, 'roles', 'roles.json'),
],
env=self.env,
)
def wait_for_success(self, cmd, nowait=False):
while True:
process = subprocess.run(cmd, env=self.env)
if process.returncode == 0 or nowait:
return process.returncode
time.sleep(0.5)
def wait_for_roles(self, nowait=False):
if not os.path.exists(os.path.join(self.directory, 'roles/roles.json')):
return
wcs_cmd = agent_settings.WCS_MANAGE_COMMAND.split()
combo_cmd = agent_settings.COMBO_MANAGE_COMMAND.split()
roles = json.load(open(os.path.join(self.directory, 'roles', 'roles.json')))
rc = 0
for role in roles['roles']:
role_name = role['name']
rc += self.wait_for_success(
wcs_cmd + ['has_role', '-d', self.wcs.tenant_name, role_name], nowait=nowait
)
for combo in self.combos:
rc += self.wait_for_success(
combo_cmd + ['tenant_command', 'has_role', '-d', combo.tenant_name, role_name],
nowait=nowait,
)
if rc and nowait:
break
return bool(rc == 0)
def import_wcs(self):
wcs_cmd = agent_settings.WCS_MANAGE_COMMAND.split()
cmd = wcs_cmd + ['imio_import_directory', '-d', self.wcs.tenant_name, self.directory]
subprocess.run(cmd, env=self.env)
def import_combos(self):
combo_cmd = agent_settings.COMBO_MANAGE_COMMAND.split()
for combo in self.combos:
exported_file = os.path.join(self.directory, 'combo/%s.json' % combo.template_name)
if not os.path.exists(exported_file):
continue
cmd = combo_cmd + ['tenant_command', 'import_site', '-d', combo.tenant_name, exported_file]
subprocess.run(cmd, env=self.env)
def import_passerelle(self):
if not os.path.exists(os.path.join(self.directory, 'passerelle')):
return
passerelle_cmd = agent_settings.PASSERELLE_MANAGE_COMMAND.split()
for filename in os.listdir(os.path.join(self.directory, 'passerelle')):
if not filename.endswith('.json'):
continue
exported_file = os.path.join(self.directory, 'passerelle', filename)
cmd = passerelle_cmd + [
'tenant_command',
'import_site',
'-d',
self.passerelle.tenant_name,
exported_file,
]
subprocess.run(cmd, env=self.env)

27
wcs/has_role.py Normal file
View File

@ -0,0 +1,27 @@
import os
import sys
from ..qommon.ctl import Command, make_option
from wcs.roles import Role
class Cmd(Command):
name = 'has_role'
def __init__(self):
super().__init__([make_option('-d', '--domain', action='store', dest='domain')])
def execute(self, base_options, sub_options, args):
from .. import publisher
publisher.WcsPublisher.configure(self.config)
publisher = publisher.WcsPublisher.create_publisher(register_tld_names=False)
publisher.app_dir = os.path.join(publisher.app_dir, sub_options.domain)
publisher.set_config()
for role in Role.select():
if role.name == args[0]:
sys.exit(0)
sys.exit(1)
Cmd.register()

View File

@ -0,0 +1,165 @@
import os
import xml.etree.ElementTree as ET
from ..qommon.ctl import Command, make_option
from wcs.blocks import BlockDef
from wcs.carddef import CardDef
from wcs.categories import Category
from wcs.data_sources import NamedDataSource
from wcs.formdef import FormDef
from wcs.workflows import Workflow
from wcs.wscalls import NamedWsCall
class Cmd(Command):
name = 'imio_import_directory'
def __init__(self):
super().__init__(
[
make_option('-d', '--domain', action='store', dest='domain'),
]
)
def execute(self, base_options, sub_options, args):
from .. import publisher
publisher.WcsPublisher.configure(self.config)
publisher = publisher.WcsPublisher.create_publisher(register_tld_names=False)
publisher.app_dir = os.path.join(publisher.app_dir, sub_options.domain)
publisher.set_config()
self.directory = args[0]
self.import_categories()
self.import_datasources()
self.import_wscalls()
self.import_workflows()
self.import_blocks()
self.import_carddefs()
self.import_formdefs()
def import_categories(self):
if not os.path.exists(os.path.join(self.directory, 'category')):
return
for filename in os.listdir(os.path.join(self.directory, 'category')):
category = Category.import_from_xml(open(os.path.join(self.directory, 'category', filename)))
try:
existing_category = Category.get_by_urlname(category.url_name)
except KeyError:
category.store()
else:
# replace
category.id = existing_category.id
category.store()
def import_datasources(self):
if not os.path.exists(os.path.join(self.directory, 'datasources')):
return
for filename in os.listdir(os.path.join(self.directory, 'datasources')):
datasource = NamedDataSource.import_from_xml(
open(os.path.join(self.directory, 'datasources', filename))
)
try:
existing_datasource = NamedDataSource.get_by_slug(datasource.slug, ignore_errors=False)
except KeyError:
datasource.store(comment='Indus Initial Import')
else:
# replace
datasource.id = existing_datasource.id
datasource.store(comment='Indus Update')
def import_workflows(self):
if not os.path.exists(os.path.join(self.directory, 'workflows')):
return
for filename in os.listdir(os.path.join(self.directory, 'workflows')):
workflow = Workflow.import_from_xml(
open(os.path.join(self.directory, 'workflows', filename)),
include_id=False,
check_datasources=True,
)
try:
existing_workflow = [
x for x in Workflow.select(ignore_errors=True) if x and x.name == workflow.name
][0]
except IndexError:
workflow.store(comment='Indus Initial Import')
else:
# replace
workflow.id = existing_workflow.id
workflow.store(comment='Indus Update')
def import_wscalls(self):
if not os.path.exists(os.path.join(self.directory, 'wscalls')):
return
for filename in os.listdir(os.path.join(self.directory, 'wscalls')):
wscall = NamedWsCall.import_from_xml(open(os.path.join(self.directory, 'wscalls', filename)))
try:
existing_wscall = NamedWsCall.get(filename, ignore_errors=False)
except KeyError:
wscall.store(comment='Indus Initial Import')
else:
# replace
wscall.id = existing_wscall.id
wscall.store(comment='Indus Update')
def import_blocks(self):
if not os.path.exists(os.path.join(self.directory, 'blocks')):
return
for filename in os.listdir(os.path.join(self.directory, 'blocks')):
fd = open(os.path.join(self.directory, 'blocks', filename))
tree = ET.parse(fd)
# do not use import_from_xml to avoid autofixing url_name.
blockdef = BlockDef.import_from_xml_tree(tree, include_id=False)
try:
existing_blockdef = BlockDef.get_by_urlname(blockdef.url_name)
except KeyError:
blockdef.store(comment='Indus Initial Import')
else:
# replace
blockdef.id = existing_blockdef.id
blockdef.store(comment='Indus Update')
def import_carddefs(self):
if not os.path.exists(os.path.join(self.directory, 'carddefs')):
return
for filename in os.listdir(os.path.join(self.directory, 'carddefs')):
fd = open(os.path.join(self.directory, 'carddefs', filename))
tree = ET.parse(fd)
# do not use import_from_xml to avoid autofixing url_name.
carddef = CardDef.import_from_xml_tree(tree, include_id=False)
try:
existing_carddef = CardDef.get_by_urlname(carddef.url_name)
except KeyError:
carddef.store(comment='Indus Initial Import')
else:
# replace
carddef.id = existing_carddef.id
carddef.store(comment='Indus Update')
def import_formdefs(self):
if not os.path.exists(os.path.join(self.directory, 'forms')):
return
for filename in os.listdir(os.path.join(self.directory, 'forms')):
fd = open(os.path.join(self.directory, 'forms', filename))
tree = ET.parse(fd)
# do not use import_from_xml to avoid autofixing url_name.
formdef = FormDef.import_from_xml_tree(tree, include_id=False)
try:
existing_formdef = FormDef.get_by_urlname(formdef.url_name)
except KeyError:
formdef.store(comment='Indus Initial Import')
else:
# partial update
for attribute in (
'fields',
'digest_template',
'lateral_template',
'submission_lateral_template',
'user_support',
'geolocations',
):
if hasattr(formdef, attribute):
setattr(existing_formdef, attribute, getattr(formdef, attribute))
existing_formdef.store(comment='Indus Update')
Cmd.register()