Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uc voice builder #10

Merged
merged 5 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 <kagorski@cisco.com>"]
readme = "README.md"
Expand Down
Loading