# Copyright 2018, 2020-2023 VMware, Inc.
# All rights reserved. -- VMware Confidential

"""Utility module for interacting with the VMkernel Syslog service.
"""
import subprocess

from esxutils import EsxcliError, runCli
from vmware import runcommand

class ExecError(Exception):
   pass

class SyslogError(Exception):
   pass

def escapeRFC5424(string):
   """Escape special characters ", \, ] as per RFC 5424 specifications
      https://datatracker.ietf.org/doc/html/rfc5424#page-8
   """
   if string == None:
      return ''
   string = str(string)
   escapedString = ""
   specialChars = '"]\\'
   for char in string:
     if char in specialChars:
        escapedString += '\\'
     escapedString += char
   return escapedString

def execCommand(command, raiseException=True):
   """Execute a command with runcommand and return a tuple of
      (returnCode, stdout, stderr).
      Parameters:
         command        - the command string to run
         raiseException - whether to raise an ExecError when the command
                          returns non-zero status.
   """
   try:
      rc, stdout, stderr = runcommand.runcommand(command, redirectErr=False)
      stdout = stdout.decode()
      stderr = stderr.decode()
   except runcommand.RunCommandError as e:
      raise ExecError('%s failed to execute: %s' % (command, str(e)))

   if rc and raiseException:
      raise ExecError('%s returned non-zero status (%d), stderr: %s'
                      % (command, rc, stderr))

   return (rc, stdout, stderr)

def stopSyslog():
   """Shutdown syslog service.
   """
   VMSYSLOGD_SHUTDOWN_SH = '/usr/lib/vmware/vmsyslog/bin/shutdown.sh'
   try:
      # Ignore non-zero status when the daemon is already stopped
      execCommand(VMSYSLOGD_SHUTDOWN_SH, raiseException=False)
   except ExecError as e:
      raise SyslogError('Failed to stop syslog: %s' % str(e))

def startSyslog():
   """Start syslog service.
   """
   VMSYSLOGD_BIN = '/usr/lib/vmware/vmsyslog/bin/vmsyslogd'
   try:
      execCommand(VMSYSLOGD_BIN)
   except ExecError as e:
      raise SyslogError('Failed to start syslog: %s' % str(e))

def reloadSyslog():
   """Reload syslog configs.
   """
   SYSLOG_RELOAD_CMD = 'system syslog reload'
   try:
      runCli(SYSLOG_RELOAD_CMD.split())
   except EsxcliError as e:
      raise SyslogError('Failed to reload syslog: %s' % str(e))

def setSyslogLogDir(logPath, reloadService=True):
   """Set new logPath and reload syslog if requested.
   """
   SYSLOG_CONFIG_CMD = 'system syslog config set --logdir=%s'
   try:
      runCli((SYSLOG_CONFIG_CMD % logPath).split())
   except EsxcliError as e:
      raise SyslogError('Failed to set syslog logdir: %s' % str(e))
   if reloadService:
      reloadSyslog()

def resetSyslogLogDir(reloadService=True):
   """Reset logdir to factory default i.e. '/scratch/log' and reload
      syslog if requested.
   """
   SYSLOG_CONFIG_CMD = 'system syslog config set --reset=logdir'
   try:
      runCli(SYSLOG_CONFIG_CMD.split())
   except EsxcliError as e:
      raise SyslogError('Failed to reset syslog logdir: %s' % str(e))
   if reloadService:
      reloadSyslog()

