File: //proc/25618/root/var/packages/CMS/scripts/CMSDelegate_dirsvs_leave.py
#!/usr/bin/env python3
import logging
import os
import sqlite3
import sys
import syslog
import traceback
from ctypes import CDLL, c_char_p
NAME = 'CMS'
VERSION = '1.0'
VENDOR = 'Synology Inc.'
SDK_MODVER = '1.0'
HOOK_NAME = 'dirsvs_leave'
# The 'SYNO.CMS' prefix helps us to log into CMS's own log file.
LOG_IDENT = 'SYNO.CMS.hook.{}'.format(HOOK_NAME)
CMS_DB_PATH = '/var/packages/CMS/var/db/cms_db.sqlite'
CMS_LIB_PATH = '/var/packages/CMS/target/lib/libcms.so'
syslog.openlog(LOG_IDENT)
logger = logging.getLogger('MyLogger')
logger.setLevel(logging.INFO)
logger.addHandler(logging.StreamHandler())
def log_info(msg: str):
new_msg = '[INFO] {}'.format(msg)
syslog.syslog(syslog.LOG_INFO, new_msg)
logger.info(new_msg)
def log_err(msg: str):
new_msg = '[ERR] {}'.format(msg)
syslog.syslog(syslog.LOG_ERR, new_msg)
logger.error(new_msg)
def log_err_n_raise(msg: str, base_exc: Exception):
log_err(msg)
raise Exception(msg) from base_exc
def log_progress(msg: str, task):
log_info(msg + ' [begin]')
try:
ret = task()
log_info(msg + ' [done]')
return ret
except Exception:
log_err(msg + ' [failed]')
raise
def print_help(bin_name: str):
print('Usage: {} --sdk-mod-ver|--name|--pkg-ver|--vendor|--pre|--post'
.format(bin_name))
def cmds():
return {
'--sdk-mod-ver': lambda: print(SDK_MODVER),
'--name': lambda: print(NAME),
'--pkg-ver': lambda: print(VERSION),
'--vendor': lambda: print(VENDOR),
'--pre': lambda: log_progress('Try running pre hook', pre_hook),
'--post': lambda: log_progress('Try running post hook', post_hook),
}
def main():
bin_name = sys.argv[0]
if len(sys.argv) < 2:
print_help(bin_name)
return
cmd = sys.argv[1]
cmds().get(cmd, lambda: print_help(bin_name))()
# Below is the interesting part of hook.
def pre_hook():
# Define your own pre hook here
pass
def post_hook():
try:
hook_result = log_progress(
'Try reading result of hook',
get_hook_result)
if hook_result == -1:
log_info('Result of hook is {} so skips it'.format(hook_result))
return
dir_server_info = log_progress(
'Try reading directory server info from hook',
get_dir_server_info)
log_info('Directory server info from hook: {}'.format(
str(dir_server_info)))
log_progress(
'Try removing all delegations of given directory server from CMS'
' db',
lambda: remove_delegations_of_directory_server_from_cms_db(
dir_server_info))
except Exception as exc:
log_err_n_raise('Failed to run post hook', exc)
class DirServerInfo:
def __init__(self, server_type, name):
self.server_type = server_type
self.name = name
def __str__(self):
return 'DirServerInfo{{server_type={}, name={}}}'.format(
self.server_type, self.name)
def get_hook_result() -> int:
try:
return int(os.environ['RESULT'])
except Exception as exc:
log_err_n_raise("Failed to get result of hook", exc)
def get_dir_server_info():
try:
return DirServerInfo(
os.environ['TYPE'],
os.environ['DOMAIN'],
)
except Exception as exc:
log_err_n_raise("Failed to get dir server info from hook", exc)
def remove_delegations_of_directory_server_from_cms_db(dir_server_info):
try:
query = read_query_string()
with sqlite3.connect(CMS_DB_PATH) as conn:
conn.cursor().execute(
query,
(dir_server_info.server_type, dir_server_info.name))
except Exception as exc:
log_err_n_raise(
"Failed to remove all delegations"
" of direcotry server from cms db: {}"
.format(str(dir_server_info)),
exc)
def read_query_string() -> str:
try:
libcms = CDLL(CMS_LIB_PATH)
query_fn = (
libcms.SYNOCMSDelegateRemoveAllOfDirectoryServer_sqlite_query
)
query_fn.restype = c_char_p
return query_fn().decode('utf-8')
except Exception as exc:
log_err_n_raise(
'Failed to read query string for'
' removing all delegations from directory server',
exc)
if __name__ == '__main__':
try:
main()
except Exception:
# Here we log call stack to syslog only since python would log to
# stdout for us.
syslog.syslog(syslog.LOG_ERR, traceback.format_exc())
raise