2020-12-16 17:25:24 +08:00

473 lines
16 KiB
Python

# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c) 2020 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
#############################################################################
from gspylib.inspection.common import SharedFuncs
import json
import imp
import types
from abc import abstractmethod
from gspylib.common.Common import DefaultValue
from gspylib.common.ErrorCode import ErrorCode
from gspylib.inspection.common.Log import LoggerFactory
from gspylib.inspection.common.CheckResult import LocalItemResult, \
ResultStatus
from gspylib.inspection.common.Exception import CheckNAException
def defaultAnalysis(self, itemResult):
# Get the item result information
itemResult.standard = self.standard
itemResult.suggestion = self.suggestion
itemResult.category = self.category
itemResult.title = self.title
errors = []
ngs = []
warnings = []
vals = {}
for i in itemResult.getLocalItems():
if (i.rst == ResultStatus.OK or i.rst == ResultStatus.NA):
if (i.val):
vals[i.host] = i.val
continue
elif (i.rst == ResultStatus.ERROR):
errors.append("%s : %s" % (i.host, i.val))
elif (i.rst == ResultStatus.WARNING):
warnings.append("%s : %s" % (i.host, i.val))
else:
ngs.append("%s : %s" % (i.host, i.val))
# Analysis results
if (len(ngs) > 0 or len(errors) > 0 or len(warnings) > 0):
rst = ResultStatus.WARNING
if len(errors) > 0:
rst = ResultStatus.ERROR
elif len(ngs) > 0:
rst = ResultStatus.NG
itemResult.rst = rst
itemResult.analysis = "\n".join(ngs + errors + warnings)
else:
itemResult.rst = ResultStatus.OK
itemResult.analysis = ""
analysisStrList = []
nas, oks, ngs, warnings, errors = classifyItemResult(itemResult)
total = len(oks) + len(ngs) + len(warnings) + len(errors)
rst = ResultStatus.OK
okMsg, okAnalysisList = countItemResult(oks)
warningMsg, warningAnalysisList = countItemResult(warnings)
failedMsg, failedAnalysisList = countItemResult(ngs)
errorMsg, errorAnalysisList = countItemResult(errors)
if (len(warnings) > 0):
rst = ResultStatus.WARNING
if (len(ngs) > 0):
rst = ResultStatus.NG
if (len(errors) > 0):
rst = ResultStatus.ERROR
countMsg = "The item run on %s nodes. %s%s%s%s" % (
total, okMsg, warningMsg, failedMsg, errorMsg)
analysisStrList.append(countMsg)
if (errorAnalysisList):
analysisStrList.extend(errorAnalysisList)
if (failedAnalysisList):
analysisStrList.extend(failedAnalysisList)
if (warningAnalysisList):
analysisStrList.extend(warningAnalysisList)
if (itemResult.name == 'CheckSysTable'):
value = [vals[key] for key in sorted(vals.keys())]
analysisStrList.extend(value)
itemResult.rst = rst
itemResult.analysis = "\n".join(analysisStrList)
return itemResult
def consistentAnalysis(self, itemResult):
# check the rst in each node and make sure the var is consistence
itemResult.standard = self.standard
itemResult.suggestion = self.suggestion
itemResult.category = self.category
itemResult.title = self.title
analysisStrList = []
nas, oks, ngs, warnings, errors = classifyItemResult(itemResult)
total = len(oks) + len(ngs) + len(warnings) + len(errors)
# The item run on %s nodes. success: %s warning: %s ng:%s error:%
rst = ResultStatus.OK
if (len(oks) == total):
okMsg, okAnalysisList = countItemResult(oks, True)
else:
okMsg, okAnalysisList = countItemResult(oks)
warningMsg, warningAnalysisList = countItemResult(warnings)
failedMsg, failedAnalysisList = countItemResult(ngs)
errorMsg, errorAnalysisList = countItemResult(errors)
if (len(okAnalysisList) > 0):
okMsg += " (consistent) " if (
len(okAnalysisList) == 1) else " (not consistent) "
if (len(warnings) > 0 and rst == ResultStatus.OK):
rst = ResultStatus.WARNING
if (len(okAnalysisList) > 1):
rst = ResultStatus.NG
if (itemResult.name in ["CheckDiskConfig", "CheckCpuCount",
"CheckMemInfo", "CheckStack",
"CheckKernelVer"]):
rst = ResultStatus.WARNING
if (len(ngs) > 0):
rst = ResultStatus.NG
if (len(errors) > 0):
rst = ResultStatus.ERROR
countMsg = "The item run on %s nodes. %s%s%s%s" % (
total, okMsg, warningMsg, failedMsg, errorMsg)
analysisStrList.append(countMsg)
if (errorAnalysisList):
analysisStrList.extend(errorAnalysisList)
if (failedAnalysisList):
analysisStrList.extend(failedAnalysisList)
if (warningAnalysisList):
analysisStrList.extend(warningAnalysisList)
if (okAnalysisList):
analysisStrList.extend(okAnalysisList)
itemResult.rst = rst
itemResult.analysis = "\n".join(analysisStrList)
return itemResult
def getValsItems(vals):
"""
:param vals:
:return:
"""
ret = {}
for i_key, i_val in list(vals.items()):
try:
i_val = eval(i_val)
except Exception:
i_val = i_val
if isinstance(i_val, dict):
for j_key, j_val in list(i_val.items()):
ret[j_key] = j_val
return ret
def getCheckType(category):
'''
function : get check type
input : category
output : 1,2,3
'''
if not category:
return 0
if category == "cluster":
return 1
elif category == "database":
return 3
else:
return 2
def classifyItemResult(itemResult):
nas = []
oks = []
ngs = []
wns = []
ers = []
# Summary results
for i in itemResult.getLocalItems():
if (i.rst == ResultStatus.OK):
oks.append(i)
if (i.rst == ResultStatus.NA):
nas.append(i)
if (i.rst == ResultStatus.NG):
ngs.append(i)
if (i.rst == ResultStatus.WARNING):
wns.append(i)
if (i.rst == ResultStatus.ERROR):
ers.append(i)
return (nas, oks, ngs, wns, ers)
def countItemResult(itemList, allNode=False):
if (itemList is None or len(itemList) == 0):
return ("", [])
first = itemList[0]
msgTitle = "default"
if (first.rst == ResultStatus.WARNING):
msgTitle = "warning"
if (first.rst == ResultStatus.NG):
msgTitle = "ng"
if (first.rst == ResultStatus.ERROR):
msgTitle = "error"
if (first.rst == ResultStatus.OK):
msgTitle = "success"
countMsg = " %s: %s " % (msgTitle, len(itemList))
defaultHosts = [first.host]
diffs = []
for i in itemList[1:]:
if i.val == first.val:
defaultHosts.append(i.host)
continue
else:
diffs.append("The different[%s] value:\n%s" % (i.host, i.val))
if (allNode):
analysisStrList = [
"The %s on all nodes value:\n%s" % (msgTitle, first.val)]
else:
analysisStrList = ["The %s%s value:\n%s" % (
msgTitle, '[' + ",".join(defaultHosts) + ']', first.val)]
if (len(diffs) > 0):
analysisStrList.extend(diffs)
return (countMsg, analysisStrList)
class BaseItem(object):
'''
base class of check item
'''
def __init__(self, name):
'''
Constructor
'''
self.name = name
self.title = None
self.set = False
self.log = None
self.suggestion = None
self.standard = None
self.threshold = {}
self.category = 'other'
self.permission = 'user'
self.analysis = 'default'
self.scope = 'all'
self.cluster = None
self.port = None
self.user = None
self.nodes = None
self.mpprcFile = None
self.thresholdDn = None
self.context = None
self.tmpPath = None
self.outPath = None
self.host = DefaultValue.GetHostIpOrName()
self.result = LocalItemResult(name, self.host)
self.routing = None
self.skipSetItem = []
self.ipAddr = None
# self cluster name not only lc
self.LCName = None
self.ShrinkNodes = None
@abstractmethod
def preCheck(self):
'''
abstract precheck for check item
'''
pass
@abstractmethod
def doCheck(self):
'''
check script for each item
'''
pass
@abstractmethod
def postAnalysis(self, itemResult, category="", name=""):
'''
analysis the item result got from each node
'''
pass
def initFrom(self, context):
'''
initialize the check item from context
'''
item = next(i for i in context.items if i['name'] == self.name)
if item:
self.title = self.__getLocaleAttr(item, 'title')
self.suggestion = self.__getLocaleAttr(item, 'suggestion')
self.standard = self.__getLocaleAttr(item, 'standard')
if (item.__contains__('threshold')):
self.category = item['category']
if (item.__contains__('threshold')):
self.threshold = item['threshold']
# set pre check method
self.setScope(item['scope'])
# set post analysis method
self.setAnalysis(item['analysis'])
self.context = context
self.cluster = context.cluster
self.user = context.user
self.nodes = context.nodes
self.mpprcFile = context.mpprc
self.result.checkID = context.checkID
self.result.user = context.user
self.tmpPath = context.tmpPath
self.outPath = context.outPath
self.set = context.set
self.log = context.log
self.routing = context.routing
self.skipSetItem = context.skipSetItem
self.__getLocalIP(context.nodes)
self.LCName = context.LCName
self.ShrinkNodes = context.ShrinkNodes
if not context.thresholdDn:
self.thresholdDn = 90
else:
self.thresholdDn = context.thresholdDn
# new host without cluster installed
if (not self.user):
self.host = DefaultValue.GetHostIpOrName()
self.result.host = DefaultValue.GetHostIpOrName()
def __getLocalIP(self, nodeList):
for node in nodeList:
if (SharedFuncs.is_local_node(node) and SharedFuncs.validate_ipv4(
node)):
self.ipAddr = node
return
def __getLocaleAttr(self, obj, attr, language='zh'):
'''
get attribute value for different language
'''
locAttr = str(attr) + '_' + language
if (not obj.__contains__(locAttr) or obj[locAttr] == ""):
return obj[str(attr) + '_' + 'zh']
else:
return obj[locAttr]
def setScope(self, scope):
# Choose execution node
self.scope = scope
# cn node to perform the check
if (scope == 'cn'):
self.preCheck = self.__cnPreCheck(self.preCheck)
# Local implementation of the inspection
elif (scope == 'local'):
self.preCheck = self.__localPreCheck(self.preCheck)
def setAnalysis(self, analysis):
# Analyze the test results
self.analysis = analysis
# Consistency analysis for ap
if (analysis == 'consistent'):
self.postAnalysis = types.MethodType(consistentAnalysis, self)
# Default analysis for ap
elif (analysis == 'default'):
self.postAnalysis = types.MethodType(defaultAnalysis, self)
def runCheck(self, context, g_logger):
'''
main process for checking
'''
try:
g_logger.debug("Start to run %s" % self.name)
# initialization
self.initFrom(context)
self.preCheck()
# Perform the inspection
self.doCheck()
if (self.set and (
self.result.rst == ResultStatus.NG
or self.result.rst == ResultStatus.WARNING)
and self.name not in self.skipSetItem):
self.doSet()
self.doCheck()
g_logger.debug("Finish to run %s" % self.name)
except CheckNAException:
self.result.rst = ResultStatus.NA
# An internal error occurred while executing code
except Exception as e:
self.result.rst = ResultStatus.ERROR
self.result.val = str(e)
g_logger.debug(
"Exception occur when running %s:\n%s" % (self.name, str(e)))
finally:
# output result
self.result.output(context.tmpPath)
def __cnPreCheck(self, func):
# cn Pre-check node
def wrapper():
if (not hasattr(self, 'cluster')):
raise Exception(ErrorCode.GAUSS_530["GAUSS_53030"]
% "cluster attribute")
if (not hasattr(self, 'host')):
raise Exception(ErrorCode.GAUSS_530["GAUSS_53030"]
% "host attribute")
if (not self.cluster):
raise Exception(ErrorCode.GAUSS_530["GAUSS_53031"])
dbNode = self.cluster.getDbNodeByName(self.host)
# The specified node does not exist or is empty
if (dbNode is None or dbNode == ""):
raise Exception(ErrorCode.GAUSS_530["GAUSS_53013"]
% "The dbNode")
if self.cluster.isSingleInstCluster():
masterDn = SharedFuncs.getMasterDnNum(self.user,
self.mpprcFile)
if len(dbNode.datanodes) < 1 or dbNode.datanodes[
0].instanceId not in masterDn:
raise CheckNAException(
"The node does not contains materDn instance")
self.port = dbNode.datanodes[0].port
else:
# The specified CN node does not exist
if (len(dbNode.coordinators) == 0):
raise CheckNAException(
"The node does not contains cn instance")
# get cn port
self.port = dbNode.coordinators[0].port
self.cntype = dbNode.coordinators[0].instanceType
return func()
return wrapper
def __localPreCheck(self, func):
def wrapper():
return func()
return wrapper
class CheckItemFactory(object):
@staticmethod
def createItem(name, path, scope='all', analysis='default'):
mod = imp.load_source(name, path)
clazz = getattr(mod, name)
checker = clazz()
# set pre check method
checker.setScope(scope)
# set post analysis method
checker.setAnalysis(analysis)
return checker
@staticmethod
def createFrom(name, path, context):
mod = imp.load_source(name, path)
clazz = getattr(mod, name)
checker = clazz()
checker.initFrom(context)
return checker