Add ability to uninstall service

This commit is contained in:
Marek Wolan
2023-08-29 14:15:49 +01:00
parent 9c8b7a7b7a
commit f0b82cbdfb
5 changed files with 74 additions and 15 deletions

View File

@@ -1,5 +1,5 @@
from random import choice from random import choice
from typing import Dict, Optional from typing import Dict, Optional, Union
from primaite import getLogger from primaite import getLogger
from primaite.simulator.core import SimComponent from primaite.simulator.core import SimComponent
@@ -211,7 +211,7 @@ class FileSystem(SimComponent):
if file is not None: if file is not None:
return file return file
def get_folder_by_name(self, folder_name: str) -> FileSystemFolder: def get_folder_by_name(self, folder_name: str) -> Union[FileSystemFolder, None]:
""" """
Returns a the first folder with a matching name. Returns a the first folder with a matching name.

View File

@@ -1004,6 +1004,7 @@ class Node(SimComponent):
if service in self: if service in self:
_LOGGER.warning(f"Can't add service {service.uuid} to node {self.uuid}. It's already installed.") _LOGGER.warning(f"Can't add service {service.uuid} to node {self.uuid}. It's already installed.")
return return
self.services[service.uuid] = service
service.parent = self service.parent = self
service.install() # Perform any additional setup, such as creating files for this service on the node. service.install() # Perform any additional setup, such as creating files for this service on the node.
_LOGGER.info(f"Added service {service.uuid} to node {self.uuid}") _LOGGER.info(f"Added service {service.uuid} to node {self.uuid}")

View File

@@ -12,6 +12,21 @@ class DatabaseService(Service):
"""TODO.""" """TODO."""
return super().describe_state() return super().describe_state()
def uninstall(self) -> None:
"""
Undo installation procedure.
This method deletes files created when installing the database, and the database folder if it is empty.
"""
super().uninstall()
node: Node = self.parent
node.file_system.delete_file(self.primary_store)
node.file_system.delete_file(self.transaction_log)
if self.secondary_store:
node.file_system.delete_file(self.secondary_store)
if len(self.folder.files) == 0:
node.file_system.delete_folder(self.folder)
def install(self) -> None: def install(self) -> None:
"""Perform first time install on a node, creating necessary files.""" """Perform first time install on a node, creating necessary files."""
super().install() super().install()
@@ -39,10 +54,16 @@ class DatabaseService(Service):
# note that this parent.file_system.create_folder call in the future will be authenticated by using permissions # note that this parent.file_system.create_folder call in the future will be authenticated by using permissions
# handler. This permission will be granted based on service account given to the database service. # handler. This permission will be granted based on service account given to the database service.
self.parent: Node self.parent: Node
folder = self.parent.file_system.create_folder(folder_name) self.folder = self.parent.file_system.create_folder(folder_name)
self.parent.file_system.create_file("db_primary_store", db_size, FileSystemFileType.MDF, folder=folder) self.primary_store = self.parent.file_system.create_file(
self.parent.file_system.create_file("db_transaction_log", "1", FileSystemFileType.LDF, folder=folder) "db_primary_store", db_size, FileSystemFileType.MDF, folder=self.folder
)
self.transaction_log = self.parent.file_system.create_file(
"db_transaction_log", "1", FileSystemFileType.LDF, folder=self.folder
)
if use_secondary_db_file: if use_secondary_db_file:
self.parent.file_system.create_file( self.secondary_store = self.parent.file_system.create_file(
"db_secondary_store", secondary_db_size, FileSystemFileType.NDF, folder=folder "db_secondary_store", secondary_db_size, FileSystemFileType.NDF, folder=self.folder
) )
else:
self.secondary_store = None

View File

@@ -1,13 +1,10 @@
from abc import abstractmethod from abc import abstractmethod
from enum import Enum from enum import Enum
from typing import Any, Dict, Set, TYPE_CHECKING from typing import Any, Dict, Set
from primaite.simulator.core import Action, ActionManager, SimComponent from primaite.simulator.core import Action, ActionManager, SimComponent
from primaite.simulator.network.transmission.transport_layer import Port from primaite.simulator.network.transmission.transport_layer import Port
if TYPE_CHECKING:
from primaite.simulator.network.hardware.base import Node
class SoftwareType(Enum): class SoftwareType(Enum):
""" """
@@ -143,11 +140,17 @@ class Software(SimComponent):
This is an abstract class that should be overwritten by specific applications or services. It must be called This is an abstract class that should be overwritten by specific applications or services. It must be called
after the service is already associate with a node. For example, a service may need to authenticate with a after the service is already associate with a node. For example, a service may need to authenticate with a
server during installation, or create files in the node's filesystem. server during installation, or create files in the node's filesystem.
:param node: Node on which this software runs.
:type node: Node
""" """
parent: "Node" = self.parent # noqa pass
def uninstall(self) -> None:
"""Uninstall this service from a node.
This is an abstract class that should be overwritten by applications or services. It must be called after the
`install` method has already been run on that node. It should undo any installation steps, for example by
deleting files, or contacting a server.
"""
pass
def scan(self) -> None: def scan(self) -> None:
"""Update the observed health status to match the actual health status.""" """Update the observed health status to match the actual health status."""

View File

@@ -20,3 +20,37 @@ def test_installing_database():
node = Node(hostname="db-server") node = Node(hostname="db-server")
node.install_service(db) node.install_service(db)
assert db in node
file_exists = False
for folder in node.file_system.folders.values():
for file in folder.files.values():
if file.name == "db_primary_store":
file_exists = True
break
if file_exists:
break
assert file_exists
def test_uninstalling_database():
db = DatabaseService(
name="SQL-database",
health_state_actual=SoftwareHealthState.GOOD,
health_state_visible=SoftwareHealthState.GOOD,
criticality=SoftwareCriticality.MEDIUM,
ports=[
Port.SQL_SERVER,
],
operating_state=ServiceOperatingState.RUNNING,
)
node = Node(hostname="db-server")
node.install_service(db)
node.uninstall_service(db)
assert db not in node
assert node.file_system.get_folder_by_name("database") is None