Coverage for  / home / runner / work / netbox-InterfaceNameRules-plugin / netbox-InterfaceNameRules-plugin / netbox-InterfaceNameRules-plugin / netbox_interface_name_rules / api / serializers.py: 100%

17 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-02 15:19 +0000

1# SPDX-License-Identifier: Apache-2.0 

2# Copyright (C) 2025 Marcin Zieba <marcinpsk@gmail.com> 

3from netbox.api.serializers import NetBoxModelSerializer 

4from rest_framework import serializers 

5 

6from netbox_interface_name_rules.models import InterfaceNameRule 

7 

8 

9class InterfaceNameRuleSerializer(NetBoxModelSerializer): 

10 """Serializer for InterfaceNameRule with mutual-exclusivity validation.""" 

11 

12 class Meta: 

13 model = InterfaceNameRule 

14 fields = [ 

15 "id", 

16 "module_type", 

17 "module_type_pattern", 

18 "module_type_is_regex", 

19 "parent_module_type", 

20 "device_type", 

21 "platform", 

22 "name_template", 

23 "channel_count", 

24 "channel_start", 

25 "description", 

26 "enabled", 

27 "applies_to_device_interfaces", 

28 ] 

29 

30 def validate(self, attrs): 

31 """Ensure module_type XOR module_type_pattern depending on regex mode.""" 

32 attrs = super().validate(attrs) 

33 instance = self.instance 

34 

35 # For PATCH requests, fall back to existing instance values for fields not in attrs 

36 is_device_level = attrs.get( 

37 "applies_to_device_interfaces", getattr(instance, "applies_to_device_interfaces", False) 

38 ) 

39 is_regex = attrs.get("module_type_is_regex", getattr(instance, "module_type_is_regex", False)) 

40 module_type = attrs.get("module_type", getattr(instance, "module_type", None)) 

41 pattern = attrs.get("module_type_pattern", getattr(instance, "module_type_pattern", "")) 

42 

43 if is_device_level: 

44 # Device-level rules must not have a module_type FK 

45 if module_type: # pragma: no cover # model.clean() runs first 

46 raise serializers.ValidationError( 

47 {"module_type": "Module type must be empty for device-level interface rules."} 

48 ) 

49 elif is_regex: 

50 if not pattern: # pragma: no cover # model.clean() runs first 

51 raise serializers.ValidationError( 

52 {"module_type_pattern": "Regex pattern is required when regex mode is enabled."} 

53 ) 

54 if module_type: # pragma: no cover # model.clean() runs first 

55 raise serializers.ValidationError( 

56 {"module_type": "Cannot set both module_type and module_type_pattern. Choose one."} 

57 ) 

58 else: 

59 if not module_type: # pragma: no cover # model.clean() runs first 

60 raise serializers.ValidationError( 

61 {"module_type": "module_type is required when regex mode is disabled."} 

62 ) 

63 if pattern: # pragma: no cover # model.clean() runs first 

64 raise serializers.ValidationError( 

65 {"module_type_pattern": "Cannot set module_type_pattern when regex mode is disabled."} 

66 ) 

67 return attrs