azext_edge/edge/providers/check/base/check_manager.py (93 lines of code) (raw):
# coding=utf-8
# ----------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License file in the project root for license information.
# ----------------------------------------------------------------------------------------------
from knack.log import get_logger
from typing import Any, Dict, List, Optional
from ..common import ALL_NAMESPACES_TARGET
from ....common import CheckTaskStatus
logger = get_logger(__name__)
class CheckManager:
"""
{
"name":"evaluateBrokerListeners",
"description": "Evaluate MQ broker listeners",
"status": "warning",
"targets": {
"mq.iotoperations.azure.com/v1": {
"_all_": {
"conditions": null,
"evaluations": [
{
"status": "success"
...
}
],
}
},
"brokerlisteners.mq.iotoperations.azure.com": {
"default": {
"displays": [],
"conditions": [
"len(brokerlisteners)>=1",
"spec",
"valid(spec.brokerRef)"
...
],
"evaluations": [
{
"name": "listener",
"kind": "brokerListener",
"value": {
"spec": { ... },
"valid(spec.brokerRef)": true
},
"status": "warning"
}
],
"status": "warning"
},
"other-namespace": {
"displays": [],
"conditions": []
...
}
}
}
}
"""
def __init__(self, check_name: str, check_desc: str):
self.check_name = check_name
self.check_desc = check_desc
self.targets = {}
self.target_displays = {}
self.worst_status = CheckTaskStatus.skipped.value
def add_target(
self,
target_name: str,
namespace: str = ALL_NAMESPACES_TARGET,
conditions: List[str] = None,
description: str = None,
) -> None:
# TODO: maybe make a singular taget into a class for consistent structure?
if target_name not in self.targets:
# Create a default `None` namespace target for targets with no namespace
self.targets[target_name] = {}
if namespace and namespace not in self.targets[target_name]:
self.targets[target_name][namespace] = {}
self.targets[target_name][namespace]["conditions"] = conditions
self.targets[target_name][namespace]["evaluations"] = []
self.targets[target_name][namespace]["status"] = CheckTaskStatus.skipped.value
if description:
self.targets[target_name][namespace]["description"] = description
def set_target_conditions(
self, target_name: str, conditions: List[str], namespace: str = ALL_NAMESPACES_TARGET
) -> None:
self.targets[target_name][namespace]["conditions"] = conditions
def add_target_conditions(
self, target_name: str, conditions: List[str], namespace: str = ALL_NAMESPACES_TARGET
) -> None:
if self.targets[target_name][namespace]["conditions"] is None:
self.targets[target_name][namespace]["conditions"] = []
self.targets[target_name][namespace]["conditions"].extend(conditions)
def set_target_status(self, target_name: str, status: str, namespace: str = ALL_NAMESPACES_TARGET) -> None:
self._process_status(target_name=target_name, namespace=namespace, status=status)
def add_target_eval(
self,
target_name: str,
status: str,
value: Optional[Any] = None,
namespace: str = ALL_NAMESPACES_TARGET,
resource_name: Optional[str] = None,
resource_kind: Optional[str] = None,
) -> None:
eval_dict = {"status": status}
if resource_name:
eval_dict["name"] = resource_name
if value:
eval_dict["value"] = value
if resource_kind:
eval_dict["kind"] = resource_kind
self.targets[target_name][namespace]["evaluations"].append(eval_dict)
self._process_status(target_name, status, namespace)
def _process_status(self, target_name: str, status: str, namespace: str = ALL_NAMESPACES_TARGET) -> None:
namespace_status = self.targets[target_name][namespace].get("status")
# success only overrides skipped status (default)
if status == CheckTaskStatus.success.value:
if namespace_status == CheckTaskStatus.skipped.value:
self.targets[target_name][namespace]["status"] = status
if self.worst_status == CheckTaskStatus.skipped.value:
self.worst_status = status
# warning overrides any state that is not "error"
elif status == CheckTaskStatus.warning.value:
if namespace_status != CheckTaskStatus.error.value:
self.targets[target_name][namespace]["status"] = status
if self.worst_status != CheckTaskStatus.error.value:
self.worst_status = status
# error overrides any state
elif status == CheckTaskStatus.error.value:
self.targets[target_name][namespace]["status"] = status
self.worst_status = status
def add_display(self, target_name: str, display: Any, namespace: str = ALL_NAMESPACES_TARGET) -> None:
if target_name not in self.target_displays:
self.target_displays[target_name] = {}
if namespace not in self.target_displays[target_name]:
self.target_displays[target_name][namespace] = []
self.target_displays[target_name][namespace].append(display)
def as_dict(self, as_list: bool = False) -> Dict[str, Any]:
from copy import deepcopy
result = {
"name": self.check_name,
"description": self.check_desc,
"targets": {},
"status": self.worst_status,
}
result["targets"] = deepcopy(self.targets)
if as_list:
for type in self.target_displays:
for namespace in self.target_displays[type]:
result["targets"][type][namespace]["displays"] = deepcopy(self.target_displays[type][namespace])
return result