| Server IP : 162.241.219.206 / Your IP : 216.73.216.195 Web Server : Apache System : Linux box5669.bluehost.com 5.14.0-687.15.1.el9_8.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jun 11 08:51:45 EDT 2026 x86_64 User : signavd5 ( 2863) PHP Version : 8.3.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /usr/libexec/kcare/python/kcarectl/ |
Upload File : |
# Copyright (c) Cloud Linux Software, Inc
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENCE.TXT
import functools
import json
import os
import time
from . import config, constants, log_utils, utils
from .py23 import json_loads_nstr
if False: # pragma: no cover
from typing import Any, Callable, Dict # noqa: F401
STATUS_CHANGE_GAP_DELAY = 5 * 60 # 5 minute
def touch_status_gap_file(filename='.kcarestatus'):
status_filepath = os.path.join(constants.PATCH_CACHE, filename)
utils.atomic_write(status_filepath, utils.timestamp_str())
def status_gap_passed(filename='.kcarestatus'):
status_filepath = os.path.join(constants.PATCH_CACHE, filename)
if os.path.isfile(status_filepath):
with open(status_filepath, 'r') as sfile:
try:
timestamp = int(sfile.read())
if int(timestamp) + config.STATUS_CHANGE_GAP + STATUS_CHANGE_GAP_DELAY > time.time():
return False
except Exception:
pass
return True
def _check_component(component):
# type: (str) -> None
if component not in ('kernel', 'libcare'):
raise ValueError('Unknown update status component: {0}'.format(component))
def _load_update_status():
# type: () -> Dict[str, Any]
content = utils.read_file(constants.UPDATE_STATUS_PATH)
if content is None:
return {}
try:
result = json_loads_nstr(content) # type: Dict[str, Any]
return result
except (ValueError, TypeError):
log_utils.kcarelog.warning('Failed to parse update status file')
return {}
def save_update_status(component, error):
# type: (str, str) -> None
_check_component(component)
try:
data = _load_update_status()
data[component] = {
'error': error,
'timestamp': int(time.time()),
}
utils.atomic_write(constants.UPDATE_STATUS_PATH, json.dumps(data))
except Exception:
log_utils.kcarelog.warning('Failed to save update status', exc_info=True)
def _error_status(err):
# type: (Exception) -> str
# Prefer the short, fixed status label that KcareError subclasses set
# (e.g. 'bad signature') for compact, groupable telemetry. When the status
# is already echoed in the message (HTTPError's "HTTP Error 414: ...") the
# message is the more useful value. When a numeric HTTP status is *not* in
# the message, compose a readable "HTTP Error: <code>" rather than a bare
# code. str() also keeps an int status subscriptable on read-back.
message = str(err)
status = str(getattr(err, 'status', ''))
if status and status not in message:
if status.isdigit():
return 'HTTP Error: {0}'.format(status)
return status
return message
def track_update_status(component):
# type: (str) -> Callable[..., Any]
_check_component(component)
def decorator(fn): # type: (Callable[..., Any]) -> Callable[..., Any]
@functools.wraps(fn)
def inner(*args, **kwargs): # type: (Any, Any) -> Any
try:
result = fn(*args, **kwargs)
except Exception as err:
save_update_status(component, error=_error_status(err))
raise
save_update_status(component, error='')
return result
return inner
return decorator
def read_update_error(component):
# type: (str) -> str
_check_component(component)
try:
data = _load_update_status()
# str() guards against status files written by older clients that
# persisted a non-string error (e.g. an int HTTP status like 414).
error = data.get(component, {}).get('error', '') # type: Any
return str(error)[: constants.UPDATE_ERROR_MAX_LENGTH]
except Exception:
log_utils.kcarelog.warning('Failed to read update status', exc_info=True)
return ''