Add page for configuring datasync

experimental! until proven worthy..
This commit is contained in:
Lance Edgar 2021-11-29 17:23:01 -06:00
parent bb0666b77d
commit 8aff5d519d
3 changed files with 954 additions and 15 deletions

View file

@ -26,12 +26,18 @@ DataSync Views
from __future__ import unicode_literals, absolute_import
import getpass
import subprocess
import logging
import sqlalchemy as sa
from rattail.db import model
from rattail.datasync.config import load_profiles
from rattail.datasync.util import get_lastrun
from tailbone.views import MasterView
from tailbone.util import csrf_token
log = logging.getLogger(__name__)
@ -78,30 +84,197 @@ class DataSyncChangeView(MasterView):
return kwargs
def restart(self):
# TODO: Add better validation (e.g. CSRF) here?
if self.request.method == 'POST':
cmd = self.rattail_config.getlist('tailbone', 'datasync.restart', default='/bin/sleep 3') # simulate by default
log.debug("attempting datasync restart with command: {}".format(cmd))
result = subprocess.call(cmd)
if result == 0:
self.request.session.flash("DataSync daemon has been restarted.")
else:
self.request.session.flash("DataSync daemon could not be restarted; result was: {}".format(result), 'error')
cmd = self.rattail_config.getlist('tailbone', 'datasync.restart',
# nb. simulate by default
default='/bin/sleep 3')
log.debug("attempting datasync restart with command: %s", cmd)
result = subprocess.call(cmd)
if result == 0:
self.request.session.flash("DataSync daemon has been restarted.")
else:
self.request.session.flash("DataSync daemon could not be restarted; result was: {}".format(result), 'error')
return self.redirect(self.request.get_referrer(default=self.request.route_url('datasyncchanges')))
def configure(self):
"""
View for configuring the DataSync daemon.
"""
if self.request.method == 'POST':
data = self.request.json_body
self.save_settings(data)
self.request.session.flash("Settings have been saved. "
"You should probably restart DataSync now.")
return self.json_response({'success': True})
profiles = load_profiles(self.rattail_config,
include_disabled=True,
ignore_problems=True)
profiles_data = []
for profile in sorted(profiles.values(), key=lambda p: p.key):
data = {
'key': profile.key,
'watcher_spec': profile.watcher_spec,
'watcher_dbkey': profile.watcher.dbkey,
'watcher_delay': profile.watcher.delay,
'watcher_retry_attempts': profile.watcher.retry_attempts,
'watcher_retry_delay': profile.watcher.retry_delay,
'watcher_default_runas': profile.watcher.default_runas,
'watcher_consumes_self': profile.watcher.consumes_self,
# 'notes': None, # TODO
'enabled': profile.enabled,
}
consumers = []
if profile.watcher.consumes_self:
pass
else:
for consumer in sorted(profile.consumers, key=lambda c: c.key):
consumers.append({
'key': consumer.key,
'consumer_spec': consumer.spec,
'consumer_dbkey': consumer.dbkey,
'consumer_runas': getattr(consumer, 'runas', None),
'consumer_delay': consumer.delay,
'consumer_retry_attempts': consumer.retry_attempts,
'consumer_retry_delay': consumer.retry_delay,
'enabled': consumer.enabled,
})
data['consumers_data'] = consumers
profiles_data.append(data)
return {
'master': self,
# TODO: really only buefy themes are supported here
'use_buefy': self.get_use_buefy(),
'index_title': "DataSync Changes",
'index_url': self.get_index_url(),
'profiles': profiles,
'profiles_data': profiles_data,
'restart_command': self.rattail_config.get('tailbone', 'datasync.restart'),
'system_user': getpass.getuser(),
}
def save_settings(self, data):
model = self.model
# collect new settings
settings = []
watch = []
for profile in data['profiles']:
pkey = profile['key']
if profile['enabled']:
watch.append(pkey)
settings.extend([
{'name': 'rattail.datasync.{}.watcher'.format(pkey),
'value': profile['watcher_spec']},
{'name': 'rattail.datasync.{}.watcher.db'.format(pkey),
'value': profile['watcher_dbkey']},
{'name': 'rattail.datasync.{}.watcher.delay'.format(pkey),
'value': profile['watcher_delay']},
{'name': 'rattail.datasync.{}.watcher.retry_attempts'.format(pkey),
'value': profile['watcher_retry_attempts']},
{'name': 'rattail.datasync.{}.watcher.retry_delay'.format(pkey),
'value': profile['watcher_retry_delay']},
{'name': 'rattail.datasync.{}.consumers.runas'.format(pkey),
'value': profile['watcher_default_runas']},
])
consumers = []
if profile['watcher_consumes_self']:
consumers = ['self']
else:
for consumer in profile['consumers_data']:
ckey = consumer['key']
if consumer['enabled']:
consumers.append(ckey)
settings.extend([
{'name': 'rattail.datasync.{}.consumer.{}'.format(pkey, ckey),
'value': consumer['consumer_spec']},
{'name': 'rattail.datasync.{}.consumer.{}.db'.format(pkey, ckey),
'value': consumer['consumer_dbkey']},
{'name': 'rattail.datasync.{}.consumer.{}.delay'.format(pkey, ckey),
'value': consumer['consumer_delay']},
{'name': 'rattail.datasync.{}.consumer.{}.retry_attempts'.format(pkey, ckey),
'value': consumer['consumer_retry_attempts']},
{'name': 'rattail.datasync.{}.consumer.{}.retry_delay'.format(pkey, ckey),
'value': consumer['consumer_retry_delay']},
{'name': 'rattail.datasync.{}.consumer.{}.runas'.format(pkey, ckey),
'value': consumer['consumer_runas']},
])
settings.extend([
{'name': 'rattail.datasync.{}.consumers'.format(pkey),
'value': ', '.join(consumers)},
])
settings.extend([
{'name': 'rattail.datasync.watch',
'value': ', '.join(watch)},
{'name': 'tailbone.datasync.restart',
'value': data['restart_command']},
])
# delete all current settings
self.delete_settings()
# create all new settings
for setting in settings:
self.Session.add(model.Setting(name=setting['name'],
value=setting['value']))
def delete_settings(self):
model = self.model
to_delete = [
'rattail.datasync.watch',
'tailbone.datasync.restart',
]
for setting in to_delete:
setting = self.Session.query(model.Setting).get(setting)
if setting:
self.Session.delete(setting)
self.Session.query(model.Setting)\
.filter(sa.or_(
model.Setting.name.like('rattail.datasync.%.watcher'),
model.Setting.name.like('rattail.datasync.%.watcher.db'),
model.Setting.name.like('rattail.datasync.%.watcher.delay'),
model.Setting.name.like('rattail.datasync.%.watcher.retry_attempts'),
model.Setting.name.like('rattail.datasync.%.watcher.retry_delay'),
model.Setting.name.like('rattail.datasync.%.consumers'),
model.Setting.name.like('rattail.datasync.%.consumers.runas'),
model.Setting.name.like('rattail.datasync.%.consumer.%')))\
.delete(synchronize_session=False)
@classmethod
def defaults(cls, config):
rattail_config = config.registry.settings.get('rattail_config')
cls._defaults(config)
cls._datasync_defaults(config)
@classmethod
def _datasync_defaults(cls, config):
permission_prefix = cls.get_permission_prefix()
# fix permission group title
config.add_tailbone_permission_group('datasync', label="DataSync")
config.add_tailbone_permission_group(permission_prefix, label="DataSync")
# restart datasync
config.add_tailbone_permission('datasync', 'datasync.restart', label="Restart DataSync Daemon")
config.add_route('datasync.restart', '/datasync/restart')
config.add_view(cls, attr='restart', route_name='datasync.restart', permission='datasync.restart')
config.add_tailbone_permission(permission_prefix,
'{}.restart'.format(permission_prefix),
label="Restart the DataSync daemon")
config.add_route('datasync.restart', '/datasync/restart',
request_method='POST')
config.add_view(cls, attr='restart',
route_name='datasync.restart',
permission='{}.restart'.format(permission_prefix))
cls._defaults(config)
# configure datasync
config.add_tailbone_permission(permission_prefix,
'{}.configure'.format(permission_prefix),
label="Configure the DataSync daemon")
config.add_route('datasync.configure', '/datasync/configure')
config.add_view(cls, attr='configure',
route_name='datasync.configure',
permission='{}.configure'.format(permission_prefix),
renderer='/datasync/configure.mako')
# TODO: deprecate / remove this
DataSyncChangesView = DataSyncChangeView