Skip to content

Commit 05eaff5

Browse files
committed
pydantic(netapp): enforce correct interface names
1 parent ad836a7 commit 05eaff5

File tree

7 files changed

+37
-56
lines changed

7 files changed

+37
-56
lines changed

python/understack-workflows/tests/test_netapp_config.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,12 +384,12 @@ def test_integration_netapp_config_with_from_nautobot_response(
384384

385385
# Create a mock nautobot response
386386
mock_interface_a = MagicMock()
387-
mock_interface_a.name = "N1-test-A"
387+
mock_interface_a.name = "N1-lif-A"
388388
mock_interface_a.address = "192.168.1.10/24"
389389
mock_interface_a.vlan = 100
390390

391391
mock_interface_b = MagicMock()
392-
mock_interface_b.name = "N1-test-B"
392+
mock_interface_b.name = "N1-lif-B"
393393
mock_interface_b.address = "192.168.1.11/24"
394394
mock_interface_b.vlan = 100
395395

@@ -413,7 +413,7 @@ def test_from_nautobot_response_default_prefix(self, valid_config_file):
413413

414414
# Create a mock nautobot response
415415
mock_interface = MagicMock()
416-
mock_interface.name = "N1-test-A"
416+
mock_interface.name = "N1-lif-A"
417417
mock_interface.address = "192.168.1.10/24"
418418
mock_interface.vlan = 100
419419

python/understack-workflows/tests/test_netapp_configure_net_integration.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -491,13 +491,6 @@ def test_end_to_end_workflow_with_various_input_combinations(
491491
# Mock successful GraphQL response (use single interface sample)
492492
mock_response = Mock()
493493
sample_data = load_json_sample("nautobot_graphql_vm_response_single.json")
494-
# Customize the interface name for this test case
495-
sample_data["data"]["virtual_machines"][0]["interfaces"][0]["name"] = (
496-
f"interface-{test_case['name']}"
497-
)
498-
sample_data["data"]["virtual_machines"][0]["interfaces"][1]["name"] = (
499-
f"interface-{test_case['name']}-B"
500-
)
501494
mock_response.json = sample_data
502495

503496
# Mock NetAppManager

python/understack-workflows/tests/test_netapp_lif_service.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def lif_service(self, mock_client, mock_error_handler):
3838
def sample_config(self):
3939
"""Create a sample NetappIPInterfaceConfig for testing."""
4040
return NetappIPInterfaceConfig(
41-
name="N1-test-A",
41+
name="N1-lif-A",
4242
address=ipaddress.IPv4Address("192.168.1.10"),
4343
network=ipaddress.IPv4Network("192.168.1.0/24"),
4444
vlan_id=100,
@@ -203,7 +203,7 @@ def test_identify_home_node_success(
203203
]
204204
mock_client.get_nodes.return_value = mock_nodes
205205

206-
# sample_config has name "N1-test-A" which should match node-01
206+
# sample_config has name "N1-lif-A" which should match node-01
207207
result = lif_service.identify_home_node(sample_config)
208208

209209
assert result == mock_nodes[0] # node-01
@@ -214,7 +214,7 @@ def test_identify_home_node_n2_interface(
214214
):
215215
"""Test node identification for N2 interface."""
216216
config = NetappIPInterfaceConfig(
217-
name="N2-test-B",
217+
name="N2-lif-B",
218218
address=ipaddress.IPv4Address("192.168.1.11"),
219219
network=ipaddress.IPv4Network("192.168.1.0/24"),
220220
vlan_id=200,
@@ -343,10 +343,10 @@ def test_node_number_extraction_logic(
343343
):
344344
"""Test the node number extraction logic with various node names."""
345345
test_cases = [
346-
("node-01", "N1-test-A", 1),
347-
("node-02", "N2-test-B", 2),
348-
("cluster-node-01", "N1-test-A", 1),
349-
("netapp-node-02", "N2-test-B", 2),
346+
("node-01", "N1-lif-A", 1),
347+
("node-02", "N2-lif-B", 2),
348+
("cluster-node-01", "N1-lif-A", 1),
349+
("netapp-node-02", "N2-lif-B", 2),
350350
]
351351

352352
for node_name, interface_name, expected_number in test_cases:

python/understack-workflows/tests/test_netapp_manager.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ def test_create_lif_delegates_to_service(
177177
manager._lif_service.create_lif = MagicMock()
178178

179179
config_obj = NetappIPInterfaceConfig(
180-
name="N1-test-A",
180+
name="N1-lif-A",
181181
address=ipaddress.IPv4Address("192.168.1.10"),
182182
network=ipaddress.IPv4Network("192.168.1.0/24"),
183183
vlan_id=100,
@@ -313,7 +313,7 @@ def test_public_api_contract_maintained(
313313

314314
# Network-related methods
315315
config_obj = NetappIPInterfaceConfig(
316-
name="test",
316+
name="N1-lif-B",
317317
address=ipaddress.IPv4Address("192.168.1.1"),
318318
network=ipaddress.IPv4Network("192.168.1.0/24"),
319319
vlan_id=100,
@@ -332,7 +332,7 @@ class TestNetAppManagerValueObjects:
332332
def test_netmask_long(self):
333333
"""Test netmask_long method."""
334334
config = NetappIPInterfaceConfig(
335-
name="N1-storage-A",
335+
name="N1-lif-A",
336336
address=ipaddress.IPv4Address("192.168.1.10"),
337337
network=ipaddress.IPv4Network("192.168.1.0/24"),
338338
vlan_id=100,
@@ -342,15 +342,15 @@ def test_netmask_long(self):
342342
def test_side_property_extraction(self):
343343
"""Test side property extraction from interface names."""
344344
config_a = NetappIPInterfaceConfig(
345-
name="N1-test-A",
345+
name="N1-lif-A",
346346
address=ipaddress.IPv4Address("192.168.1.10"),
347347
network=ipaddress.IPv4Network("192.168.1.0/24"),
348348
vlan_id=100,
349349
)
350350
assert config_a.side == "A"
351351

352352
config_b = NetappIPInterfaceConfig(
353-
name="N1-test-B",
353+
name="N1-lif-B",
354354
address=ipaddress.IPv4Address("192.168.1.10"),
355355
network=ipaddress.IPv4Network("192.168.1.0/24"),
356356
vlan_id=100,
@@ -360,15 +360,15 @@ def test_side_property_extraction(self):
360360
def test_desired_node_number_extraction(self):
361361
"""Test node number extraction from interface names."""
362362
config_n1 = NetappIPInterfaceConfig(
363-
name="N1-test-A",
363+
name="N1-lif-A",
364364
address=ipaddress.IPv4Address("192.168.1.10"),
365365
network=ipaddress.IPv4Network("192.168.1.0/24"),
366366
vlan_id=100,
367367
)
368368
assert config_n1.desired_node_number == 1
369369

370370
config_n2 = NetappIPInterfaceConfig(
371-
name="N2-test-B",
371+
name="N2-lif-B",
372372
address=ipaddress.IPv4Address("192.168.1.10"),
373373
network=ipaddress.IPv4Network("192.168.1.0/24"),
374374
vlan_id=100,

python/understack-workflows/tests/test_netapp_manager_integration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ def test_backward_compatibility_maintained(
443443
)
444444

445445
config_obj = NetappIPInterfaceConfig(
446-
name="test",
446+
name="N3-lif-A",
447447
address=ipaddress.IPv4Address("192.168.1.1"),
448448
network=ipaddress.IPv4Network("192.168.1.0/24"),
449449
vlan_id=100,

python/understack-workflows/tests/test_netapp_value_objects.py

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -913,55 +913,42 @@ def test_malformed_interface_names_for_side_detection(self):
913913
"N1-test-1", # Numeric suffix instead of letter
914914
"N1-test-X", # Invalid side letter
915915
"test", # No side at all
916+
"",
916917
]
917918

918919
for invalid_name in invalid_names_for_side:
919-
config = NetappIPInterfaceConfig(
920-
name=invalid_name,
921-
address="192.168.1.10", # type: ignore[arg-type]
922-
network="192.168.1.0/24", # type: ignore[arg-type]
923-
vlan_id=100,
924-
)
925-
# The error should occur when accessing the computed field
926-
with pytest.raises(
927-
ValueError, match="Cannot determine side from interface"
928-
):
920+
with pytest.raises(ValueError):
921+
config = NetappIPInterfaceConfig(
922+
name=invalid_name,
923+
address="192.168.1.10", # type: ignore[arg-type]
924+
network="192.168.1.0/24", # type: ignore[arg-type]
925+
vlan_id=100,
926+
)
929927
_ = config.side
930928

931-
# Test empty name separately as it causes IndexError
932-
config_empty = NetappIPInterfaceConfig(
933-
name="",
934-
address="192.168.1.10", # type: ignore[arg-type]
935-
network="192.168.1.0/24", # type: ignore[arg-type]
936-
vlan_id=100,
937-
)
938-
with pytest.raises((ValueError, IndexError)):
939-
_ = config_empty.side
940-
941929
def test_malformed_interface_names_for_node_detection(self):
942930
"""Test interface names that cannot determine node number."""
943931
from understack_workflows.netapp.value_objects import NetappIPInterfaceConfig
944932

945-
# Test names that can't determine node number
933+
# Test names that can't determine node number or side
946934
invalid_names_for_node = [
947935
"X1-test-A", # Invalid node prefix
948936
"N3-test-A", # Unsupported node number
949937
"test-A", # Missing node prefix
950938
"N-test-A", # Missing node number
939+
"N1-blah", # Missing side
951940
"", # Empty name
952941
]
953942

954943
for invalid_name in invalid_names_for_node:
955-
config = NetappIPInterfaceConfig(
956-
name=invalid_name,
957-
address="192.168.1.10", # type: ignore[arg-type]
958-
network="192.168.1.0/24", # type: ignore[arg-type]
959-
vlan_id=100,
960-
)
961944
# The error should occur when accessing the computed field
962-
with pytest.raises(
963-
ValueError, match="Cannot determine node index from name"
964-
):
945+
with pytest.raises(ValueError):
946+
config = NetappIPInterfaceConfig(
947+
name=invalid_name,
948+
address="192.168.1.10", # type: ignore[arg-type]
949+
network="192.168.1.0/24", # type: ignore[arg-type]
950+
vlan_id=100,
951+
)
965952
_ = config.desired_node_number
966953

967954

python/understack-workflows/understack_workflows/netapp/value_objects.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from ipaddress import IPv4Network
1010

1111
from pydantic import BaseModel
12+
from pydantic import Field
1213
from pydantic import ConfigDict
1314
from pydantic import computed_field
1415
from pydantic import field_validator
@@ -104,7 +105,7 @@ def from_graphql_vm(cls, vm_data: dict) -> "VirtualMachineNetworkInfo":
104105
class NetappIPInterfaceConfig(BaseModel):
105106
"""Configuration for NetApp IP interface creation."""
106107

107-
name: str
108+
name: str = Field(pattern=r'^N\d-lif-(A|B)$')
108109
address: IPv4Address
109110
network: IPv4Network
110111
vlan_id: int

0 commit comments

Comments
 (0)