| Viewing file:  manager.py (6.98 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
# -*- coding: utf-8 -*-
 # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2022 All Rights Reserved
 #
 # Licensed under CLOUD LINUX LICENSE AGREEMENT
 # http://cloudlinux.com/docs/LICENSE.TXT
 #
 import os
 import logging
 import subprocess
 
 from packaging.version import Version
 
 from clcommon import cpapi
 from clcommon.cpapi.plugins.plesk import query_sql
 from clcommon.public_hooks import CLOUDLINUX_HOOKS, CONTACT_SUPPORT_MESSAGE_FOOTER
 
 BIN_DIR = os.path.join(CLOUDLINUX_HOOKS, 'plesk/')
 PLESK_HOOK_REGISTER_FILE = '/usr/local/psa/bin/event_handler'
 
 HOOKS = {
 'phys_hosting_create': {'SCRIPT_FILE': os.path.join(BIN_DIR, 'physical_hosting_created')},
 'phys_hosting_update': {'SCRIPT_FILE': os.path.join(BIN_DIR, 'physical_hosting_updated')},
 'phys_hosting_delete': {'SCRIPT_FILE': os.path.join(BIN_DIR, 'physical_hosting_deleted')},
 'domain_update':       {'SCRIPT_FILE': os.path.join(BIN_DIR, 'domain_updated')},
 'template_domain_update': {'SCRIPT_FILE': os.path.join(BIN_DIR, 'plan_updated')},
 'template_admin_update': {'SCRIPT_FILE': os.path.join(BIN_DIR, 'plan_updated')},
 }
 
 logger = logging.getLogger(__name__)
 
 
 def plesk_get_event_handler_name_list(plesk_version, bin_dir=BIN_DIR):
 """
 Get all installed events. Assume that we always have
 no more than one executable file of each event type.
 :param plesk_version: plesk cp version;
 :param bin_dir: filter hooks by directory where
 their executable is stored
 :return: Dictionary of already installed events
 {event_name: {handler_id, action_id, command}}
 """
 if Version(plesk_version) < Version('17.8'):
 sql = "SELECT a.name, eh.id, eh.action_id, eh.command " \
 "FROM psa.event_handlers eh " \
 "INNER JOIN psa.actions a ON a.id=eh.action_id"
 else:
 sql = "SELECT action_name, id, 0, command " \
 "FROM psa.event_handlers"
 rows = query_sql(sql)
 result = {}
 for row in rows:
 # row[0] - action_name
 # row[1] - handler id
 # row[2] - action id (deprecated in PLESK 17.8 )
 # row[3] - command
 # take only hooks installed by this lib
 if bin_dir in row[3]:
 result[row[0]] = {
 'handler_id': int(row[1]),
 'action_id': int(row[2]),
 'command': row[3]
 }
 return result
 
 
 def plesk_hook_install(event_id, script_file):
 """
 Plesk single hook install into /usr/local/bin
 :param event_id: Event ID that must be created
 :param script_file: Command for event
 """
 if not os.path.isfile(script_file):
 logger.error("File '%s' does not exist. "
 "Maybe some rpm package is malformed. %s",
 script_file, CONTACT_SUPPORT_MESSAGE_FOOTER)
 return
 
 try:
 output = subprocess.check_output([
 PLESK_HOOK_REGISTER_FILE, '--create',
 '-command', script_file, '-priority', '50',
 '-user', 'root', '-event', str(event_id)
 ], stderr=subprocess.STDOUT, text=True)
 except (OSError, subprocess.CalledProcessError) as e:
 if isinstance(e, subprocess.CalledProcessError):
 message = e.output.rstrip('\n')
 else:
 message = str(e)
 logger.error('failed to register Plesk hook %s: %s. %s',
 script_file, message, CONTACT_SUPPORT_MESSAGE_FOOTER)
 else:
 logger.info('Register hook ended successfully; tool output: `%s`', output.rstrip())
 
 
 def plesk_hook_remove(handler_id):
 """
 Remove Plesk hook
 :param handler_id: Handler ID of created event
 :return: Nothing
 """
 try:
 output = subprocess.check_output([
 PLESK_HOOK_REGISTER_FILE, '--delete', str(handler_id)
 ], stderr=subprocess.STDOUT, text=True)
 except (OSError, subprocess.CalledProcessError) as e:
 if isinstance(e, subprocess.CalledProcessError):
 message = e.output.rstrip('\n')
 else:
 message = str(e)
 logger.error('Failed to unregister Plesk hook %s. '
 'Plesk reported following error: %s. %s',
 handler_id, message, CONTACT_SUPPORT_MESSAGE_FOOTER)
 else:
 logger.info('Unregister hook ended successfully; tool output: `%s`', output.rstrip())
 
 
 def define_hook_ids():
 """
 Defines IDs of hooks by name (extends existing PLESK_HOOKS)
 """
 hook_names_str = ','.join([f"'{i}'" for i in HOOKS])
 sql = f"SELECT id, name FROM psa.actions WHERE name IN({hook_names_str})"
 rows = query_sql(sql)
 if not rows:
 return
 for row in rows:
 HOOKS[row[1]]['EVENT_ID'] = int(row[0])
 
 
 def install_hooks():
 """
 Plesk hooks install into /usr/local/bin
 """
 if not os.path.isfile(PLESK_HOOK_REGISTER_FILE):
 logger.warning('%s does not exist; skip installing hooks', PLESK_HOOK_REGISTER_FILE)
 return
 
 panel_data = cpapi.get_cp_description()
 plesk_version = panel_data['version']
 
 if Version(plesk_version) < Version('17.8'):
 define_hook_ids()
 
 installed_events = plesk_get_event_handler_name_list(plesk_version)
 for hook_name, hook_data in HOOKS.items():
 # Checking of not installed events
 if hook_name in installed_events:
 logger.info('Hook %s is already registered in plesk; skip', hook_name)
 continue
 logger.debug('Registering %s action hook', hook_name)
 if Version(plesk_version) < Version('17.8'):
 plesk_hook_install(hook_data['EVENT_ID'], hook_data['SCRIPT_FILE'])
 else:
 plesk_hook_install(hook_name, hook_data['SCRIPT_FILE'])
 
 
 def remove_hooks():
 """
 All Plesk hooks remove
 """
 if not os.path.isfile(PLESK_HOOK_REGISTER_FILE):
 logger.warning('%s does not exist; skip installing hooks', PLESK_HOOK_REGISTER_FILE)
 return
 
 panel_data = cpapi.get_cp_description()
 plesk_version = panel_data['version']
 
 installed_events = plesk_get_event_handler_name_list(plesk_version)
 
 for hook in HOOKS:
 if hook not in installed_events:
 logger.info('Hook %s is not registered in plesk; skip', hook)
 continue
 logger.debug('Unregistering %s action hook', hook)
 plesk_hook_remove(installed_events[hook]['handler_id'])
 
 
 # DOT NOT CHANGE OR REMOVE: USED IN CAGEFS
 def remove_hook_by_str_id_and_location(event_name, bin_dir):
 """
 Remove hooks of given
 :param event_name: string id of hook type,
 like 'phys_hosting_create'
 :param bin_dir: directory where we should search
 for hooks subscribed to given event name
 :return: Nothing
 """
 if not os.path.isfile(PLESK_HOOK_REGISTER_FILE):
 return
 
 panel_data = cpapi.get_cp_description()
 plesk_version = panel_data['version']
 
 installed_events = plesk_get_event_handler_name_list(plesk_version, bin_dir)
 
 if event_name not in installed_events:
 return
 plesk_hook_remove(installed_events[event_name]['handler_id'])
 
 
 |