From f32bd5e4b62e23bd3270b6cc60ead2082e103ba2 Mon Sep 17 00:00:00 2001 From: AlexCXC <1223408988@qq.com> Date: Wed, 18 Oct 2023 15:52:40 +0800 Subject: [PATCH] support license-expiring-notices --- dtable_events/app/app.py | 3 + .../tasks/license_expiring_notices_sender.py | 109 ++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 dtable_events/tasks/license_expiring_notices_sender.py diff --git a/dtable_events/app/app.py b/dtable_events/app/app.py index 9a4008a2..344aa9d5 100644 --- a/dtable_events/app/app.py +++ b/dtable_events/app/app.py @@ -9,6 +9,7 @@ from dtable_events.tasks.dtable_real_time_rows_counter import DTableRealTimeRowsCounter from dtable_events.tasks.ldap_syncer import LDAPSyncer from dtable_events.tasks.dtable_asset_trash_cleaner import DTableAssetTrashCleaner +from dtable_events.tasks.license_expiring_notices_sender import LicenseExpiringNoticesSender from dtable_events.notification_rules.handler import NotificationRuleHandler from dtable_events.notification_rules.dtable_notification_rules_scanner import DTableNofiticationRulesScanner from dtable_events.automations.handler import AutomationRuleHandler @@ -51,6 +52,7 @@ def __init__(self, config, task_mode): self._data_syncr = DataSyncer(config) self._workflow_schedule_scanner = WorkflowSchedulesScanner(config) self._dtable_asset_trash_cleaner = DTableAssetTrashCleaner(config) + self._license_expiring_notices_sender = LicenseExpiringNoticesSender(config) def serve_forever(self): if self._enable_foreground_tasks: @@ -78,3 +80,4 @@ def serve_forever(self): self._data_syncr.start() # default True self._workflow_schedule_scanner.start() # default True self._dtable_asset_trash_cleaner.start() # always True + self._license_expiring_notices_sender.start() # always True diff --git a/dtable_events/tasks/license_expiring_notices_sender.py b/dtable_events/tasks/license_expiring_notices_sender.py new file mode 100644 index 00000000..637ea942 --- /dev/null +++ b/dtable_events/tasks/license_expiring_notices_sender.py @@ -0,0 +1,109 @@ +import logging +import os +import re +from datetime import date +from threading import Thread + +from apscheduler.schedulers.blocking import BlockingScheduler +from dateutil import parser + +from seaserv import ccnet_api + +from dtable_events.app.config import dtable_web_dir +from dtable_events.db import init_db_session_class +from dtable_events.utils import get_opt_from_conf_or_env, get_python_executable, run + + +class LicenseExpiringNoticesSender: + + def __init__(self, config): + self._db_session_class = init_db_session_class(config) + self.days = [35, 15, 7, 6, 5, 4, 3, 2, 1] + self.license_path = '/shared/seatable-license.txt' + self._parse_config(config) + logdir = os.path.join(os.environ.get('LOG_DIR', '')) + self._logfile = os.path.join(logdir, 'license_expiring_notices_sender.log') + + def _parse_config(self, config): + section_name = 'LICENSE-EXPIRING-NOTICES-SENDER' + key_days = 'days' + key_license_path = 'license_path' + if not config.has_section(section_name): + return + + days_str = get_opt_from_conf_or_env(config, section_name, key_days, default='30,15,7,6,5,4,3,2,1') + days = [] + for day_str in days_str.split(','): + try: + day = int(day_str.strip()) + if day > 0 and day not in days: + days.append(day) + except: + pass + if days: + self.days = days + self.license_path = get_opt_from_conf_or_env(config, section_name, key_license_path, default='/shared/seatable-license.txt') + + def start(self): + timer = LicenseExpiringNoticesSenderTimer(self._db_session_class, self.days, self.license_path, self._logfile) + logging.info('Start license notices sender...') + timer.start() + + +class LicenseExpiringNoticesSenderTimer(Thread): + + def __init__(self, db_session_class, days, license_path, _log_file): + super(LicenseExpiringNoticesSenderTimer, self).__init__() + self.daemon = True + self.db_session_class = db_session_class + self.days = days + self.license_path = license_path + self._logfile = _log_file + + def run(self): + sched = BlockingScheduler() + + @sched.scheduled_job('cron', day_of_week='*', hour='*', minute='44') + def check(): + logging.info('start to check license...') + if not os.path.isfile(self.license_path): + logging.warning('No license file found') + return + expire_str = '' + with open(self.license_path, 'r') as f: + for line in f.readlines(): + line = line.strip() + logging.info('line: %s', line) + if line.startswith('Expiration'): + expire_str = line + break + if not expire_str: + logging.warning('No license expiration found') + return + date_strs = re.findall(r'\d{4}-\d{1,2}-\d{1,2}', expire_str) + if not date_strs: + logging.warning('No expire date found: %s', expire_str) + return + try: + expire_date = parser.parse(date_strs[0]).date() + except Exception as e: + logging.warning('No expire date found: %s error: %s', expire_str, e) + return + days = (expire_date - date.today()).days + days = 30 + if days in self.days: + try: + python_exec = get_python_executable() + manage_py = os.path.join(dtable_web_dir, 'manage.py') + cmd = [ + python_exec, + manage_py, + 'send_license_expiring_notices', + str(days), + ] + with open(self._logfile, 'a') as fp: + run(cmd, cwd=dtable_web_dir, output=fp) + except Exception as e: + logging.exception('error when cleaning trash dtables: %s', e) + + sched.start()