diff --git a/docs/reporef/index.rst b/docs/reporef/index.rst index cc43f063..96ac2aeb 100644 --- a/docs/reporef/index.rst +++ b/docs/reporef/index.rst @@ -403,7 +403,7 @@ Keys for interfaces.yml or interfaces_.yml: * Additional interface options for port_template type: * untagged_vlan: Optional. Numeric VLAN ID for untagged frames. - * tagged_vlan_list: Optional. List of allowed numeric VLAN IDs for tagged frames. + * tagged_vlan_list: Optional. List of allowed VLAN IDs, can be single values or ranges, ex: [1, 5, "10-15"] * description: Optional. Description for the interface, this should be a string 0-64 characters. * enabled: Optional. Set the administrative state of the interface. Defaults to true if not set. * aggregate_id: Optional. Identifier for configuring LACP etc. Integer value. diff --git a/src/cnaas_nms/db/settings.py b/src/cnaas_nms/db/settings.py index 9efcdd7b..c6354f85 100644 --- a/src/cnaas_nms/db/settings.py +++ b/src/cnaas_nms/db/settings.py @@ -38,7 +38,6 @@ def get_settings_root(): f_root = get_settings_root() - redis_client = StrictRedis( host=app_settings.REDIS_HOSTNAME, port=app_settings.REDIS_PORT, retry_on_timeout=True, socket_keepalive=True ) @@ -193,6 +192,8 @@ def get_pydantic_error_value(data: dict, loc: tuple): try: obj = data for item in loc: + if type(obj) is str: + return obj obj = obj[item] except KeyError: return None diff --git a/src/cnaas_nms/db/settings_fields.py b/src/cnaas_nms/db/settings_fields.py index b9150717..b3943c29 100644 --- a/src/cnaas_nms/db/settings_fields.py +++ b/src/cnaas_nms/db/settings_fields.py @@ -1,5 +1,5 @@ from ipaddress import AddressValueError, IPv4Interface -from typing import Annotated, Dict, List, Optional +from typing import Annotated, Dict, List, Optional, Union from pydantic import BaseModel, Field, FieldValidationInfo, conint, field_validator from pydantic.functional_validators import AfterValidator @@ -131,6 +131,15 @@ class f_evpn_peer(BaseModel): hostname: str = hostname_schema +def vlan_range_check(v: str): + if "-" in v: + start, end = v.split("-") + assert int(start) < int(end), "Start of range must be less than end of range" + assert int(start) >= 1 and int(end) <= 4095, "VLAN IDs in range must be between 1-4095" + else: + assert 1 <= int(v) <= 4095, "VLAN IDs in range must be between 1-4095" + + class f_interface(BaseModel): name: str = ifname_range_schema ifclass: str = ifclass_schema @@ -139,7 +148,10 @@ class f_interface(BaseModel): description: Optional[str] = ifdescr_schema enabled: Optional[bool] = None untagged_vlan: Optional[int] = vlan_id_schema_optional - tagged_vlan_list: Optional[List[Annotated[int, Field(ge=1, le=4094)]]] = None + # tagged vlan list can be list of vlans IDs or ranges of VLAN IDs ("1-10") + tagged_vlan_list: Optional[ + List[Union[Annotated[int, Field(ge=1, le=4095)], Annotated[str, AfterValidator(vlan_range_check)]]] + ] = None aggregate_id: Optional[int] = None tags: Optional[List[str]] = None vrf: Optional[str] = vlan_name_schema