Skip to content

Commit

Permalink
Add excluded_machines in undeploy (#294)
Browse files Browse the repository at this point in the history
  • Loading branch information
Skazza94 committed May 15, 2024
1 parent 5a3ae87 commit 0ad23f3
Show file tree
Hide file tree
Showing 10 changed files with 495 additions and 63 deletions.
11 changes: 7 additions & 4 deletions src/Kathara/foundation/manager/IManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ def deploy_link(self, link: Link) -> None:
raise NotImplementedError("You must implement `deploy_link` method.")

@abstractmethod
def deploy_lab(self, lab: Lab, selected_machines: Set[str] = None, excluded_machines: Set[str] = None) -> None:
def deploy_lab(self, lab: Lab, selected_machines: Optional[Set[str]] = None,
excluded_machines: Optional[Set[str]] = None) -> None:
"""Deploy a Kathara network scenario.
Args:
lab (Kathara.model.Lab): A Kathara network scenario.
selected_machines (Set[str]): If not None, deploy only the specified devices.
excluded_machines (Set[str]): If not None, exclude devices from being deployed.
selected_machines (Optional[Set[str]]): If not None, deploy only the specified devices.
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being deployed.
Returns:
None
Expand Down Expand Up @@ -124,7 +125,8 @@ def undeploy_link(self, link: Link) -> None:

@abstractmethod
def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] = None, lab: Optional[Lab] = None,
selected_machines: Optional[Set[str]] = None) -> None:
selected_machines: Optional[Set[str]] = None,
excluded_machines: Optional[Set[str]] = None) -> None:
"""Undeploy a Kathara network scenario.
Args:
Expand All @@ -135,6 +137,7 @@ def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] =
lab (Optional[Kathara.model.Lab]): The network scenario object.
Can be used as an alternative to lab_hash and lab_name. If None, lab_hash or lab_name should be set.
selected_machines (Optional[Set[str]]): If not None, undeploy only the specified devices.
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being undeployed.
Returns:
None
Expand Down
13 changes: 8 additions & 5 deletions src/Kathara/manager/Kathara.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,14 @@ def deploy_link(self, link: Link) -> None:
"""
self.manager.deploy_link(link)

def deploy_lab(self, lab: Lab, selected_machines: Set[str] = None, excluded_machines: Set[str] = None) -> None:
def deploy_lab(self, lab: Lab, selected_machines: Optional[Set[str]] = None,
excluded_machines: Optional[Set[str]] = None) -> None:
"""Deploy a Kathara network scenario.
Args:
lab (Kathara.model.Lab): A Kathara network scenario.
selected_machines (Set[str]): If not None, deploy only the specified devices.
excluded_machines (Set[str]): If not None, exclude devices from being deployed.
selected_machines (Optional[Set[str]]): If not None, deploy only the specified devices.
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being deployed.
Returns:
None
Expand Down Expand Up @@ -152,7 +153,8 @@ def undeploy_link(self, link: Link) -> None:
self.manager.undeploy_link(link)

def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] = None, lab: Optional[Lab] = None,
selected_machines: Optional[Set[str]] = None) -> None:
selected_machines: Optional[Set[str]] = None,
excluded_machines: Optional[Set[str]] = None) -> None:
"""Undeploy a Kathara network scenario.
Args:
Expand All @@ -163,14 +165,15 @@ def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] =
lab (Optional[Kathara.model.Lab]): The network scenario object.
Can be used as an alternative to lab_hash and lab_name. If None, lab_hash or lab_name should be set.
selected_machines (Optional[Set[str]]): If not None, undeploy only the specified devices.
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being undeployed.
Returns:
None
Raises:
InvocationError: If a running network scenario hash or name is not specified.
"""
self.manager.undeploy_lab(lab_hash, lab_name, lab, selected_machines)
self.manager.undeploy_lab(lab_hash, lab_name, lab, selected_machines, excluded_machines)

def wipe(self, all_users: bool = False) -> None:
"""Undeploy all the running network scenarios.
Expand Down
13 changes: 9 additions & 4 deletions src/Kathara/manager/docker/DockerMachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,22 +470,27 @@ def start(self, machine: Machine) -> None:

machine.api_object.reload()

def undeploy(self, lab_hash: str, selected_machines: Set[str] = None) -> None:
def undeploy(self, lab_hash: str, selected_machines: Set[str] = None, excluded_machines: Set[str] = None) -> None:
"""Undeploy the devices contained in the network scenario defined by the lab_hash.
If a set of selected_machines is specified, undeploy only the specified devices.
Args:
lab_hash (str): The hash of the network scenario to undeploy.
selected_machines (Optional[Set[str]]): If not None, undeploy only the specified devices.
selected_machines (Set[str]): A set containing the name of the devices to undeploy.
excluded_machines (Set[str]): A set containing the name of the devices to exclude.
Returns:
None
"""
containers = self.get_machines_api_objects_by_filters(lab_hash=lab_hash, user=utils.get_current_user_name())

if selected_machines is not None and len(selected_machines) > 0:
containers = [item for item in containers if item.labels["name"] in selected_machines]
if selected_machines or excluded_machines:
containers = [
item for item in containers
if (selected_machines is None or item.labels["name"] in selected_machines) and
(excluded_machines is None or item.labels["name"] not in excluded_machines)
]

if len(containers) > 0:
pool_size = utils.get_pool_size()
Expand Down
15 changes: 9 additions & 6 deletions src/Kathara/manager/docker/DockerManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from ... import utils
from ...decorators import privileged
from ...exceptions import DockerDaemonConnectionError, LinkNotFoundError, MachineCollisionDomainError, \
InvocationError, LabNotFoundError, MachineNotRunningError, PrivilegeError
InvocationError, LabNotFoundError, MachineNotRunningError
from ...exceptions import MachineNotFoundError
from ...foundation.manager.IManager import IManager
from ...model.Lab import Lab
Expand Down Expand Up @@ -121,13 +121,14 @@ def deploy_link(self, link: Link) -> None:
self.docker_link.deploy_links(link.lab, selected_links={link.name})

@privileged
def deploy_lab(self, lab: Lab, selected_machines: Set[str] = None, excluded_machines: Set[str] = None) -> None:
def deploy_lab(self, lab: Lab, selected_machines: Optional[Set[str]] = None,
excluded_machines: Optional[Set[str]] = None) -> None:
"""Deploy a Kathara network scenario.
Args:
lab (Kathara.model.Lab): A Kathara network scenario.
selected_machines (Set[str]): If not None, deploy only the specified devices.
excluded_machines (Set[str]): If not None, exclude devices from being deployed.
selected_machines (Optional[Set[str]]): If not None, deploy only the specified devices.
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being deployed.
Returns:
None
Expand Down Expand Up @@ -284,7 +285,8 @@ def undeploy_link(self, link: Link) -> None:

@privileged
def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] = None, lab: Optional[Lab] = None,
selected_machines: Optional[Set[str]] = None) -> None:
selected_machines: Optional[Set[str]] = None,
excluded_machines: Optional[Set[str]] = None) -> None:
"""Undeploy a Kathara network scenario.
Args:
Expand All @@ -295,6 +297,7 @@ def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] =
lab (Optional[Kathara.model.Lab]): The network scenario object.
Can be used as an alternative to lab_hash and lab_name. If None, lab_hash or lab_name should be set.
selected_machines (Optional[Set[str]]): If not None, undeploy only the specified devices.
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being undeployed.
Returns:
None
Expand All @@ -308,7 +311,7 @@ def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] =
elif lab_name:
lab_hash = utils.generate_urlsafe_hash(lab_name)

self.docker_machine.undeploy(lab_hash, selected_machines=selected_machines)
self.docker_machine.undeploy(lab_hash, selected_machines=selected_machines, excluded_machines=excluded_machines)

self.docker_link.undeploy(lab_hash)

Expand Down
21 changes: 14 additions & 7 deletions src/Kathara/manager/kubernetes/KubernetesMachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,26 +483,33 @@ def _build_definition(self, machine: Machine, config_map: client.V1ConfigMap) ->
spec=deployment_spec
)

def undeploy(self, lab_hash: str, selected_machines: Optional[Set[str]] = None) -> None:
def undeploy(self, lab_hash: str, selected_machines: Set[str] = None, excluded_machines: Set[str] = None) -> None:
"""Undeploy all the running Kubernetes deployments and Pods contained in the scenario defined by the lab_hash.
If selected_machines is not None, undeploy only the specified devices.
Args:
lab_hash (str): The hash of the network scenario to undeploy.
selected_machines (Optional[Set[str]]): If not None, undeploy only the specified devices.
selected_machines (Set[str]): A set containing the name of the devices to undeploy.
excluded_machines (Set[str]): A set containing the name of the devices to exclude.
Returns:
None
"""
pods = self.get_machines_api_objects_by_filters(lab_hash=lab_hash)
if selected_machines is not None and len(selected_machines) > 0:
pods = [item for item in pods if item.metadata.labels["name"] in selected_machines]
else:
selected_machines = {item.metadata.labels["name"] for item in pods}
machines_to_watch = {item.metadata.labels["name"] for item in pods}
if selected_machines or excluded_machines:
pods = [
item for item in pods
if (selected_machines is None or item.metadata.labels["name"] in selected_machines) and
(excluded_machines is None or item.metadata.labels["name"] not in excluded_machines)
]

machines_to_watch = selected_machines if selected_machines else machines_to_watch
machines_to_watch = machines_to_watch if not excluded_machines else machines_to_watch - excluded_machines

if len(pods) > 0:
wait_thread = threading.Thread(target=self._wait_machines_shutdown, args=(lab_hash, selected_machines))
wait_thread = threading.Thread(target=self._wait_machines_shutdown, args=(lab_hash, machines_to_watch))
wait_thread.start()

pool_size = utils.get_pool_size()
Expand Down
36 changes: 26 additions & 10 deletions src/Kathara/manager/kubernetes/KubernetesManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,14 @@ def deploy_link(self, link: Link) -> None:
self.k8s_namespace.create(link.lab)
self.k8s_link.deploy_links(link.lab, selected_links={link.name})

def deploy_lab(self, lab: Lab, selected_machines: Set[str] = None, excluded_machines: Set[str] = None) -> None:
def deploy_lab(self, lab: Lab, selected_machines: Optional[Set[str]] = None,
excluded_machines: Optional[Set[str]] = None) -> None:
"""Deploy a Kathara network scenario.
Args:
lab (Kathara.model.Lab): A Kathara network scenario.
selected_machines (Set[str]): If not None, deploy only the specified devices.
excluded_machines (Set[str]): If not None, exclude devices from being deployed.
selected_machines (Optional[Set[str]]): If not None, deploy only the specified devices.
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being deployed.
Returns:
None
Expand Down Expand Up @@ -236,7 +237,8 @@ def undeploy_link(self, link: Link) -> None:
self.k8s_link.undeploy(link.lab.hash, selected_links={network_name})

def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] = None, lab: Optional[Lab] = None,
selected_machines: Optional[Set[str]] = None) -> None:
selected_machines: Optional[Set[str]] = None,
excluded_machines: Optional[Set[str]] = None) -> None:
"""Undeploy a Kathara network scenario.
Args:
Expand All @@ -247,6 +249,7 @@ def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] =
lab (Optional[Kathara.model.Lab]): The network scenario object.
Can be used as an alternative to lab_hash and lab_name. If None, lab_hash or lab_name should be set.
selected_machines (Optional[Set[str]]): If not None, undeploy only the specified devices.
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being undeployed.
Returns:
None
Expand All @@ -263,7 +266,7 @@ def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] =
lab_hash = lab_hash.lower()

# When only some machines should be undeployed, special checks are required.
if selected_machines:
if selected_machines or excluded_machines:
# Get all current deployed networks and save only their name
networks = self.k8s_link.get_links_api_objects_by_filters(lab_hash=lab_hash)
all_networks = set([network["metadata"]["name"] for network in networks])
Expand All @@ -280,7 +283,9 @@ def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] =
network_annotation = json.loads(machine.metadata.annotations["k8s.v1.cni.cncf.io/networks"])
networks = [net['name'] for net in network_annotation]

if machine.metadata.labels["name"] not in selected_machines:
# To be running, you are not selected to undeploy, or you are excluded from undeploy
if (selected_machines is not None and machine.metadata.labels["name"] not in selected_machines) or \
(excluded_machines is not None and machine.metadata.labels["name"] in excluded_machines):
running_networks.update(networks)

# Difference between all networks and attached networks are the ones to delete
Expand All @@ -290,13 +295,24 @@ def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] =
running_machines = set([machine.metadata.labels["name"] for machine in running_machines])
else:
networks_to_delete = None
running_machines = set()
running_machines = {}

self.k8s_machine.undeploy(lab_hash, selected_machines=selected_machines)
self.k8s_machine.undeploy(lab_hash, selected_machines=selected_machines, excluded_machines=excluded_machines)
self.k8s_link.undeploy(lab_hash, selected_links=networks_to_delete)

# If no machines are selected or there are no running machines, undeploy the namespace
if not selected_machines or len(running_machines - selected_machines) <= 0:
# Undeploy the namespace if:
# 1- No machines are selected/excluded
# 2- There are machines selected and excluded but the difference is empty
# 3- There are machines selected but the difference is empty
# 4- There are machines excluded but the difference is empty
undeploy_namespace = (
(not selected_machines and not excluded_machines) or
(selected_machines and excluded_machines and
not (running_machines - (selected_machines - excluded_machines))) or
(selected_machines and not (running_machines - selected_machines)) or
(excluded_machines and not (running_machines - excluded_machines))
)
if undeploy_namespace:
logging.debug("Waiting for namespace deletion...")

self.k8s_namespace.undeploy(lab_hash=lab_hash)
Expand Down
Loading

0 comments on commit 0ad23f3

Please sign in to comment.