17
17
from extras .models .customfields import CustomField
18
18
19
19
from .common import UnresolvedReference
20
+ from .compat import in_version_range
20
21
from .plugin_utils import content_type_id , get_object_type , get_object_type_model
21
22
22
23
logger = logging .getLogger (__name__ )
162
163
name = "logical_service_name_no_device_or_vm" ,
163
164
model_class = get_object_type_model ("ipam.service" ),
164
165
condition = Q (device__isnull = True , virtual_machine__isnull = True ),
166
+ max_version = "4.2.99" ,
165
167
),
166
168
ObjectMatchCriteria (
167
169
fields = ("name" , "device" ),
168
170
name = "logical_service_name_on_device" ,
169
171
model_class = get_object_type_model ("ipam.service" ),
170
172
condition = Q (device__isnull = False ),
173
+ max_version = "4.2.99" ,
171
174
),
172
175
ObjectMatchCriteria (
173
176
fields = ("name" , "virtual_machine" ),
174
177
name = "logical_service_name_on_vm" ,
175
178
model_class = get_object_type_model ("ipam.service" ),
176
179
condition = Q (virtual_machine__isnull = False ),
180
+ max_version = "4.2.99" ,
181
+ ),
182
+ ObjectMatchCriteria (
183
+ fields = ("name" , "parent_object_type" , "parent_object_id" ),
184
+ name = "logical_service_name_on_parent" ,
185
+ model_class = get_object_type_model ("ipam.service" ),
186
+ condition = Q (parent_object_type__isnull = False ),
187
+ min_version = "4.3.0"
177
188
),
178
189
],
179
190
"dcim.modulebay" : lambda : [
201
212
model_class = get_object_type_model ("ipam.fhrpgroup" ),
202
213
)
203
214
],
215
+ "tenancy.contact" : lambda : [
216
+ ObjectMatchCriteria (
217
+ # contacts are unconstrained in 4.3.0
218
+ # in 4.2 they are constrained by unique name per group
219
+ fields = ("name" , ),
220
+ name = "logical_contact_name" ,
221
+ model_class = get_object_type_model ("tenancy.contact" ),
222
+ min_version = "4.3.0" ,
223
+ )
224
+ ],
225
+ "dcim.devicerole" : lambda : [
226
+ ObjectMatchCriteria (
227
+ fields = ("name" ,),
228
+ name = "logical_device_role_name_no_parent" ,
229
+ model_class = get_object_type_model ("dcim.devicerole" ),
230
+ condition = Q (parent__isnull = True ),
231
+ min_version = "4.3.0" ,
232
+ ),
233
+ ObjectMatchCriteria (
234
+ fields = ("slug" ,),
235
+ name = "logical_device_role_slug_no_parent" ,
236
+ model_class = get_object_type_model ("dcim.devicerole" ),
237
+ condition = Q (parent__isnull = True ),
238
+ min_version = "4.3.0" ,
239
+ )
240
+ ],
204
241
}
205
242
206
243
@dataclass
@@ -223,6 +260,9 @@ class ObjectMatchCriteria:
223
260
model_class : type [models .Model ] | None = None
224
261
name : str | None = None
225
262
263
+ min_version : str | None = None
264
+ max_version : str | None = None
265
+
226
266
def __hash__ (self ):
227
267
"""Hash the object match criteria."""
228
268
return hash ((self .fields , self .expressions , self .condition , self .model_class .__name__ , self .name ))
@@ -414,6 +454,9 @@ class CustomFieldMatcher:
414
454
custom_field : str
415
455
model_class : type [models .Model ]
416
456
457
+ min_version : str | None = None
458
+ max_version : str | None = None
459
+
417
460
def fingerprint (self , data : dict ) -> str | None :
418
461
"""Fingerprint the custom field value."""
419
462
if not self .has_required_fields (data ):
@@ -450,6 +493,9 @@ class GlobalIPNetworkIPMatcher:
450
493
model_class : type [models .Model ]
451
494
name : str
452
495
496
+ min_version : str | None = None
497
+ max_version : str | None = None
498
+
453
499
def _check_condition (self , data : dict ) -> bool :
454
500
"""Check the condition for the custom field."""
455
501
return data .get (self .vrf_field , None ) is None
@@ -510,6 +556,9 @@ class VRFIPNetworkIPMatcher:
510
556
model_class : type [models .Model ]
511
557
name : str
512
558
559
+ min_version : str | None = None
560
+ max_version : str | None = None
561
+
513
562
def _check_condition (self , data : dict ) -> bool :
514
563
"""Check the condition for the custom field."""
515
564
return data .get (self .vrf_field , None ) is not None
@@ -584,6 +633,9 @@ class AutoSlugMatcher:
584
633
slug_field : str
585
634
model_class : type [models .Model ]
586
635
636
+ min_version : str | None = None
637
+ max_version : str | None = None
638
+
587
639
def fingerprint (self , data : dict ) -> str | None :
588
640
"""Fingerprint the custom field value."""
589
641
if not self .has_required_fields (data ):
@@ -649,7 +701,10 @@ def _get_autoslug_matchers(model_class) -> list:
649
701
@lru_cache (maxsize = 256 )
650
702
def _get_model_matchers (model_class ) -> list [ObjectMatchCriteria ]:
651
703
object_type = get_object_type (model_class )
652
- matchers = _LOGICAL_MATCHERS .get (object_type , lambda : [])()
704
+ matchers = [
705
+ x for x in _LOGICAL_MATCHERS .get (object_type , lambda : [])()
706
+ if in_version_range (x .min_version , x .max_version )
707
+ ]
653
708
654
709
# collect single fields that are unique
655
710
for field in model_class ._meta .fields :
0 commit comments