Skip to content

Commit 7cf0d33

Browse files
Merge pull request #14 from SWR-MoIP/feature/topology-elements-by-module
Extend TopologyDeviceConfiguration Class with new methods for vertex filtering by module label
2 parents 5451f85 + 3e9e75e commit 7cf0d33

6 files changed

Lines changed: 118 additions & 17 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ The provided methods and data models ensure easy handling, robust validation, co
2929
### Prerequisites
3030

3131
- Access to a VideoIPath Server (version 2023.4.2 or higher, LTS versions recommended)
32-
- A user account with API access credentials
32+
- Username and Password for a user account with API access
3333
- Python 3.11 or higher
3434

3535
### Installation
@@ -39,7 +39,7 @@ The package is available via the [Python Package Index (PyPI)](https://pypi.org/
3939
#### Install the package using pip
4040

4141
```bash
42-
pip3 install videoipath-automation-tool
42+
pip install videoipath-automation-tool
4343
```
4444

4545
### A Simple Example: Adding a Device to the Inventory
@@ -49,7 +49,7 @@ pip3 install videoipath-automation-tool
4949
from videoipath_automation_tool import VideoIPathApp
5050

5151
# Initialize the VideoIPathApp
52-
app = VideoIPathApp(server_address="10.1.100.10", username="api-user", password="veryStrongPassword")
52+
app = VideoIPathApp(server_address="10.1.100.10", username="api-user", password="veryStrongPassword", use_https=False, verify_ssl_cert=False)
5353

5454
# Create a device object with NMOS Multidevice driver
5555
staged_device = app.inventory.create_device(driver="com.nevion.NMOS_multidevice-0.1.0")

docs/development-and-release.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ For stable/official versions, the common semver pattern is used:
2222
For development versions, there are multiple options - since this package doesn't have a complex testing and verification process for release,
2323
a simple format is used:
2424

25-
`<Major>.<Minor>.<Patch>.dev+<short commit SHA>`
25+
`<Major>.<Minor>.<Patch>.dev<GitHub Action Run ID>`
2626

2727
Pip won't treat those versions as stable, they can only be installed by specifying the exact version or using the `--pre` flag.
2828

@@ -71,7 +71,7 @@ flowchart TD
7171
subgraph run-mr-pipeline["Run Merge-Request Pipeline"]
7272
mr-tests["Run Tests [Pipeline]"]
7373
mr-build["Build the Package [Pipeline]"]
74-
publish-dev-version["Publish Dev Version, e.g. 1.3.6.dev+d882293d [Pipeline]"]
74+
publish-dev-version["Publish Dev Version, e.g. 1.3.6.dev256 [Pipeline]"]
7575
7676
mr-tests --> mr-build
7777
mr-build --> publish-dev-version

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "videoipath-automation-tool"
3-
version = "0.1.6"
3+
version = "0.2.0"
44
description = "A Python package for automating VideoIPath configuration workflows."
55
authors = ["Paul Winterstein <paul.winterstein@swr.de>"]
66
maintainers = ["SWR Media-over-IP Team <moip@swr.de>", "Josia Hildebrandt <manuel_josia.hildebrandt@swr.de>"]

src/videoipath_automation_tool/apps/inventory/model/device_status.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List
1+
from typing import List, Optional
22

33
from pydantic import BaseModel, Field
44

@@ -65,3 +65,30 @@ class DeviceStatus(BaseModel):
6565
reachable: bool
6666
softwareInfo: dict
6767
url: str
68+
69+
def list_modules_label(self) -> List[str]:
70+
"""List all modules label."""
71+
return [module.label for module in self.modules]
72+
73+
def list_modules_id(self) -> List[str]:
74+
"""List all modules id."""
75+
return [module.id for module in self.modules]
76+
77+
def get_module_by_id(self, module_id: str) -> Optional[ModulesEntry]:
78+
"""Get module by id."""
79+
for module in self.modules:
80+
if module.id == module_id:
81+
return module
82+
return None
83+
84+
def get_module_by_label(self, module_label: str) -> Optional[ModulesEntry]:
85+
"""Returns the module with the specified label, or None if not found.
86+
87+
Raises:
88+
ValueError: If multiple modules with the same label are found.
89+
"""
90+
matches = [module for module in self.modules if module.label == module_label]
91+
92+
if len(matches) > 1:
93+
raise ValueError(f"Multiple modules found with label '{module_label}'")
94+
return matches[0] if matches else None

src/videoipath_automation_tool/apps/topology/model/topology_device.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def add_virtual_module(self) -> GenericVertex:
180180
"_vid": module_id,
181181
"descriptor": {"label": "", "desc": ""},
182182
"fDescriptor": {
183-
"label": f"Virtual Device {device_number+1} Virtual Switching Core {module_number}",
183+
"label": f"Virtual Device {device_number + 1} Virtual Switching Core {module_number}",
184184
"desc": "",
185185
},
186186
"deviceId": f"{device_id}",
@@ -248,7 +248,7 @@ def add_virtual_codec_vertex(
248248
"descriptor": {"label": "", "desc": ""},
249249
"fDescriptor": {
250250
"label": f"Vertex {vertex_number}",
251-
"desc": f"Virtual Device {device_number+1} Vertex {vertex_number}",
251+
"desc": f"Virtual Device {device_number + 1} Vertex {vertex_number}",
252252
},
253253
"deviceId": f"{device_id}",
254254
"gpid": {
@@ -305,7 +305,7 @@ def add_virtual_codec_vertex(
305305
"descriptor": {"label": "", "desc": ""},
306306
"excludeFormats": [],
307307
"fDescriptor": {
308-
"label": f"Vertex {vertex_number} -> Virtual Device {device_number+1} Virtual Switching Core {module_number}",
308+
"label": f"Vertex {vertex_number} -> Virtual Device {device_number + 1} Virtual Switching Core {module_number}",
309309
"desc": "",
310310
},
311311
"fromId": f"{vertex_id}",
@@ -332,7 +332,7 @@ def add_virtual_codec_vertex(
332332
"descriptor": {"label": "", "desc": ""},
333333
"excludeFormats": [],
334334
"fDescriptor": {
335-
"label": f"Virtual Device {device_number+1} Virtual Switching Core {module_number} -> Vertex {vertex_number}",
335+
"label": f"Virtual Device {device_number + 1} Virtual Switching Core {module_number} -> Vertex {vertex_number}",
336336
"desc": "",
337337
},
338338
"fromId": f"{module_id}",
@@ -390,7 +390,7 @@ def add_virtual_ip_vertex(
390390
"descriptor": {"label": "", "desc": ""},
391391
"fDescriptor": {
392392
"label": f"Vertex {vertex_number}",
393-
"desc": f"Virtual Device {device_number+1} Vertex {vertex_number}",
393+
"desc": f"Virtual Device {device_number + 1} Vertex {vertex_number}",
394394
},
395395
"deviceId": f"{device_id}",
396396
"gpid": {
@@ -436,7 +436,7 @@ def add_virtual_ip_vertex(
436436
"descriptor": {"label": "", "desc": ""},
437437
"excludeFormats": [],
438438
"fDescriptor": {
439-
"label": f"Vertex {vertex_number} -> Virtual Device {device_number+1} Virtual Switching Core {module_number}",
439+
"label": f"Vertex {vertex_number} -> Virtual Device {device_number + 1} Virtual Switching Core {module_number}",
440440
"desc": "",
441441
},
442442
"fromId": f"{vertex_id}",
@@ -463,7 +463,7 @@ def add_virtual_ip_vertex(
463463
"descriptor": {"label": "", "desc": ""},
464464
"excludeFormats": [],
465465
"fDescriptor": {
466-
"label": f"Virtual Device {device_number+1} Virtual Switching Core {module_number} -> Vertex {vertex_number}",
466+
"label": f"Virtual Device {device_number + 1} Virtual Switching Core {module_number} -> Vertex {vertex_number}",
467467
"desc": "",
468468
},
469469
"fromId": f"{module_id}",
@@ -521,7 +521,7 @@ def add_virtual_generic_vertex(
521521
"descriptor": {"label": "", "desc": ""},
522522
"fDescriptor": {
523523
"label": f"Vertex {vertex_number}",
524-
"desc": f"Virtual Device {device_number+1} Vertex {vertex_number}",
524+
"desc": f"Virtual Device {device_number + 1} Vertex {vertex_number}",
525525
},
526526
"deviceId": f"{device_id}",
527527
"gpid": {
@@ -556,7 +556,7 @@ def add_virtual_generic_vertex(
556556
"descriptor": {"label": "", "desc": ""},
557557
"excludeFormats": [],
558558
"fDescriptor": {
559-
"label": f"Vertex {vertex_number} -> Virtual Device {device_number+1} Virtual Switching Core {module_number}",
559+
"label": f"Vertex {vertex_number} -> Virtual Device {device_number + 1} Virtual Switching Core {module_number}",
560560
"desc": "",
561561
},
562562
"fromId": f"{vertex_id}",
@@ -583,7 +583,7 @@ def add_virtual_generic_vertex(
583583
"descriptor": {"label": "", "desc": ""},
584584
"excludeFormats": [],
585585
"fDescriptor": {
586-
"label": f"Virtual Device {device_number+1} Virtual Switching Core {module_number} -> Vertex {vertex_number}",
586+
"label": f"Virtual Device {device_number + 1} Virtual Switching Core {module_number} -> Vertex {vertex_number}",
587587
"desc": "",
588588
},
589589
"fromId": f"{module_id}",

src/videoipath_automation_tool/apps/topology/model/topology_device_configuration.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
from pydantic import BaseModel, Field
66
from typing_extensions import deprecated
77

8+
from videoipath_automation_tool.apps.inventory.model.device_status import DeviceStatus
9+
from videoipath_automation_tool.apps.inventory.model.inventory_device import InventoryDevice
810
from videoipath_automation_tool.apps.topology.model.n_graph_elements.topology_base_device import BaseDevice
911
from videoipath_automation_tool.apps.topology.model.n_graph_elements.topology_codec_vertex import CodecVertex
1012
from videoipath_automation_tool.apps.topology.model.n_graph_elements.topology_generic_vertex import GenericVertex
@@ -166,6 +168,78 @@ def site_id(self, value: str) -> None:
166168
self.base_device.siteId = value
167169

168170
# --- Methods ---
171+
def get_vertices_by_module_label(
172+
self,
173+
module_label: str,
174+
inventory_device_status: InventoryDevice | DeviceStatus,
175+
vertex_type: Literal["all", "codec_vertex", "ip_vertex", "generic_vertex"] = "all",
176+
):
177+
"""Get all vertices by module label.
178+
Optionally, the search can be filtered by vertex type.
179+
180+
Args:
181+
module_label (str): The module label to search for (e.g. `Slot 3`).
182+
inventory_device_status (InventoryDevice | DeviceStatus): The inventory device status object.
183+
184+
Returns:
185+
List[BaseDevice | GenericVertex | IpVertex | CodecVertex | UnidirectionalEdge]: A list of matching nGraphElements.
186+
"""
187+
188+
if vertex_type == "all":
189+
combined_vertex_list = chain(
190+
self.generic_vertices,
191+
self.ip_vertices,
192+
self.codec_vertices,
193+
) # Note: Base Device and Edges are not included in this search
194+
elif vertex_type == "codec_vertex":
195+
combined_vertex_list = self.codec_vertices
196+
elif vertex_type == "ip_vertex":
197+
combined_vertex_list = self.ip_vertices
198+
elif vertex_type == "generic_vertex":
199+
combined_vertex_list = self.generic_vertices
200+
else:
201+
raise ValueError(
202+
f"Invalid vertex type: {vertex_type}. Valid options are 'all', 'codec_vertex', 'ip_vertex', or 'generic_vertex'."
203+
)
204+
205+
if isinstance(inventory_device_status, InventoryDevice):
206+
device_status = inventory_device_status
207+
else:
208+
device_status = inventory_device_status
209+
210+
if not device_status:
211+
raise ValueError("Device status is not available.")
212+
213+
# Check if the device ID matches the topology device ID
214+
if device_status.id != self.base_device.id:
215+
raise ValueError(
216+
f"Device ID mismatch: Inventory device ID '{device_status.id}' does not match topology device ID '{self.base_device.id}'."
217+
)
218+
219+
module = device_status.get_module_by_label(module_label)
220+
221+
if not module:
222+
raise ValueError(f"Module with label '{module_label}' not found in device status.")
223+
224+
# Build the list of element IDs to search for
225+
# <device_id>.<module_id>.<port_id>
226+
# e.g. 'device66.4.6200000'
227+
228+
element_id_list = []
229+
device_id = device_status.id
230+
module_id = module.id
231+
for port in module.ports:
232+
port_id = port.id
233+
element_id = f"{device_id}.{module_id}.{port_id}"
234+
element_id_list.append(element_id)
235+
236+
vertex_list = []
237+
for element in combined_vertex_list:
238+
if element.id in element_id_list:
239+
vertex_list.append(element)
240+
241+
return vertex_list
242+
169243
def get_nGraphElement_by_id(
170244
self, element_id: str
171245
) -> Optional[BaseDevice | GenericVertex | IpVertex | CodecVertex | UnidirectionalEdge]:

0 commit comments

Comments
 (0)