Skip to content
This repository has been archived by the owner on Nov 21, 2024. It is now read-only.

Commit

Permalink
dev-uxmt: Fix discovered migration flow issues (#756)
Browse files Browse the repository at this point in the history
* Static IP address with device specific value converted to dynamic IP address #67

* Migration Feature Template with IPSec route fails #60

* KeyError: 'aggregate_only' during Cisco VPN feature template migration #59

* Constant value convernted to variable value for integrity-type from Cisco Secuirty feature template #58

* Incorrect value for static IPv4 address after migration to ux2 #57

* Fix imports

* Fix: entire lan ethernet interface. fix attribute error when checking for vpn id value

* Fix whitespace

* Minor fixes

* Support banner and snmp

* fix: asPath parameter and conversion for Route Policy

* bump version

---------

Co-authored-by: Szymon Basan <[email protected]>
  • Loading branch information
jpkrajewski and sbasan authored Jul 11, 2024
1 parent 82abf3f commit 121ba1d
Show file tree
Hide file tree
Showing 25 changed files with 510 additions and 222 deletions.
56 changes: 28 additions & 28 deletions ENDPOINTS.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,16 @@
from catalystwan.models.configuration.feature_profile.sdwan.service.lan.ipsec import InterfaceIpsecParcel
from catalystwan.models.configuration.feature_profile.sdwan.service.lan.multilink import InterfaceMultilinkParcel
from catalystwan.models.configuration.feature_profile.sdwan.service.lan.svi import InterfaceSviParcel
from catalystwan.models.configuration.feature_profile.sdwan.service.lan.vpn import LanVpnParcel
from catalystwan.models.configuration.feature_profile.sdwan.service.lan.vpn import (
IPv4Prefix,
LanVpnParcel,
OmpAdvertiseIPv4,
ProtocolIPv4,
RoutePrefix,
ServiceRoute,
StaticGreRouteIPv4,
StaticIpsecRouteIPv4,
)
from catalystwan.models.configuration.feature_profile.sdwan.service.multicast import (
AutoRpAttributes,
BsrCandidateAttributes,
Expand Down Expand Up @@ -140,6 +149,40 @@ def test_when_default_values_service_vpn_parcel_expect_successful_post(self):
parcel_name="TestVpnParcel",
parcel_description="Test Vpn Parcel",
vpn_id=Global[int](value=2),
ipsec_route=[
StaticIpsecRouteIPv4(
prefix=RoutePrefix(ip_address=as_global("1.2.3.4"), subnet_mask=as_global("0.0.0.0")),
)
],
gre_route=[
StaticGreRouteIPv4(
prefix=RoutePrefix(
ip_address=as_global("8.6.5.4"),
subnet_mask=as_global("255.255.255.0"),
)
)
],
service_route=[
ServiceRoute(
prefix=RoutePrefix(
ip_address=as_global("8.6.5.2"),
subnet_mask=as_global("255.255.255.0"),
)
)
],
omp_advertise_ipv4=[
OmpAdvertiseIPv4(
omp_protocol=Global[ProtocolIPv4](value="aggregate"),
prefix_list=[
IPv4Prefix(
prefix=AddressWithMask(
address=as_global("10.3.2.1"),
mask=as_global("255.255.255.0"),
)
)
],
)
],
)
# Act
parcel_id = self.api.create_parcel(self.profile_uuid, vpn_parcel).id
Expand Down
1 change: 0 additions & 1 deletion catalystwan/models/configuration/feature_profile/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Copyright 2024 Cisco Systems, Inc. and its affiliates
# Copyright 2023 Cisco Systems, Inc. and its affiliates

from datetime import datetime
from ipaddress import IPv4Address, IPv4Interface, IPv6Address, IPv6Interface
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2023 Cisco Systems, Inc. and its affiliates
# Copyright 2024 Cisco Systems, Inc. and its affiliates

from ipaddress import IPv4Address, IPv6Address, IPv6Interface
from typing import List, Literal, Optional, Union
Expand Down Expand Up @@ -132,7 +132,9 @@ class OmpAdvertiseIPv4(BaseModel):
route_policy: Optional[Union[Default[None], Global[UUID]]] = Field(
serialization_alias="routePolicy", validation_alias="routePolicy", default=None
)
prefix_list: Optional[List[IPv4Prefix]] = None
prefix_list: Optional[List[IPv4Prefix]] = Field(
default=None, serialization_alias="prefixList", validation_alias="prefixList"
)


class OmpAdvertiseIPv6(BaseModel):
Expand Down Expand Up @@ -342,7 +344,7 @@ class Service(BaseModel):
class ServiceRoute(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True, populate_by_name=True)

prefix: AddressWithMask
prefix: RoutePrefix
service: Union[Variable, Global[ServiceRouteType], Default[ServiceRouteType]] = Default[ServiceRouteType](
value="SIG"
)
Expand All @@ -355,15 +357,15 @@ class ServiceRoute(BaseModel):
class StaticGreRouteIPv4(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True, populate_by_name=True)

prefix: AddressWithMask
prefix: RoutePrefix
interface: Union[Variable, Global[List[str]], Default[None]] = Default[None](value=None)
vpn: Global[int] = Global[int](value=0)


class StaticIpsecRouteIPv4(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True, populate_by_name=True)

prefix: AddressWithMask
prefix: RoutePrefix
interface: Union[Variable, Global[List[str]], Default[None]] = Default[None](value=None)


Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Copyright 2024 Cisco Systems, Inc. and its affiliates
from __future__ import annotations

from typing import List, Literal, Optional, Union

from pydantic import AliasPath, BaseModel, ConfigDict, Field

from catalystwan.api.configuration_groups.parcel import Default, Global, Variable, _ParcelBase, as_default, as_variable
from catalystwan.api.configuration_groups.parcel import Default, Global, Variable, _ParcelBase, as_default

IntegrityType = Literal["esp", "ip-udp-esp", "none", "ip-udp-esp-no-id"]
ReplayWindow = Literal["64", "128", "256", "512", "1024", "2048", "4096", "8192"]
Expand Down Expand Up @@ -44,7 +45,7 @@ class OneOfendChoice3(BaseModel):
extra="forbid",
populate_by_name=True,
)
exact: Global[float] = Field(..., description="Configure Key lifetime end time")
exact: Global[int] = Field(..., description="Configure Key lifetime end time")


class SendLifetime(BaseModel):
Expand All @@ -59,7 +60,7 @@ class SendLifetime(BaseModel):
local: Optional[Union[Variable, Global[bool], Default[bool]]] = Field(
default=None, description="Configure Send lifetime Local"
)
start_epoch: Global[float] = Field(
start_epoch: Global[int] = Field(
...,
serialization_alias="startEpoch",
validation_alias="startEpoch",
Expand All @@ -82,7 +83,7 @@ class AcceptLifetime(BaseModel):
local: Optional[Union[Variable, Global[bool], Default[bool]]] = Field(
default=None, description="Configure Send lifetime Local"
)
start_epoch: Global[float] = Field(
start_epoch: Global[int] = Field(
...,
serialization_alias="startEpoch",
validation_alias="startEpoch",
Expand All @@ -101,7 +102,7 @@ class KeyItem(BaseModel):
id: Global[int] = Field(..., description="Select the Key ID")
name: Global[str] = Field(..., description="Select the chain name")
send_id: Union[Global[int], Variable] = Field(
..., serialization_alias="recvId", validation_alias="srecvId", description="Specify the Send ID"
..., serialization_alias="sendId", validation_alias="sendId", description="Specify the Send ID"
)
recv_id: Union[Global[int], Variable] = Field(
..., serialization_alias="recvId", validation_alias="recvId", description="Specify the Receiver ID"
Expand Down Expand Up @@ -162,7 +163,6 @@ class SecurityParcel(_ParcelBase):
description="Extended Anti-Replay Window",
)
integrity_type: Union[Global[List[IntegrityType]], Variable] = Field(
default=as_variable("{{security_auth_type_inte}}"),
validation_alias=AliasPath("data", "integrityType"),
description="Set the authentication type for DTLS connections",
)
Expand Down
4 changes: 2 additions & 2 deletions catalystwan/models/policy/policy_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ class AsPathListMatchEntry(BaseModel):


class AsPathActionEntryValue(BaseModel):
prepend: SpaceSeparatedNonNegativeIntList
exclude: SpaceSeparatedNonNegativeIntList
prepend: Optional[SpaceSeparatedNonNegativeIntList] = None
exclude: Optional[SpaceSeparatedNonNegativeIntList] = None


class AsPathActionEntry(BaseModel):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


class BannerConverter(FTConverter):
supported_template_types = ("cisco_banner",)
supported_template_types = ("cisco_banner", "banner")

def create_parcel(self, name: str, description: str, template_values: dict) -> BannerParcel:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ def convert(self, name: str, description: str, template_values: dict) -> Convert
parcel = self.create_parcel(name, description, template_values)
self._convert_result.output = parcel
except (CatalystwanConverterCantConvertException, AttributeError, LookupError, TypeError, ValueError) as e:
self._convert_result.update_status("failed", str(e))
self._convert_result.update_status("failed", str(e.__class__.__name__ + ": " + str(e)))
return self._convert_result
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,6 @@ def parse_prefix(self, address: Optional[Union[Variable, Global[IPv4Interface]]]
return AddressWithMask(address=address, mask=address)

return AddressWithMask(
address=as_global(address.value.network.network_address),
address=as_global(address.value.ip),
mask=as_global(str(address.value.netmask)),
)
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def _set_summary_addresses(self, values: dict) -> List[SummaryAddress]:
def _set_summary_address(self, addr: dict) -> SummaryAddress:
return SummaryAddress(
prefix=AddressWithMask(
address=as_global(addr["prefix"].value.network.network_address),
address=as_global(addr["prefix"].value.ip),
mask=as_global(str(addr["prefix"].value.netmask)),
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Copyright 2024 Cisco Systems, Inc. and its affiliates
from typing import Optional, Type, TypeVar, Union

from catalystwan.api.configuration_groups.parcel import Global, OptionType, Variable

T = TypeVar("T")


def create_dict_without_none(**kwargs) -> dict:
"""Create a dictionary without None values.
This speeds up the converting because we don't need to check for None values.
If pydantic model input doesn't have a key:value pair, it will use a default value."""
return {k: v for k, v in kwargs.items() if v is not None}


def return_global_variable_or_none(
data: dict, key: str, global_type: Type[Global[T]]
) -> Optional[Union[Global[T], Variable]]:
"""Return a Global or Variable object from the data dictionary or None if the key doesn't exist."""
value = data.get(key)
if value is None:
return None
return global_type(value=value.value) if value.option_type == OptionType.GLOBAL else value
Loading

0 comments on commit 121ba1d

Please sign in to comment.