#1355 - Carried out full renaming in node.py, active_node.py, passive_node.py, and service_node.py to make params and variable names explicit.
- Made the same renaming in the yaml laydown config files. - Added Type hints wherever I've been. - Added a custom NodeType in custom_typing.py to encompass the Union of ActiveNode, PassiveNode, ServiceNode.
This commit is contained in:
@@ -3,7 +3,14 @@
|
||||
import logging
|
||||
from typing import Final
|
||||
|
||||
from primaite.common.enums import FILE_SYSTEM_STATE, HARDWARE_STATE, SOFTWARE_STATE
|
||||
from primaite.common.config_values_main import ConfigValuesMain
|
||||
from primaite.common.enums import (
|
||||
FileSystemState,
|
||||
HardwareState,
|
||||
NodeType,
|
||||
Priority,
|
||||
SoftwareState,
|
||||
)
|
||||
from primaite.nodes.node import Node
|
||||
|
||||
_LOGGER: Final[logging.Logger] = logging.getLogger(__name__)
|
||||
@@ -14,216 +21,174 @@ class ActiveNode(Node):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
_id,
|
||||
_name,
|
||||
_type,
|
||||
_priority,
|
||||
_state,
|
||||
_ip_address,
|
||||
_os_state,
|
||||
_file_system_state,
|
||||
_config_values,
|
||||
node_id: str,
|
||||
name: str,
|
||||
node_type: NodeType,
|
||||
priority: Priority,
|
||||
hardware_state: HardwareState,
|
||||
ip_address: str,
|
||||
software_state: SoftwareState,
|
||||
file_system_state: FileSystemState,
|
||||
config_values: ConfigValuesMain,
|
||||
):
|
||||
"""
|
||||
Init.
|
||||
|
||||
Args:
|
||||
_id: The node ID
|
||||
_name: The node name
|
||||
_type: The node type (enum)
|
||||
_priority: The node priority (enum)
|
||||
_state: The node state (enum)
|
||||
_ip_address: The node IP address
|
||||
_os_state: The node Operating System state
|
||||
_file_system_state: The node file system state
|
||||
_config_values: The config values
|
||||
:param node_id: The node ID
|
||||
:param name: The node name
|
||||
:param node_type: The node type (enum)
|
||||
:param priority: The node priority (enum)
|
||||
:param hardware_state: The node Hardware State
|
||||
:param ip_address: The node IP address
|
||||
:param software_state: The node Software State
|
||||
:param file_system_state: The node file system state
|
||||
:param config_values: The config values
|
||||
"""
|
||||
super().__init__(_id, _name, _type, _priority, _state, _config_values)
|
||||
self.ip_address = _ip_address
|
||||
# Related to O/S
|
||||
self.os_state = _os_state
|
||||
self.patching_count = 0
|
||||
super().__init__(
|
||||
node_id, name, node_type, priority, hardware_state, config_values
|
||||
)
|
||||
self.ip_address: str = ip_address
|
||||
# Related to Software
|
||||
self._software_state: SoftwareState = software_state
|
||||
self.patching_count: int = 0
|
||||
# Related to File System
|
||||
self.file_system_state_actual = _file_system_state
|
||||
self.file_system_state_observed = _file_system_state
|
||||
self.file_system_scanning = False
|
||||
self.file_system_scanning_count = 0
|
||||
self.file_system_action_count = 0
|
||||
self.file_system_state_actual: FileSystemState = file_system_state
|
||||
self.file_system_state_observed: FileSystemState = file_system_state
|
||||
self.file_system_scanning: bool = False
|
||||
self.file_system_scanning_count: int = 0
|
||||
self.file_system_action_count: int = 0
|
||||
|
||||
def set_ip_address(self, _ip_address):
|
||||
@property
|
||||
def software_state(self) -> SoftwareState:
|
||||
"""
|
||||
Sets IP address.
|
||||
Get the software_state.
|
||||
|
||||
Args:
|
||||
_ip_address: IP address
|
||||
:return: The software_state.
|
||||
"""
|
||||
self.ip_address = _ip_address
|
||||
return self._software_state
|
||||
|
||||
def get_ip_address(self):
|
||||
@software_state.setter
|
||||
def software_state(self, software_state: SoftwareState):
|
||||
"""
|
||||
Gets IP address.
|
||||
Get the software_state.
|
||||
|
||||
Returns:
|
||||
IP address
|
||||
:param software_state: Software State.
|
||||
"""
|
||||
return self.ip_address
|
||||
|
||||
def set_os_state(self, _os_state):
|
||||
"""
|
||||
Sets operating system state.
|
||||
|
||||
Args:
|
||||
_os_state: Operating system state
|
||||
"""
|
||||
if self.operating_state != HARDWARE_STATE.OFF:
|
||||
self.os_state = _os_state
|
||||
if _os_state == SOFTWARE_STATE.PATCHING:
|
||||
if self.hardware_state != HardwareState.OFF:
|
||||
self._software_state = software_state
|
||||
if software_state == SoftwareState.PATCHING:
|
||||
self.patching_count = self.config_values.os_patching_duration
|
||||
else:
|
||||
_LOGGER.info(
|
||||
f"The Nodes operating state is OFF so OS State cannot be "
|
||||
f"The Nodes hardware state is OFF so OS State cannot be "
|
||||
f"changed. "
|
||||
f"Node:{self.id}, "
|
||||
f"Node Operating State:{self.operating_state}, "
|
||||
f"Node Operating System State:{self.os_state}"
|
||||
f"Node.node_id:{self.node_id}, "
|
||||
f"Node.hardware_state:{self.hardware_state}, "
|
||||
f"Node.software_state:{self._software_state}"
|
||||
)
|
||||
|
||||
def set_os_state_if_not_compromised(self, _os_state):
|
||||
def set_software_state_if_not_compromised(self, software_state: SoftwareState):
|
||||
"""
|
||||
Sets operating system state if the node is not compromised.
|
||||
Sets Software State if the node is not compromised.
|
||||
|
||||
Args:
|
||||
_os_state: Operating system state
|
||||
software_state: Software State
|
||||
"""
|
||||
if self.operating_state != HARDWARE_STATE.OFF:
|
||||
if self.os_state != SOFTWARE_STATE.COMPROMISED:
|
||||
self.os_state = _os_state
|
||||
if _os_state == SOFTWARE_STATE.PATCHING:
|
||||
if self.hardware_state != HardwareState.OFF:
|
||||
if self._software_state != SoftwareState.COMPROMISED:
|
||||
self._software_state = software_state
|
||||
if software_state == SoftwareState.PATCHING:
|
||||
self.patching_count = self.config_values.os_patching_duration
|
||||
else:
|
||||
_LOGGER.info(
|
||||
f"The Nodes operating state is OFF so OS State cannot be changed."
|
||||
f"Node:{self.id}, "
|
||||
f"Node Operating State:{self.operating_state}, "
|
||||
f"Node Operating System State:{self.os_state}",
|
||||
f"The Nodes hardware state is OFF so OS State cannot be changed."
|
||||
f"Node.node_id:{self.node_id}, "
|
||||
f"Node.hardware_state:{self.hardware_state}, "
|
||||
f"Node.software_state:{self._software_state}"
|
||||
)
|
||||
|
||||
def get_os_state(self):
|
||||
"""
|
||||
Gets operating system state.
|
||||
|
||||
Returns:
|
||||
Operating system state
|
||||
"""
|
||||
return self.os_state
|
||||
|
||||
def update_os_patching_status(self):
|
||||
"""Updates operating system status based on patching cycle."""
|
||||
self.patching_count -= 1
|
||||
if self.patching_count <= 0:
|
||||
self.patching_count = 0
|
||||
self.os_state = SOFTWARE_STATE.GOOD
|
||||
self._software_state = SoftwareState.GOOD
|
||||
|
||||
def set_file_system_state(self, _file_system_state):
|
||||
def set_file_system_state(self, file_system_state: FileSystemState):
|
||||
"""
|
||||
Sets the file system state (actual and observed).
|
||||
|
||||
Args:
|
||||
_file_system_state: File system state
|
||||
file_system_state: File system state
|
||||
"""
|
||||
if self.operating_state != HARDWARE_STATE.OFF:
|
||||
self.file_system_state_actual = _file_system_state
|
||||
if self.hardware_state != HardwareState.OFF:
|
||||
self.file_system_state_actual = file_system_state
|
||||
|
||||
if _file_system_state == FILE_SYSTEM_STATE.REPAIRING:
|
||||
if file_system_state == FileSystemState.REPAIRING:
|
||||
self.file_system_action_count = (
|
||||
self.config_values.file_system_repairing_limit
|
||||
)
|
||||
self.file_system_state_observed = FILE_SYSTEM_STATE.REPAIRING
|
||||
elif _file_system_state == FILE_SYSTEM_STATE.RESTORING:
|
||||
self.file_system_state_observed = FileSystemState.REPAIRING
|
||||
elif file_system_state == FileSystemState.RESTORING:
|
||||
self.file_system_action_count = (
|
||||
self.config_values.file_system_restoring_limit
|
||||
)
|
||||
self.file_system_state_observed = FILE_SYSTEM_STATE.RESTORING
|
||||
elif _file_system_state == FILE_SYSTEM_STATE.GOOD:
|
||||
self.file_system_state_observed = FILE_SYSTEM_STATE.GOOD
|
||||
self.file_system_state_observed = FileSystemState.RESTORING
|
||||
elif file_system_state == FileSystemState.GOOD:
|
||||
self.file_system_state_observed = FileSystemState.GOOD
|
||||
else:
|
||||
_LOGGER.info(
|
||||
f"The Nodes operating state is OFF so File System State "
|
||||
f"The Nodes hardware state is OFF so File System State "
|
||||
f"cannot be changed. "
|
||||
f"Node:{self.id}, "
|
||||
f"Node Operating State:{self.operating_state}, "
|
||||
f"Node File System State:{self.file_system_state_actual}",
|
||||
f"Node.node_id:{self.node_id}, "
|
||||
f"Node.hardware_state:{self.hardware_state}, "
|
||||
f"Node.file_system_state.actual:{self.file_system_state_actual}"
|
||||
)
|
||||
|
||||
def set_file_system_state_if_not_compromised(self, _file_system_state):
|
||||
def set_file_system_state_if_not_compromised(
|
||||
self, file_system_state: FileSystemState
|
||||
):
|
||||
"""
|
||||
Sets the file system state (actual and observed) if not in a compromised state.
|
||||
|
||||
Use for green PoL to prevent it overturning a compromised state
|
||||
|
||||
Args:
|
||||
_file_system_state: File system state
|
||||
file_system_state: File system state
|
||||
"""
|
||||
if self.operating_state != HARDWARE_STATE.OFF:
|
||||
if self.hardware_state != HardwareState.OFF:
|
||||
if (
|
||||
self.file_system_state_actual != FILE_SYSTEM_STATE.CORRUPT
|
||||
and self.file_system_state_actual != FILE_SYSTEM_STATE.DESTROYED
|
||||
self.file_system_state_actual != FileSystemState.CORRUPT
|
||||
and self.file_system_state_actual != FileSystemState.DESTROYED
|
||||
):
|
||||
self.file_system_state_actual = _file_system_state
|
||||
self.file_system_state_actual = file_system_state
|
||||
|
||||
if _file_system_state == FILE_SYSTEM_STATE.REPAIRING:
|
||||
if file_system_state == FileSystemState.REPAIRING:
|
||||
self.file_system_action_count = (
|
||||
self.config_values.file_system_repairing_limit
|
||||
)
|
||||
self.file_system_state_observed = FILE_SYSTEM_STATE.REPAIRING
|
||||
elif _file_system_state == FILE_SYSTEM_STATE.RESTORING:
|
||||
self.file_system_state_observed = FileSystemState.REPAIRING
|
||||
elif file_system_state == FileSystemState.RESTORING:
|
||||
self.file_system_action_count = (
|
||||
self.config_values.file_system_restoring_limit
|
||||
)
|
||||
self.file_system_state_observed = FILE_SYSTEM_STATE.RESTORING
|
||||
elif _file_system_state == FILE_SYSTEM_STATE.GOOD:
|
||||
self.file_system_state_observed = FILE_SYSTEM_STATE.GOOD
|
||||
self.file_system_state_observed = FileSystemState.RESTORING
|
||||
elif file_system_state == FileSystemState.GOOD:
|
||||
self.file_system_state_observed = FileSystemState.GOOD
|
||||
else:
|
||||
_LOGGER.info(
|
||||
f"The Nodes operating state is OFF so File System State (if not "
|
||||
f"The Nodes hardware state is OFF so File System State (if not "
|
||||
f"compromised) cannot be changed. "
|
||||
f"Node:{self.id}, "
|
||||
f"Node Operating State:{self.operating_state}, "
|
||||
f"Node File System State:{self.file_system_state_actual}",
|
||||
f"Node.node_id:{self.node_id}, "
|
||||
f"Node.hardware_state:{self.hardware_state}, "
|
||||
f"Node.file_system_state.actual:{self.file_system_state_actual}"
|
||||
)
|
||||
|
||||
def get_file_system_state_actual(self):
|
||||
"""
|
||||
Gets file system state (actual).
|
||||
|
||||
Returns:
|
||||
File system state (actual)
|
||||
"""
|
||||
return self.file_system_state_actual
|
||||
|
||||
def get_file_system_state_observed(self):
|
||||
"""
|
||||
Gets file system state (observed).
|
||||
|
||||
Returns:
|
||||
File system state (observed)
|
||||
"""
|
||||
return self.file_system_state_observed
|
||||
|
||||
def start_file_system_scan(self):
|
||||
"""Starts a file system scan."""
|
||||
self.file_system_scanning = True
|
||||
self.file_system_scanning_count = self.config_values.file_system_scanning_limit
|
||||
|
||||
def is_scanning_file_system(self):
|
||||
"""
|
||||
Gets true/false on whether file system is being scanned.
|
||||
|
||||
Returns:
|
||||
True if file system is being scanned
|
||||
"""
|
||||
return self.file_system_scanning
|
||||
|
||||
def update_file_system_state(self):
|
||||
"""Updates file system status based on scanning/restore/repair cycle."""
|
||||
# Deprecate both the action count (for restoring or reparing) and the scanning count
|
||||
@@ -234,11 +199,11 @@ class ActiveNode(Node):
|
||||
if self.file_system_action_count <= 0:
|
||||
self.file_system_action_count = 0
|
||||
if (
|
||||
self.file_system_state_actual == FILE_SYSTEM_STATE.REPAIRING
|
||||
or self.file_system_state_actual == FILE_SYSTEM_STATE.RESTORING
|
||||
self.file_system_state_actual == FileSystemState.REPAIRING
|
||||
or self.file_system_state_actual == FileSystemState.RESTORING
|
||||
):
|
||||
self.file_system_state_actual = FILE_SYSTEM_STATE.GOOD
|
||||
self.file_system_state_observed = FILE_SYSTEM_STATE.GOOD
|
||||
self.file_system_state_actual = FileSystemState.GOOD
|
||||
self.file_system_state_observed = FileSystemState.GOOD
|
||||
|
||||
# Scanning updates
|
||||
if self.file_system_scanning == True and self.file_system_scanning_count < 0:
|
||||
|
||||
@@ -1,135 +1,56 @@
|
||||
# Crown Copyright (C) Dstl 2022. DEFCON 703. Shared in confidence.
|
||||
"""The base Node class."""
|
||||
from primaite.common.enums import HARDWARE_STATE
|
||||
from typing import Final
|
||||
|
||||
from primaite.common.config_values_main import ConfigValuesMain
|
||||
from primaite.common.enums import HardwareState, NodeType, Priority
|
||||
|
||||
|
||||
class Node:
|
||||
"""Node class."""
|
||||
|
||||
def __init__(self, _id, _name, _type, _priority, _state, _config_values):
|
||||
def __init__(
|
||||
self,
|
||||
node_id: str,
|
||||
name: str,
|
||||
node_type: NodeType,
|
||||
priority: Priority,
|
||||
hardware_state: HardwareState,
|
||||
config_values: ConfigValuesMain,
|
||||
):
|
||||
"""
|
||||
Init.
|
||||
|
||||
Args:
|
||||
_id: The node id
|
||||
_name: The name of the node
|
||||
_type: The type of the node
|
||||
_priority: The priority of the node
|
||||
_state: The state of the node
|
||||
:param node_id: The node id.
|
||||
:param name: The name of the node.
|
||||
:param node_type: The type of the node.
|
||||
:param priority: The priority of the node.
|
||||
:param hardware_state: The state of the node.
|
||||
:param config_values: Config values.
|
||||
"""
|
||||
self.id = _id
|
||||
self.name = _name
|
||||
self.type = _type
|
||||
self.priority = _priority
|
||||
self.operating_state = _state
|
||||
self.resetting_count = 0
|
||||
self.config_values = _config_values
|
||||
self.node_id: Final[str] = node_id
|
||||
self.name: Final[str] = name
|
||||
self.node_type: Final[NodeType] = node_type
|
||||
self.priority = priority
|
||||
self.hardware_state: HardwareState = hardware_state
|
||||
self.resetting_count: int = 0
|
||||
self.config_values: ConfigValuesMain = config_values
|
||||
|
||||
def __repr__(self):
|
||||
"""Returns the name of the node."""
|
||||
return self.name
|
||||
|
||||
def set_id(self, _id):
|
||||
"""
|
||||
Sets the node ID.
|
||||
|
||||
Args:
|
||||
_id: The node ID
|
||||
"""
|
||||
self.id = _id
|
||||
|
||||
def get_id(self):
|
||||
"""
|
||||
Gets the node ID.
|
||||
|
||||
Returns:
|
||||
The node ID
|
||||
"""
|
||||
return self.id
|
||||
|
||||
def set_name(self, _name):
|
||||
"""
|
||||
Sets the node name.
|
||||
|
||||
Args:
|
||||
_name: The node name
|
||||
"""
|
||||
self.name = _name
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Gets the node name.
|
||||
|
||||
Returns:
|
||||
The node name
|
||||
"""
|
||||
return self.name
|
||||
|
||||
def set_type(self, _type):
|
||||
"""
|
||||
Sets the node type.
|
||||
|
||||
Args:
|
||||
_type: The node type
|
||||
"""
|
||||
self.type = _type
|
||||
|
||||
def get_type(self):
|
||||
"""
|
||||
Gets the node type.
|
||||
|
||||
Returns:
|
||||
The node type
|
||||
"""
|
||||
return self.type
|
||||
|
||||
def set_priority(self, _priority):
|
||||
"""
|
||||
Sets the node priority.
|
||||
|
||||
Args:
|
||||
_priority: The node priority
|
||||
"""
|
||||
self.priority = _priority
|
||||
|
||||
def get_priority(self):
|
||||
"""
|
||||
Gets the node priority.
|
||||
|
||||
Returns:
|
||||
The node priority
|
||||
"""
|
||||
return self.priority
|
||||
|
||||
def set_state(self, _state):
|
||||
"""
|
||||
Sets the node state.
|
||||
|
||||
Args:
|
||||
_state: The node state
|
||||
"""
|
||||
self.operating_state = _state
|
||||
|
||||
def get_state(self):
|
||||
"""
|
||||
Gets the node operating state.
|
||||
|
||||
Returns:
|
||||
The node operating state
|
||||
"""
|
||||
return self.operating_state
|
||||
|
||||
def turn_on(self):
|
||||
"""Sets the node state to ON."""
|
||||
self.operating_state = HARDWARE_STATE.ON
|
||||
self.hardware_state = HardwareState.ON
|
||||
|
||||
def turn_off(self):
|
||||
"""Sets the node state to OFF."""
|
||||
self.operating_state = HARDWARE_STATE.OFF
|
||||
self.hardware_state = HardwareState.OFF
|
||||
|
||||
def reset(self):
|
||||
"""Sets the node state to Resetting and starts the reset count."""
|
||||
self.operating_state = HARDWARE_STATE.RESETTING
|
||||
self.hardware_state = HardwareState.RESETTING
|
||||
self.resetting_count = self.config_values.node_reset_duration
|
||||
|
||||
def update_resetting_status(self):
|
||||
@@ -137,4 +58,4 @@ class Node:
|
||||
self.resetting_count -= 1
|
||||
if self.resetting_count <= 0:
|
||||
self.resetting_count = 0
|
||||
self.operating_state = HARDWARE_STATE.ON
|
||||
self.hardware_state = HardwareState.ON
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Crown Copyright (C) Dstl 2022. DEFCON 703. Shared in confidence.
|
||||
"""Defines node behaviour for Green PoL."""
|
||||
from primaite.common.enums import NodePOLType
|
||||
|
||||
|
||||
class NodeStateInstructionRed(object):
|
||||
@@ -12,7 +13,7 @@ class NodeStateInstructionRed(object):
|
||||
_end_step,
|
||||
_target_node_id,
|
||||
_pol_initiator,
|
||||
_pol_type,
|
||||
_pol_type: NodePOLType,
|
||||
pol_protocol,
|
||||
_pol_state,
|
||||
_pol_source_node_id,
|
||||
@@ -40,7 +41,7 @@ class NodeStateInstructionRed(object):
|
||||
self.end_step = _end_step
|
||||
self.target_node_id = _target_node_id
|
||||
self.initiator = _pol_initiator
|
||||
self.pol_type = _pol_type
|
||||
self.pol_type: NodePOLType = _pol_type
|
||||
self.service_name = pol_protocol # Not used when not a service instruction
|
||||
self.state = _pol_state
|
||||
self.source_node_id = _pol_source_node_id
|
||||
@@ -83,7 +84,7 @@ class NodeStateInstructionRed(object):
|
||||
"""
|
||||
return self.initiator
|
||||
|
||||
def get_pol_type(self):
|
||||
def get_pol_type(self) -> NodePOLType:
|
||||
"""
|
||||
Gets the node pattern of life type (enum).
|
||||
|
||||
|
||||
@@ -1,32 +1,44 @@
|
||||
# Crown Copyright (C) Dstl 2022. DEFCON 703. Shared in confidence.
|
||||
"""The Passive Node class (i.e. an actuator)."""
|
||||
|
||||
from primaite.common.config_values_main import ConfigValuesMain
|
||||
from primaite.common.enums import HardwareState, NodeType, Priority
|
||||
from primaite.nodes.node import Node
|
||||
|
||||
|
||||
class PassiveNode(Node):
|
||||
"""The Passive Node class."""
|
||||
|
||||
def __init__(self, _id, _name, _type, _priority, _state, _config_values):
|
||||
def __init__(
|
||||
self,
|
||||
node_id: str,
|
||||
name: str,
|
||||
node_type: NodeType,
|
||||
priority: Priority,
|
||||
hardware_state: HardwareState,
|
||||
config_values: ConfigValuesMain,
|
||||
):
|
||||
"""
|
||||
Init.
|
||||
|
||||
Args:
|
||||
_id: The node id
|
||||
_name: The name of the node
|
||||
_type: The type of the node
|
||||
_priority: The priority of the node
|
||||
_state: The state of the node
|
||||
:param node_id: The node id.
|
||||
:param name: The name of the node.
|
||||
:param node_type: The type of the node.
|
||||
:param priority: The priority of the node.
|
||||
:param hardware_state: The state of the node.
|
||||
:param config_values: Config values.
|
||||
"""
|
||||
# Pass through to Super for now
|
||||
super().__init__(_id, _name, _type, _priority, _state, _config_values)
|
||||
super().__init__(
|
||||
node_id, name, node_type, priority, hardware_state, config_values
|
||||
)
|
||||
|
||||
def get_ip_address(self):
|
||||
@property
|
||||
def ip_address(self) -> str:
|
||||
"""
|
||||
Gets the node IP address.
|
||||
Gets the node IP address as an empty string.
|
||||
|
||||
Returns:
|
||||
The node IP address
|
||||
No concept of IP address for passive nodes for now.
|
||||
|
||||
:return: The node IP address.
|
||||
"""
|
||||
# No concept of IP address for passive nodes for now
|
||||
return ""
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
# Crown Copyright (C) Dstl 2022. DEFCON 703. Shared in confidence.
|
||||
"""A Service Node (i.e. not an actuator)."""
|
||||
import logging
|
||||
from typing import Final
|
||||
from typing import Dict, Final
|
||||
|
||||
from primaite.common.enums import HARDWARE_STATE, SOFTWARE_STATE
|
||||
from primaite.common.config_values_main import ConfigValuesMain
|
||||
from primaite.common.enums import (
|
||||
FileSystemState,
|
||||
HardwareState,
|
||||
NodeType,
|
||||
Priority,
|
||||
SoftwareState,
|
||||
)
|
||||
from primaite.common.service import Service
|
||||
from primaite.nodes.active_node import ActiveNode
|
||||
|
||||
_LOGGER: Final[logging.Logger] = logging.getLogger(__name__)
|
||||
@@ -14,185 +22,169 @@ class ServiceNode(ActiveNode):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
_id,
|
||||
_name,
|
||||
_type,
|
||||
_priority,
|
||||
_state,
|
||||
_ip_address,
|
||||
_os_state,
|
||||
_file_system_state,
|
||||
_config_values,
|
||||
node_id: str,
|
||||
name: str,
|
||||
node_type: NodeType,
|
||||
priority: Priority,
|
||||
hardware_state: HardwareState,
|
||||
ip_address: str,
|
||||
software_state: SoftwareState,
|
||||
file_system_state: FileSystemState,
|
||||
config_values: ConfigValuesMain,
|
||||
):
|
||||
"""
|
||||
Init.
|
||||
|
||||
Args:
|
||||
_id: The node id
|
||||
_name: The name of the node
|
||||
_type: The type of the node
|
||||
_priority: The priority of the node
|
||||
_state: The state of the node
|
||||
_ipAddress: The IP address of the node
|
||||
_osState: The operating system state of the node
|
||||
_file_system_state: The file system state of the node
|
||||
:param node_id: The node ID
|
||||
:param name: The node name
|
||||
:param node_type: The node type (enum)
|
||||
:param priority: The node priority (enum)
|
||||
:param hardware_state: The node Hardware State
|
||||
:param ip_address: The node IP address
|
||||
:param software_state: The node Software State
|
||||
:param file_system_state: The node file system state
|
||||
:param config_values: The config values
|
||||
"""
|
||||
super().__init__(
|
||||
_id,
|
||||
_name,
|
||||
_type,
|
||||
_priority,
|
||||
_state,
|
||||
_ip_address,
|
||||
_os_state,
|
||||
_file_system_state,
|
||||
_config_values,
|
||||
node_id,
|
||||
name,
|
||||
node_type,
|
||||
priority,
|
||||
hardware_state,
|
||||
ip_address,
|
||||
software_state,
|
||||
file_system_state,
|
||||
config_values,
|
||||
)
|
||||
self.services = {}
|
||||
self.services: Dict[str, Service] = {}
|
||||
|
||||
def add_service(self, _service):
|
||||
def add_service(self, service: Service):
|
||||
"""
|
||||
Adds a service to the node.
|
||||
|
||||
Args:
|
||||
_service: The service to add
|
||||
:param service: The service to add
|
||||
"""
|
||||
self.services[_service.get_name()] = _service
|
||||
self.services[service.name] = service
|
||||
|
||||
def get_services(self):
|
||||
"""
|
||||
Gets the dictionary of services on this node.
|
||||
|
||||
Returns:
|
||||
Dictionary of services on this node
|
||||
"""
|
||||
return self.services
|
||||
|
||||
def has_service(self, _protocol):
|
||||
def has_service(self, protocol_name: str) -> bool:
|
||||
"""
|
||||
Indicates whether a service is on a node.
|
||||
|
||||
Returns:
|
||||
True if service (protocol) is on the node
|
||||
:param protocol_name: The service (protocol)e.
|
||||
:return: True if service (protocol) is on the node, otherwise False.
|
||||
"""
|
||||
for service_key, service_value in self.services.items():
|
||||
if service_key == _protocol:
|
||||
if service_key == protocol_name:
|
||||
return True
|
||||
else:
|
||||
pass
|
||||
return False
|
||||
|
||||
def service_running(self, _protocol):
|
||||
def service_running(self, protocol_name: str) -> bool:
|
||||
"""
|
||||
Indicates whether a service is in a running state on the node.
|
||||
|
||||
Returns:
|
||||
True if service (protocol) is in a running state on the node
|
||||
:param protocol_name: The service (protocol)
|
||||
:return: True if service (protocol) is in a running state on the
|
||||
node, otherwise False.
|
||||
"""
|
||||
for service_key, service_value in self.services.items():
|
||||
if service_key == _protocol:
|
||||
if service_value.get_state() != SOFTWARE_STATE.PATCHING:
|
||||
if service_key == protocol_name:
|
||||
if service_value.software_state != SoftwareState.PATCHING:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
pass
|
||||
return False
|
||||
|
||||
def service_is_overwhelmed(self, _protocol):
|
||||
def service_is_overwhelmed(self, protocol_name: str) -> bool:
|
||||
"""
|
||||
Indicates whether a service is in an overwhelmed state on the node.
|
||||
|
||||
Returns:
|
||||
True if service (protocol) is in an overwhelmed state on the node
|
||||
:param protocol_name: The service (protocol)
|
||||
:return: True if service (protocol) is in an overwhelmed state on the
|
||||
node, otherwise False.
|
||||
"""
|
||||
for service_key, service_value in self.services.items():
|
||||
if service_key == _protocol:
|
||||
if service_value.get_state() == SOFTWARE_STATE.OVERWHELMED:
|
||||
if service_key == protocol_name:
|
||||
if service_value.software_state == SoftwareState.OVERWHELMED:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
pass
|
||||
return False
|
||||
|
||||
def set_service_state(self, _protocol, _state):
|
||||
def set_service_state(self, protocol_name: str, software_state: SoftwareState):
|
||||
"""
|
||||
Sets the state of a service (protocol) on the node.
|
||||
Sets the software_state of a service (protocol) on the node.
|
||||
|
||||
Args:
|
||||
_protocol: The service (protocol)
|
||||
_state: The state value
|
||||
:param protocol_name: The service (protocol).
|
||||
:param software_state: The software_state.
|
||||
"""
|
||||
if self.operating_state != HARDWARE_STATE.OFF:
|
||||
for service_key, service_value in self.services.items():
|
||||
if service_key == _protocol:
|
||||
# Can't set to compromised if you're in a patching state
|
||||
if (
|
||||
_state == SOFTWARE_STATE.COMPROMISED
|
||||
and service_value.get_state() != SOFTWARE_STATE.PATCHING
|
||||
) or _state != SOFTWARE_STATE.COMPROMISED:
|
||||
service_value.set_state(_state)
|
||||
else:
|
||||
# Do nothing
|
||||
pass
|
||||
if _state == SOFTWARE_STATE.PATCHING:
|
||||
if self.hardware_state != HardwareState.OFF:
|
||||
service_key = protocol_name
|
||||
service_value = self.services.get(service_key)
|
||||
if service_value:
|
||||
# Can't set to compromised if you're in a patching state
|
||||
if (
|
||||
software_state == SoftwareState.COMPROMISED
|
||||
and service_value.software_state != SoftwareState.PATCHING
|
||||
) or software_state != SoftwareState.COMPROMISED:
|
||||
service_value.software_state = software_state
|
||||
if software_state == SoftwareState.PATCHING:
|
||||
service_value.patching_count = (
|
||||
self.config_values.service_patching_duration
|
||||
)
|
||||
else:
|
||||
_LOGGER.info(
|
||||
f"The Nodes hardware state is OFF so the state of a service "
|
||||
f"cannot be changed. "
|
||||
f"Node.node_id:{self.node_id}, "
|
||||
f"Node.hardware_state:{self.hardware_state}, "
|
||||
f"Node.services[<key>]:{protocol_name}, "
|
||||
f"Node.services[<key>].software_state:{software_state}"
|
||||
)
|
||||
|
||||
def set_service_state_if_not_compromised(
|
||||
self, protocol_name: str, software_state: SoftwareState
|
||||
):
|
||||
"""
|
||||
Sets the software_state of a service (protocol) on the node.
|
||||
|
||||
Done if the software_state is not "compromised".
|
||||
|
||||
:param protocol_name: The service (protocol).
|
||||
:param software_state: The software_state.
|
||||
"""
|
||||
if self.hardware_state != HardwareState.OFF:
|
||||
service_key = protocol_name
|
||||
service_value = self.services.get(service_key)
|
||||
if service_value:
|
||||
if service_value.software_state != SoftwareState.COMPROMISED:
|
||||
service_value.software_state = software_state
|
||||
if software_state == SoftwareState.PATCHING:
|
||||
service_value.patching_count = (
|
||||
self.config_values.service_patching_duration
|
||||
)
|
||||
else:
|
||||
# Do nothing
|
||||
pass
|
||||
else:
|
||||
_LOGGER.info(
|
||||
f"The Nodes operating state is OFF so the state of a service "
|
||||
f"The Nodes hardware state is OFF so the state of a service "
|
||||
f"cannot be changed. "
|
||||
f"Node:{self.id}, "
|
||||
f"Node Operating State:{self.operating_state}, "
|
||||
f"Node Service Protocol:{_protocol}, "
|
||||
f"Node Service State: {_state}"
|
||||
f"Node.node_id:{self.node_id}, "
|
||||
f"Node.hardware_state:{self.hardware_state}, "
|
||||
f"Node.services[<key>]:{protocol_name}, "
|
||||
f"Node.services[<key>].software_state:{software_state}"
|
||||
)
|
||||
|
||||
def set_service_state_if_not_compromised(self, _protocol, _state):
|
||||
"""
|
||||
Sets the state of a service (protocol) on the node if the operating state is not "compromised".
|
||||
|
||||
Args:
|
||||
_protocol: The service (protocol)
|
||||
_state: The state value
|
||||
"""
|
||||
if self.operating_state != HARDWARE_STATE.OFF:
|
||||
for service_key, service_value in self.services.items():
|
||||
if service_key == _protocol:
|
||||
if service_value.get_state() != SOFTWARE_STATE.COMPROMISED:
|
||||
service_value.set_state(_state)
|
||||
if _state == SOFTWARE_STATE.PATCHING:
|
||||
service_value.patching_count = (
|
||||
self.config_values.service_patching_duration
|
||||
)
|
||||
else:
|
||||
_LOGGER.info(
|
||||
f"The Nodes operating state is OFF so the state of a service "
|
||||
f"cannot be changed. "
|
||||
f"Node:{self.id}, "
|
||||
f"Node Operating State:{self.operating_state}, "
|
||||
f"Node Service Protocol:{_protocol}, "
|
||||
f"Node Service State:{_state}"
|
||||
)
|
||||
|
||||
def get_service_state(self, _protocol):
|
||||
def get_service_state(self, protocol_name):
|
||||
"""
|
||||
Gets the state of a service.
|
||||
|
||||
Returns:
|
||||
The state of the service
|
||||
:return: The software_state of the service.
|
||||
"""
|
||||
for service_key, service_value in self.services.items():
|
||||
if service_key == _protocol:
|
||||
return service_value.get_state()
|
||||
service_key = protocol_name
|
||||
service_value = self.services.get(service_key)
|
||||
if service_value:
|
||||
return service_value.software_state
|
||||
|
||||
def update_services_patching_status(self):
|
||||
"""Updates the patching counter for any service that are patching."""
|
||||
for service_key, service_value in self.services.items():
|
||||
if service_value.get_state() == SOFTWARE_STATE.PATCHING:
|
||||
if service_value.software_state == SoftwareState.PATCHING:
|
||||
service_value.reduce_patching_count()
|
||||
|
||||
Reference in New Issue
Block a user