/
opt
/
cloudlinux
/
venv
/
lib64
/
python3.11
/
site-packages
/
clwpos
/
user
/
Upload Filee
HOME
# -*- coding: utf-8 -*- # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2021 All Rights Reserved # # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENSE.TXT from __future__ import absolute_import import subprocess from typing import Optional, Tuple, Dict from clwpos import gettext as _ from clcommon.utils import ExternalProgramFailed, run_command from clwpos.cl_wpos_exceptions import WposError class DeadRedisPurgeAttempt(WposError): """ Happens when somebody tries to purge redis instance which is not runnning """ def __init__(self): super().__init__(message=_( "Unable to purge cache because cache database is not running. " "Enable at least one optimization feature to start cache database instance.")) class PurgeFailedError(WposError): """ Happens when redis is not able to purge cached data for some reason. """ def __init__(self, std_out: str, std_err: str): super().__init__( message=_('Unable to purge cache. \n' 'Database backend returned error of command "%(command)s" execution. ' 'Try again a bit later or contact your system administrator for help.'), details='stdout: \n<i>%(stdout)s</i>\n' 'stderr: \n<i>%(stderr)s</i>\n', context={ "command": 'purge', "stdout": std_out or 'empty', "stderr": std_err or 'empty', }) class RedisLibUser(object): def __init__(self, socket_path: str, redis_cli_path: str = "/opt/alt/redis/bin/redis-cli") -> None: self.socket_path = socket_path self.redis_cli_path = redis_cli_path def get_redis_shell_command(self, redis_command): return [ self.redis_cli_path, "-s", self.socket_path, ] + redis_command.split(" ") def run_redis_command(self, command: str) -> Tuple[int, str, str]: redis_command = self.get_redis_shell_command(command) try: returncode, std_out, std_err = run_command( redis_command, return_full_output=True ) except (subprocess.CalledProcessError, ExternalProgramFailed) as error: raise WposError( message=_("Error during %(command)s command execution: \n%(error)s"), context={"command": " ".join(redis_command), "error": str(error)}, ) return returncode, std_out, std_err def purge_redis(self) -> Dict: """ Clean entire redis cache for user. """ if not self.is_redis_alive(): raise DeadRedisPurgeAttempt() purge_command = "flushall async" returncode, std_out, std_err = self.run_redis_command(purge_command) # Output of Redis FLUSHALL command should be: "OK" if returncode != 0 or "ok" not in std_out.lower(): raise PurgeFailedError(std_out, std_err) return { "used_memory": self.get_redis_used_memory() } def is_redis_alive(self) -> bool: """ Check if user's redis is alive. """ returncode, std_out, _ = self.run_redis_command("ping") return returncode == 0 and "pong" in std_out.lower() def is_redis_empty(self) -> bool: """ Check if user's redis is empty. Example (redis is empty): # Keyspace Example (redis is NOT empty): # Keyspace db0:keys=2,expires=0,avg_ttl=0 """ returncode, std_out, _ = self.run_redis_command("info keyspace") return returncode == 0 and len(std_out.strip().split("\n")) <= 1 def get_redis_used_memory(self) -> Optional[str]: """ Return amount of memmory used by user's redis instance in human readable format (kb or mb). If redis status is offline, 'used_memory_value' value is null. 'info memory' command output: # Memory used_memory:369616 used_memory_human:360.95K ... """ _, std_out, _ = self.run_redis_command("info memory") for line in std_out.split("\n"): if not line.startswith("used_memory_human"): continue _, used_memory_value = line.split(":") return used_memory_value if used_memory_value != "null" else None