Skip to content

Commit b5abfc8

Browse files
committed
Merge branch '294-add-excluded' into develop
2 parents 344ece7 + cac8513 commit b5abfc8

22 files changed

+1086
-134
lines changed

docs/kathara-lclean.1.ronn

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ kathara-lclean(1) -- Stop a Kathara network scenario
44

55
## SYNOPSIS
66

7-
`kathara lclean` [`-h`] [`-d` <DIRECTORY>] [<DEVICE_NAME> [<DEVICE_NAME> ...]]
7+
`kathara lclean` [`-h`] [`-d` <DIRECTORY>] [`--exclude` <DEVICE_NAME> [<DEVICE_NAME> ...]] [<DEVICE_NAME> [<DEVICE_NAME> ...]]
88

99
## DESCRIPTION
1010

@@ -22,6 +22,9 @@ By default, stops all the devices of the network scenario. If a list of <DEVICE_
2222
Cleans the Kathara network scenario that is located inside <DIRECTORY>.
2323
If no `-d` option is provided, assume the network scenario is located in the current directory.
2424

25+
* `--exclude` [<DEVICE_NAME> [<DEVICE_NAME> ...]]
26+
A list of device names. You can exclude certain devices of the network scenario from being shut down.
27+
2528
* `DEVICE_NAME`:
2629
A list of device names. Instead of shutting down the whole network scenario, only specified devices are stopped.
2730

docs/kathara-lrestart.1.ronn

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ kathara-lrestart(1) -- Restart a Kathara network scenario
77
`kathara lrestart` [`-h`] [`-F`] [`-l`]
88
[`--noterminals` | `--terminals` | `--privileged`] [`-d` <DIRECTORY>]
99
[`-o` [<OPTION> [<OPTION> ...]]] [`--xterm` <XTERM>]
10-
[`--no-hosthome` \| `--hosthome`] [`--no-shared` \| `--shared`] [<DEVICE_NAME> [<DEVICE_NAME> ...]]
10+
[`--no-hosthome` \| `--hosthome`] [`--no-shared` \| `--shared`] [`--exclude` <DEVICE_NAME> [<DEVICE_NAME> ...]]
11+
[<DEVICE_NAME> [<DEVICE_NAME> ...]]
1112

1213

1314
## DESCRIPTION
@@ -75,6 +76,9 @@ Mainly it has the same options of `lstart` with the lack of some options (e.g. `
7576

7677
Mount the `shared` directory inside the network scenario folder inside all devices on the special directory `/shared`. This is the default specified in `kathara.conf`(5) file.
7778

79+
* `--exclude` [<DEVICE_NAME> [<DEVICE_NAME> ...]]
80+
A list of device names. You can exclude certain devices of the network scenario from being restarted.
81+
7882
* `DEVICE_NAME`:
7983
A list of device names. Instead of restarting the whole network scenario, only specified devices are restarted.
8084

docs/kathara-lstart.1.ronn

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ kathara-lstart(1) -- Start a Kathara network scenario
66

77
`kathara lstart` [`-h`] [`--noterminals` \| `--terminals` \| `--privileged`]
88
[`-d` <DIRECTORY>] [`-F`] [`-l`] [`-o` [<OPTION> [<OPTION> ...]]] [`--xterm` <XTERM>]
9-
[`--print`] [`--no-hosthome` \| `--hosthome`] [`--no-shared` \| `--shared`] [<DEVICE_NAME> [<DEVICE_NAME> ...]]
9+
[`--print`] [`--no-hosthome` \| `--hosthome`] [`--no-shared` \| `--shared`] [`--exclude` <DEVICE_NAME> [<DEVICE_NAME> ...]]
10+
[<DEVICE_NAME> [<DEVICE_NAME> ...]]
1011

1112

1213
## DESCRIPTION
@@ -86,11 +87,14 @@ The configuration of a Kathara network scenario consists of some files described
8687

8788
Mount the `shared` directory inside the network scenario folder inside all devices on the special directory `/shared`. This is the default specified in `kathara.conf`(5) file.
8889

90+
* `--exclude` [<DEVICE_NAME> [<DEVICE_NAME> ...]]
91+
A list of device names. You can exclude certain devices of the network scenario from being started.
92+
8993
* `DEVICE_NAME`:
9094
A list of device names. Instead of starting the whole network scenario, only specified devices are started.
9195

9296
m4_include(footer.txt)
9397

9498
## SEE ALSO
9599

96-
`kathara`(1), `kathara-lclean`(1), `kathara-lrestart`(1), `kathara-ltest`(1), `kathara-linfo`(1), `kathara-lab.conf`(5), `kathara-lab.dep`(5), `kathara-lab.ext`(5)
100+
`kathara`(1), `kathara-lclean`(1), `kathara-lrestart`(1), `kathara-ltest`(1), `kathara-linfo`(1), `kathara-lab.conf`(5), `kathara-lab.dep`(5), `kathara-lab.ext`(5)

src/Kathara/cli/command/LcleanCommand.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ def __init__(self) -> None:
3333
required=False,
3434
help='Specify the folder containing the network scenario.'
3535
)
36+
self.parser.add_argument(
37+
'--exclude',
38+
dest='excluded_machines',
39+
metavar='DEVICE_NAME',
40+
nargs='+',
41+
default=[],
42+
help='Exclude specified devices from clean.'
43+
)
3644
self.parser.add_argument(
3745
'machine_names',
3846
metavar='DEVICE_NAME',
@@ -55,5 +63,6 @@ def run(self, current_path: str, argv: List[str]) -> None:
5563

5664
Kathara.get_instance().undeploy_lab(
5765
lab_hash=lab.hash,
58-
selected_machines=set(args['machine_names']) if args['machine_names'] else None
66+
selected_machines=set(args['machine_names']) if args['machine_names'] else None,
67+
excluded_machines=set(args['excluded_machines']) if args['excluded_machines'] else None,
5968
)

src/Kathara/cli/command/LrestartCommand.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ def __init__(self) -> None:
110110
const=True,
111111
help='Mount "/shared" directory inside devices.'
112112
)
113+
self.parser.add_argument(
114+
'--exclude',
115+
dest='excluded_machines',
116+
metavar='DEVICE_NAME',
117+
nargs='+',
118+
default=[],
119+
help='Exclude specified devices.'
120+
)
113121
self.parser.add_argument(
114122
'machine_name',
115123
metavar='DEVICE_NAME',
@@ -125,6 +133,8 @@ def run(self, current_path: str, argv: List[str]) -> None:
125133

126134
if args['machine_name']:
127135
lclean_argv.extend(args['machine_name'])
136+
if args['excluded_machines']:
137+
lclean_argv.extend(['--exclude'] + args['excluded_machines'])
128138

129139
LcleanCommand().run(current_path, lclean_argv)
130140
LstartCommand().run(current_path, argv)

src/Kathara/cli/command/LstartCommand.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ def __init__(self) -> None:
129129
const=True,
130130
help='Mount "/shared" directory inside devices.'
131131
)
132+
self.parser.add_argument(
133+
'--exclude',
134+
dest='excluded_machines',
135+
metavar='DEVICE_NAME',
136+
nargs='+',
137+
default=[],
138+
help='Exclude specified devices from startup.'
139+
)
132140
self.parser.add_argument(
133141
'machine_name',
134142
metavar='DEVICE_NAME',
@@ -216,7 +224,9 @@ def run(self, current_path: str, argv: List[str]) -> Lab:
216224
self.console.print("[yellow]\u26a0 Running devices with privileged capabilities, terminals won't open!")
217225
Setting.get_instance().open_terminals = False
218226

219-
Kathara.get_instance().deploy_lab(lab, selected_machines=set(args['machine_name']))
227+
Kathara.get_instance().deploy_lab(
228+
lab, selected_machines=set(args['machine_name']), excluded_machines=set(args['excluded_machines'])
229+
)
220230

221231
if args['list']:
222232
with self.console.status(

src/Kathara/foundation/manager/IManager.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@ def deploy_link(self, link: Link) -> None:
4343
raise NotImplementedError("You must implement `deploy_link` method.")
4444

4545
@abstractmethod
46-
def deploy_lab(self, lab: Lab, selected_machines: Set[str] = None) -> None:
46+
def deploy_lab(self, lab: Lab, selected_machines: Optional[Set[str]] = None,
47+
excluded_machines: Optional[Set[str]] = None) -> None:
4748
"""Deploy a Kathara network scenario.
4849
4950
Args:
5051
lab (Kathara.model.Lab): A Kathara network scenario.
51-
selected_machines (Set[str]): If not None, deploy only the specified devices.
52+
selected_machines (Optional[Set[str]]): If not None, deploy only the specified devices.
53+
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being deployed.
5254
5355
Returns:
5456
None
@@ -123,7 +125,8 @@ def undeploy_link(self, link: Link) -> None:
123125

124126
@abstractmethod
125127
def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] = None, lab: Optional[Lab] = None,
126-
selected_machines: Optional[Set[str]] = None) -> None:
128+
selected_machines: Optional[Set[str]] = None,
129+
excluded_machines: Optional[Set[str]] = None) -> None:
127130
"""Undeploy a Kathara network scenario.
128131
129132
Args:
@@ -134,6 +137,7 @@ def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] =
134137
lab (Optional[Kathara.model.Lab]): The network scenario object.
135138
Can be used as an alternative to lab_hash and lab_name. If None, lab_hash or lab_name should be set.
136139
selected_machines (Optional[Set[str]]): If not None, undeploy only the specified devices.
140+
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being undeployed.
137141
138142
Returns:
139143
None

src/Kathara/manager/Kathara.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,19 @@ def deploy_link(self, link: Link) -> None:
7575
"""
7676
self.manager.deploy_link(link)
7777

78-
def deploy_lab(self, lab: Lab, selected_machines: Set[str] = None) -> None:
78+
def deploy_lab(self, lab: Lab, selected_machines: Optional[Set[str]] = None,
79+
excluded_machines: Optional[Set[str]] = None) -> None:
7980
"""Deploy a Kathara network scenario.
8081
8182
Args:
8283
lab (Kathara.model.Lab): A Kathara network scenario.
83-
selected_machines (Set[str]): If not None, deploy only the specified devices.
84+
selected_machines (Optional[Set[str]]): If not None, deploy only the specified devices.
85+
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being deployed.
8486
8587
Returns:
8688
None
8789
"""
88-
self.manager.deploy_lab(lab, selected_machines)
90+
self.manager.deploy_lab(lab, selected_machines, excluded_machines)
8991

9092
def connect_machine_to_link(self, machine: Machine, link: Link, mac_address: Optional[str] = None) -> None:
9193
"""Connect a Kathara device to a collision domain.
@@ -151,7 +153,8 @@ def undeploy_link(self, link: Link) -> None:
151153
self.manager.undeploy_link(link)
152154

153155
def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] = None, lab: Optional[Lab] = None,
154-
selected_machines: Optional[Set[str]] = None) -> None:
156+
selected_machines: Optional[Set[str]] = None,
157+
excluded_machines: Optional[Set[str]] = None) -> None:
155158
"""Undeploy a Kathara network scenario.
156159
157160
Args:
@@ -162,14 +165,15 @@ def undeploy_lab(self, lab_hash: Optional[str] = None, lab_name: Optional[str] =
162165
lab (Optional[Kathara.model.Lab]): The network scenario object.
163166
Can be used as an alternative to lab_hash and lab_name. If None, lab_hash or lab_name should be set.
164167
selected_machines (Optional[Set[str]]): If not None, undeploy only the specified devices.
168+
excluded_machines (Optional[Set[str]]): If not None, exclude devices from being undeployed.
165169
166170
Returns:
167171
None
168172
169173
Raises:
170174
InvocationError: If a running network scenario hash or name is not specified.
171175
"""
172-
self.manager.undeploy_lab(lab_hash, lab_name, lab, selected_machines)
176+
self.manager.undeploy_lab(lab_hash, lab_name, lab, selected_machines, excluded_machines)
173177

174178
def wipe(self, all_users: bool = False) -> None:
175179
"""Undeploy all the running network scenarios.

src/Kathara/manager/docker/DockerLink.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from .stats.DockerLinkStats import DockerLinkStats
1414
from ... import utils
1515
from ...event.EventDispatcher import EventDispatcher
16-
from ...exceptions import PrivilegeError
16+
from ...exceptions import PrivilegeError, InvocationError
1717
from ...model.ExternalLink import ExternalLink
1818
from ...model.Lab import Lab
1919
from ...model.Link import BRIDGE_LINK_NAME, Link
@@ -30,18 +30,32 @@ def __init__(self, client: DockerClient, docker_plugin: DockerPlugin) -> None:
3030
self.client: DockerClient = client
3131
self.docker_plugin: DockerPlugin = docker_plugin
3232

33-
def deploy_links(self, lab: Lab, selected_links: Set[str] = None) -> None:
33+
def deploy_links(self, lab: Lab, selected_links: Set[str] = None, excluded_links: Set[str] = None) -> None:
3434
"""Deploy all the network scenario collision domains as Docker networks.
3535
3636
Args:
3737
lab (Kathara.model.Lab.Lab): A Kathara network scenario.
3838
selected_links (Set[str]): A set containing the name of the collision domains to deploy.
39+
excluded_links (Set[str]): A set containing the name of the collision domains to exclude.
3940
4041
Returns:
4142
None
43+
44+
Raises:
45+
InvocationError: If both `selected_links` and `excluded_links` are specified.
4246
"""
43-
links = {k: v for (k, v) in lab.links.items() if k in selected_links}.items() if selected_links \
44-
else lab.links.items()
47+
if selected_links and excluded_links:
48+
raise InvocationError(f"You can either specify `selected_links` or `excluded_links`.")
49+
50+
links = lab.links.items()
51+
if selected_links:
52+
links = {
53+
k: v for k, v in links if k in selected_links
54+
}.items()
55+
elif excluded_links:
56+
links = {
57+
k: v for k, v in links if k not in excluded_links
58+
}.items()
4559

4660
if len(links) > 0:
4761
pool_size = utils.get_pool_size()
@@ -148,7 +162,7 @@ def undeploy(self, lab_hash: str, selected_links: Optional[Set[str]] = None) ->
148162
None
149163
"""
150164
networks = self.get_links_api_objects_by_filters(lab_hash=lab_hash)
151-
if selected_links is not None and len(selected_links) > 0:
165+
if selected_links:
152166
networks = [item for item in networks if item.attrs["Labels"]["name"] in selected_links]
153167

154168
for item in networks:

src/Kathara/manager/docker/DockerMachine.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from ... import utils
1919
from ...event.EventDispatcher import EventDispatcher
2020
from ...exceptions import MountDeniedError, MachineAlreadyExistsError, DockerPluginError, \
21-
MachineBinaryError, MachineNotRunningError, PrivilegeError
21+
MachineBinaryError, MachineNotRunningError, PrivilegeError, InvocationError
2222
from ...model.Interface import Interface
2323
from ...model.Lab import Lab
2424
from ...model.Link import Link, BRIDGE_LINK_NAME
@@ -109,24 +109,36 @@ def __init__(self, client: DockerClient, docker_image: DockerImage) -> None:
109109
self._engine_version: str = client.version()['Version']
110110
self.docker_image: DockerImage = docker_image
111111

112-
def deploy_machines(self, lab: Lab, selected_machines: Set[str] = None) -> None:
112+
def deploy_machines(self, lab: Lab, selected_machines: Set[str] = None, excluded_machines: Set[str] = None) -> None:
113113
"""Deploy all the network scenario devices as Docker containers.
114114
115115
Args:
116116
lab (Kathara.model.Lab.Lab): A Kathara network scenario.
117117
selected_machines (Set[str]): A set containing the name of the devices to deploy.
118+
excluded_machines (Set[str]): A set containing the name of the devices to exclude.
118119
119120
Returns:
120121
None
121122
122123
Raises:
123124
PrivilegeError: If the privileged mode is active and the user does not have root privileges.
125+
InvocationError: If both `selected_machines` and `excluded_machines` are specified.
124126
"""
125127
if lab.general_options['privileged_machines'] and not utils.is_admin():
126128
raise PrivilegeError("You must be root in order to start Kathara devices in privileged mode.")
127129

128-
machines = {k: v for (k, v) in lab.machines.items() if k in selected_machines}.items() if selected_machines \
129-
else lab.machines.items()
130+
if selected_machines and excluded_machines:
131+
raise InvocationError(f"You can either specify `selected_machines` or `excluded_machines`.")
132+
133+
machines = lab.machines.items()
134+
if selected_machines:
135+
machines = {
136+
k: v for k, v in machines if k in selected_machines
137+
}.items()
138+
elif excluded_machines:
139+
machines = {
140+
k: v for k, v in machines if k not in excluded_machines
141+
}.items()
130142

131143
# Check and pulling machine images
132144
lab_images = set(map(lambda x: x[1].get_image(), machines))
@@ -471,22 +483,30 @@ def start(self, machine: Machine) -> None:
471483

472484
machine.api_object.reload()
473485

474-
def undeploy(self, lab_hash: str, selected_machines: Set[str] = None) -> None:
486+
def undeploy(self, lab_hash: str, selected_machines: Set[str] = None, excluded_machines: Set[str] = None) -> None:
475487
"""Undeploy the devices contained in the network scenario defined by the lab_hash.
476488
477489
If a set of selected_machines is specified, undeploy only the specified devices.
478490
479491
Args:
480492
lab_hash (str): The hash of the network scenario to undeploy.
481-
selected_machines (Optional[Set[str]]): If not None, undeploy only the specified devices.
493+
selected_machines (Set[str]): A set containing the name of the devices to undeploy.
494+
excluded_machines (Set[str]): A set containing the name of the devices to exclude.
482495
483496
Returns:
484497
None
498+
499+
Raises:
500+
InvocationError: If both `selected_machines` and `excluded_machines` are specified.
485501
"""
486-
containers = self.get_machines_api_objects_by_filters(lab_hash=lab_hash, user=utils.get_current_user_name())
502+
if selected_machines and excluded_machines:
503+
raise InvocationError(f"You can either specify `selected_machines` or `excluded_machines`.")
487504

488-
if selected_machines is not None and len(selected_machines) > 0:
505+
containers = self.get_machines_api_objects_by_filters(lab_hash=lab_hash, user=utils.get_current_user_name())
506+
if selected_machines:
489507
containers = [item for item in containers if item.labels["name"] in selected_machines]
508+
elif excluded_machines:
509+
containers = [item for item in containers if item.labels["name"] not in excluded_machines]
490510

491511
if len(containers) > 0:
492512
pool_size = utils.get_pool_size()

0 commit comments

Comments
 (0)