Skip to content

Commit

Permalink
Merge pull request #10 from cisco-en-programmability/uc-voice-builder
Browse files Browse the repository at this point in the history
Uc voice builder
  • Loading branch information
jpkrajewski authored Dec 3, 2024
2 parents ba94492 + e0b1fa5 commit 5664a66
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 2 deletions.
2 changes: 2 additions & 0 deletions catalystwan/api/builders/feature_profiles/builder_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from catalystwan.api.builders.feature_profiles.service import ServiceFeatureProfileBuilder
from catalystwan.api.builders.feature_profiles.system import SystemFeatureProfileBuilder
from catalystwan.api.builders.feature_profiles.transport import TransportAndManagementProfileBuilder
from catalystwan.api.builders.feature_profiles.uc_voice import UcVoiceFeatureProfileBuilder
from catalystwan.exceptions import CatalystwanException
from catalystwan.models.configuration.feature_profile.common import ProfileType

Expand All @@ -31,6 +32,7 @@
"transport": TransportAndManagementProfileBuilder,
"cli": CliFeatureProfileBuilder,
"application-priority": ApplicationPriorityFeatureProfileBuilder,
"uc-voice": UcVoiceFeatureProfileBuilder,
}


Expand Down
116 changes: 116 additions & 0 deletions catalystwan/api/builders/feature_profiles/uc_voice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Copyright 2024 Cisco Systems, Inc. and its affiliates
from __future__ import annotations

import logging
from dataclasses import dataclass
from typing import TYPE_CHECKING, List, Optional
from uuid import UUID

from catalystwan.api.builders.feature_profiles.report import FeatureProfileBuildReport, handle_build_report
from catalystwan.api.feature_profile_api import UcVoiceFeatureProfileAPI
from catalystwan.endpoints.configuration.feature_profile.sdwan.uc_voice import UcVoiceFeatureProfile
from catalystwan.models.configuration.feature_profile.common import FeatureProfileCreationPayload
from catalystwan.models.configuration.feature_profile.sdwan.uc_voice import (
AnyUcVoiceParcel,
TranslationProfileParcel,
TranslationRuleParcel,
)

logger = logging.getLogger(__name__)

if TYPE_CHECKING:
from catalystwan.session import ManagerSession


@dataclass
class TranslationProfile:
tpp: TranslationProfileParcel
calling: Optional[TranslationRuleParcel] = None
called: Optional[TranslationRuleParcel] = None


class UcVoiceFeatureProfileBuilder:
"""
A class for building UcVoice feature profiles.
"""

def __init__(self, session: ManagerSession) -> None:
"""
Initialize a new instance of the Service class.
Args:
session (ManagerSession): The ManagerSession object used for API communication.
profile_uuid (UUID): The UUID of the profile.
"""
self._profile: FeatureProfileCreationPayload
self._api = UcVoiceFeatureProfileAPI(session)
self._endpoints = UcVoiceFeatureProfile(session)
self._independent_items: List[AnyUcVoiceParcel] = []
self._translation_profiles: List[TranslationProfile] = []

def add_profile_name_and_description(self, feature_profile: FeatureProfileCreationPayload) -> None:
"""
Adds a name and description to the feature profile.
Args:
name (str): The name of the feature profile.
description (str): The description of the feature profile.
Returns:
None
"""
self._profile = feature_profile

def add_parcel(self, parcel: AnyUcVoiceParcel) -> None:
"""
Adds a parcel to the feature profile.
Args:
parcel (AnySystemParcel): The parcel to add.
Returns:
None
"""
self._independent_items.append(parcel)

def add_translation_profile(
self,
tpp: TranslationProfileParcel,
calling: Optional[TranslationRuleParcel] = None,
called: Optional[TranslationRuleParcel] = None,
):
if not calling and not called:
raise ValueError("There must be at least one translation rule to create a translation profile")
self._translation_profiles.append(TranslationProfile(tpp=tpp, called=called, calling=calling))

def build(self) -> FeatureProfileBuildReport:
"""
Builds the feature profile.
Returns:
UUID: The UUID of the created feature profile.
"""

profile_uuid = self._endpoints.create_uc_voice_feature_profile(self._profile).id
self.build_report = FeatureProfileBuildReport(profile_uuid=profile_uuid, profile_name=self._profile.name)
for parcel in self._independent_items:
self._create_parcel(profile_uuid, parcel)
for tp in self._translation_profiles:
self._create_translation_profile(profile_uuid, tp)

return self.build_report

@handle_build_report
def _create_parcel(self, profile_uuid: UUID, parcel: AnyUcVoiceParcel) -> UUID:
return self._api.create_parcel(profile_uuid, parcel).id

def _create_translation_profile(self, profile_uuid: UUID, tp: TranslationProfile):
if tp.called:
called_uuid = self._create_parcel(profile_uuid, tp.called)
if called_uuid:
tp.tpp.set_ref_by_call_type(called_uuid, "called")
if tp.calling:
calling_uuid = self._create_parcel(profile_uuid, tp.calling)
if calling_uuid:
tp.tpp.set_ref_by_call_type(calling_uuid, "calling")
self._create_parcel(profile_uuid, tp.tpp)
60 changes: 60 additions & 0 deletions catalystwan/integration_tests/profile_builder/test_pb_uc_voice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright 2024 Cisco Systems, Inc. and its affiliates
from catalystwan.api.configuration_groups.parcel import Global
from catalystwan.integration_tests.base import TestCaseBase, create_name_with_run_id
from catalystwan.models.configuration.feature_profile.common import FeatureProfileCreationPayload
from catalystwan.models.configuration.feature_profile.sdwan.uc_voice import (
TranslationProfileParcel,
TranslationRuleParcel,
)
from catalystwan.models.configuration.feature_profile.sdwan.uc_voice.translation_rule import Action, RuleSettings


class TestUcVoiceFeatureProfileBuilder(TestCaseBase):
def setUp(self) -> None:
self.fp_name = create_name_with_run_id("FeatureProfileBuilderUcVoice")
self.fp_description = "Transport feature profile"
self.builder = self.session.api.builders.feature_profiles.create_builder("uc-voice")
self.builder.add_profile_name_and_description(
feature_profile=FeatureProfileCreationPayload(name=self.fp_name, description=self.fp_description)
)
self.api = self.session.api.sdwan_feature_profiles.transport

def test_when_build_profile_with_translation_profile_and_rules_expect_success(self):
tp = TranslationProfileParcel(parcel_name="TPP", parcel_description="TTP_Desc", translation_profile_settings=[])
tr_calling = TranslationRuleParcel(
parcel_name="2",
parcel_description="desc",
rule_name=Global[int](value=2),
rule_settings=[
RuleSettings(
action=Global[Action](value="replace"),
match=Global[str](value="/123/"),
replacement_pattern=Global[str](value="/444/"),
rule_num=Global[int](value=2),
)
],
)
tr_called = TranslationRuleParcel(
parcel_name="4",
parcel_description="desc",
rule_name=Global[int](value=4),
rule_settings=[
RuleSettings(
action=Global[Action](value="replace"),
match=Global[str](value="/321/"),
replacement_pattern=Global[str](value="/4445/"),
rule_num=Global[int](value=4),
)
],
)
self.builder.add_translation_profile(tp, tr_calling, tr_called)
# Act
report = self.builder.build()
# Assert
assert len(report.failed_parcels) == 0

def tearDown(self) -> None:
target_profile = self.api.get_profiles().filter(profile_name=self.fp_name).single_or_default()
if target_profile:
# In case of a failed test, the profile might not have been created
self.api.delete_profile(target_profile.profile_id)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright 2024 Cisco Systems, Inc. and its affiliates
from typing import List, Literal, Optional, Union
from uuid import UUID

from pydantic import AliasPath, BaseModel, ConfigDict, Field

Expand Down Expand Up @@ -27,3 +28,15 @@ class TranslationProfileParcel(_ParcelBase):
validation_alias=AliasPath("data", "translationProfileSettings"),
description="Translation Profile configuration",
)

def set_ref_by_call_type(self, ref: UUID, ct: CallType) -> TranslationProfileSettings:
"""Set reference UUID to a calling or called rule item or create one and then set the UUID"""
tps = None
for tps_ in self.translation_profile_settings:
if isinstance(tps_.call_type, Global) and tps_.call_type.value == ct:
tps = tps_
if tps is None:
tps = TranslationProfileSettings(call_type=Global[CallType](value=ct))
self.translation_profile_settings.append(tps)
tps.translation_rule = RefIdItem.from_uuid(ref)
return tps
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ class TranslationRuleParcel(_ParcelBase):
validation_alias=AliasPath("data", "ruleSettings"),
description="Translation Rule configuration",
)
rule_name: Optional[Global[int]] = Field(default=None, validation_alias="ruleName", serialization_alias="ruleName")
rule_name: Optional[Global[int]] = Field(default=None, validation_alias=AliasPath("data", "ruleName"))
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "catalystwan"
version = "0.40.0dev2"
version = "0.40.0dev3"
description = "Cisco Catalyst WAN SDK for Python"
authors = ["kagorski <[email protected]>"]
readme = "README.md"
Expand Down

0 comments on commit 5664a66

Please sign in to comment.