Skip to content

Commit

Permalink
Adding SIP routing functionality to PhoneNumbers SDK (#22805)
Browse files Browse the repository at this point in the history
* Initial commit

* Copied shared files

* Added basic functionality to the sip client.

* Copied shared folder to get the utilities. Implemented sample files. Changed naming in client

* Modified function comments and added class comment for _sip_routing_client.

* Fixed kwargs propagation

* Changed sample file to pull parameteres from environment variables.

* Changed get SIP configuration sample to be a class to align with the update samples. Changed naming of the update samples class.

* Implemented basic tests for the SIP client

* Removed unused import

* Fixed comment.

* Renamed variables dut_client to test_client.

* Merge from original repo

* Feature/communication sip configuration dev/basic client functionality (#3)

Adding async client.

* Updated from original (#4)

Updated from main repo.

* Fixing pylint

* Changed value error to be compatible with python 2.

* Reverted changes for pylint.

* Fixed dev requirements and MANIFEST

* Fixing async tests. Fixing comments.

* Removed async mock to be compatible with the builds.

* Fixing test failures for Ubuntu and Mac

* Changed versions for python. Fixed pylint issue in version.

* Modified _version file to prevent path errors.

* Added newline.

* Downgraded six version to match the frozen  requirements.

* Fixed async test errors by excluding asynchronous tests for python 2.7.

* Regenerated by autorest

* Updated swagger definition.

* Squashed commit of the following:

commit 3d7c16a5355a6461a4e688e89410a735dfdcfcce
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Mon Jun 7 17:50:06 2021 +0200

    Added e2e and recordings of the tests.

commit 3f92f30afc5e932b2834a337401f51231abfb602
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Mon Jun 7 17:39:44 2021 +0200

    Renamed communication testcase and async communication testcase.

commit 6f92a5aaf37c94878aedbfa4a505282e17041ff8
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Mon Jun 7 17:25:47 2021 +0200

    Fixed sanitized url to have .net instead of .com .

commit 6e1ab5e228452b3bb29d9ec01b13a779cb6103c2
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Mon Jun 7 17:25:04 2021 +0200

    Fixed async client to have all the needed asynchronous behaviour

commit a3ce07361fbab9f0fb335cd35379009486382786
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Mon Jun 7 09:23:29 2021 +0200

    Split the testcase and request replacer processor into two files.

commit 26026c256bff0cd186f38656e0477f466e7e5d02
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Mon Jun 7 08:18:44 2021 +0200

    Modified paths to fake credential tokens to reflect teh changed naming.

commit fdda1dd10f57b1f67a354fc844b8f5346d1ba200
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Mon Jun 7 08:17:29 2021 +0200

    Added dev requirement

commit 2967dff8a91067cacdf34fb3047e5a992be1721b
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Mon Jun 7 08:17:10 2021 +0200

    Renamed mocks to testcases

commit 16b55c29ba7570d00e4ed1780f60da83e852258d
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Fri Jun 4 11:38:12 2021 +0200

    Renamed variable names for sip configuration

commit 63b338e3ea22e6a9c691e7a4f42663d03af5756c
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Fri Jun 4 10:45:37 2021 +0200

    Renamed methods of sip routing client

commit f709b26d646df3b9b98506af22185d800c02234a
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Fri Jun 4 10:20:49 2021 +0200

    Modified clients to allow for credentials.

commit ea8d1323fcfa069e066d52521a4f08f08dffe871
Author: Jiri Burant <83883278+jiriburant@users.noreply.github.com>
Date:   Fri Jun 4 10:14:02 2021 +0200

    Initial Readms

* Fixed readme links and formatting. Added sdk_moniker for client

* Refactored authentication files. AAdded response sanitization.

* Fixed linting issues.

* Modified version to beta.

* Regenerated swagger with latest definitions, implemented missing async sample files.

* Fixing lint issues.

* Fixed pylint disable comment.

* Renamed sip routing client to match the conventions and updated tests.

* Removed -Patch from public namespace.

* Addressing comments from api review

* Removed older files in separate package

* Updated version for azure.core to support newly generated code.

* Implemented swagger definition for SIP routing

* Implemented SIP routing logic

* Implemented siprouting changes

* Added new types to public package

* Changed phone numbers test to work with package structure

* prepared recordings for sip routing

* Added internal and public version of SipTrunk to accomodate for fqdn parameter. Changed public client interface to have functions separately for trunks/routes.

* Fixing formatting.

* Changed public interface.

* Recordings of e2e tests.

* Addressing comments from second internal review.

* Minor changes in cleaning up code. Added a few sample calls.

* Added test for token auth

* Implemented inputs from api review

* Fixed linting issues and credential  issues.

* Fixed test recordings.

* Removed test credentials.

* Moved siprouting tests to common namespace and removed packaging on tests.

* Changed token authorization test to work in recorded mode.
Fixed dependencies in setup.py file

* Restored setup.py file to avoid package clashes.

* Regenerated code with lower version of autorest to pass build validation.

* Renamed replace_trunks and replace_routes to set_trunks, set_routes

* Renamed recordings of tests.

* Added more tests for managed identity. Updated README and Changelog.

* Updated version.

* Addressing comments from review.

* Removing forgotten credential.

* Addressing comments from review
  • Loading branch information
jiriburant authored Jun 23, 2022
1 parent 570cfb1 commit 7058612
Show file tree
Hide file tree
Showing 76 changed files with 9,632 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# Release History
## 1.1.0b3 (Unreleased)
- Users can now manage SIP configuration for Direct routing.

### Features Added
- Added new SIP routing client for handling Direct routing numbers.

## 1.1.0b2 (2022-03-30)

Expand Down
117 changes: 104 additions & 13 deletions sdk/communication/azure-communication-phonenumbers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,18 @@ pip install azure-communication-phonenumbers

## Key concepts

### Initializing Phone Numbers Client
This SDK provides functionality to easily manage `direct offer` and `direct routing` numbers.

The `direct offer` numbers come in two types: Geographic and Toll-Free. Geographic phone plans are phone plans associated with a location, whose phone numbers' area codes are associated with the area code of a geographic location. Toll-Free phone plans are phone plans not associated location. For example, in the US, toll-free numbers can come with area codes such as 800 or 888.
They are managed using the `PhoneNumbersClient`

The `direct routing` feature enables connecting your existing telephony infrastructure to ACS.
The configuration is managed using the `SipRoutingClient`, which provides methods for setting up SIP trunks and voice routing rules, in order to properly handle calls for your telephony subnet.

### Initializing Client
Client can be initialized using the AAD authentication.

```python
# You can find your connection string from your resource in the Azure Portal
import os
from azure.communication.phonenumbers import PhoneNumbersClient
from azure.identity import DefaultAzureCredential
Expand All @@ -31,10 +40,20 @@ endpoint = "https://<RESOURCE_NAME>.communication.azure.com"
# To use Azure Active Directory Authentication (DefaultAzureCredential) make sure to have your
# AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET as env variables.
phone_numbers_client = PhoneNumbersClient(endpoint, DefaultAzureCredential())
```

```python
import os
from azure.communication.phonenumbers.siprouting import SipRoutingClient
from azure.identity import DefaultAzureCredential

endpoint = "https://<RESOURCE_NAME>.communication.azure.com"
# To use Azure Active Directory Authentication (DefaultAzureCredential) make sure to have your
# AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET as env variables.
sip_routing_client = SipRoutingClient(endpoint, DefaultAzureCredential())
```
### Initializing the Client Using Your Connection String
Connection string authentication is also available for Phone Numbers Client.

Another option is to initialize the client using connection string of the resource.

```python
# You can find your connection string from your resource in the Azure Portal
Expand All @@ -45,19 +64,39 @@ connection_str = "endpoint=ENDPOINT;accessKey=KEY"
phone_numbers_client = PhoneNumbersClient.from_connection_string(connection_str)
```

### Phone Number Types overview
```python
# You can find your connection string from your resource in the Azure Portal
import os
from azure.communication.phonenumbers.siprouting import SipRoutingClient

connection_str = "endpoint=ENDPOINT;accessKey=KEY"
sip_routing_client = SipRoutingClient.from_connection_string(connection_str)
```

### Phone numbers client

#### Phone number types overview

Phone numbers come in two types; Geographic and Toll-Free. Geographic phone numbers are phone numbers associated with a location, whose area codes are associated with the area code of a geographic location. Toll-Free phone numbers are phone numbers with no associated location. For example, in the US, toll-free numbers can come with area codes such as 800 or 888.

### Searching and Purchasing and Releasing numbers
#### Searching and Purchasing and Releasing numbers

Phone numbers can be searched through the search creation API by providing an area code, quantity of phone numbers, application type, phone number type, and capabilities. The provided quantity of phone numbers will be reserved for ten minutes and can be purchased within this time. If the search is not purchased, the phone numbers will become available to others after ten minutes. If the search is purchased, then the phone numbers are acquired for the Azure resources.

Phone numbers can also be released using the release API.

### SIP routing client

Direct routing feature allows connecting customer-provided telephony infrastructure to Azure Communication Resources. In order to setup routing configuration properly, customer needs to supply the SIP trunk configuration and SIP routing rules for calls. SIP routing client provides the necessary interface for setting this configuration.

When the call arrives, system tries to match the destination number with regex number patterns of defined routes. The first route to match the number will be selected. The order of regex matching is the same as the order of routes in configuration, therefore the order of routes matters.
Once a route is matched, the call is routed to the first trunk in the route's trunks list. If the trunk is not available, next trunk in the list is selected.

## Examples

### Get All Purchased Phone Numbers
### PhoneNumbersClient

#### Get All Purchased Phone Numbers

Lists all of your purchased phone numbers

Expand All @@ -67,7 +106,7 @@ for acquired_phone_number in purchased_phone_numbers:
print(acquired_phone_number.phone_number)
```

### Get Purchased Phone Number
#### Get Purchased Phone Number

Gets the information from the specified phone number

Expand All @@ -77,11 +116,11 @@ print(result.country_code)
print(result.phone_number)
```

## Long Running Operations
### Long Running Operations

The Phone Number Client supports a variety of long running operations that allow indefinite polling time to the functions listed down below.

### Search for Available Phone Number
#### Search for Available Phone Number

You can search for available phone numbers by providing the capabilities of the phone you want to acquire, the phone number type, the assignment type, and the country code. It's worth mentioning that for the toll-free phone number type, proving the area code is optional.
The result of the search can then be used to purchase the number in the corresponding API.
Expand All @@ -103,7 +142,7 @@ poller = phone_numbers_client.begin_search_available_phone_numbers(
search_result = poller.result()
```

### Purchase Phone Numbers
#### Purchase Phone Numbers

The result of your search can be used to purchase the specified phone numbers. This can be done by passing the `search_id` from the search response to the purchase phone number API.

Expand All @@ -114,7 +153,7 @@ purchase_poller = phone_numbers_client.begin_purchase_phone_numbers(
)
```

### Release Phone Number
#### Release Phone Number

Releases an acquired phone number.

Expand All @@ -125,7 +164,7 @@ poller = self.phone_number_client.begin_release_phone_number(
)
```

### Updating Phone Number Capabilities
#### Updating Phone Number Capabilities

Updates the specified phone number capabilities for Calling and SMS to one of:

Expand All @@ -143,6 +182,58 @@ poller = self.phone_number_client.begin_update_phone_number_capabilities(
)
```

### SipRoutingClient

#### Retrieve SIP trunks and routes

Get the list of currently configured trunks or routes.

```python
trunks = sip_routing_client.get_trunks()
for trunk in trunks:
print(trunk.fqdn)
print(trunk.sip_signaling_port)
routes = sip_routing_client.get_routes()
for route in routes:
print(route.name)
print(route.description)
print(route.number_pattern)
for trunk_fqdn in route.trunks:
print(trunk_fqdn)
```

#### Replace SIP trunks and routes

Replace the list of currently configured trunks or routes with new values.

```python
new_trunks = [SipTrunk(fqdn="sbs1.contoso.com", sip_signaling_port=1122), SipTrunk(fqdn="sbs2.contoso.com", sip_signaling_port=1123)]
new_routes = [SipTrunkRoute(name="First rule", description="Handle numbers starting with '+123'", number_pattern="\+123[0-9]+", trunks=["sbs1.sipconfigtest.com"])]
sip_routing_client.set_trunks(new_trunks)
sip_routing_client.set_routes(new_routes)
```

#### Retrieve single trunk

```python
trunk = sip_routing_client.get_trunk("sbs1.contoso.com")
```

#### Set single trunk

```python
# Set function will either modify existing item or add new item to the collection.
# The trunk is matched based on it's FQDN.
new_trunk = SipTrunk(fqdn="sbs3.contoso.com", sip_signaling_port=5555)
sip_routing_client.set_trunk(new_trunk)
```

#### Delete single trunk

```python
sip_routing_client.delete_trunk("sbs1.contoso.com")
```

# Troubleshooting
The Phone Numbers Administration client will raise exceptions defined in [Azure Core][azure_core].

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@
'PhoneNumberAssignmentType',
'PhoneNumberCapabilityType',
'PhoneNumberType',
'PhoneNumbersClient',
'PhoneNumbersClient'
]
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
# license information.
# --------------------------------------------------------------------------

VERSION = "1.1.0b2"
VERSION = "1.1.0b3"

SDK_MONIKER = "communication-phonenumbers/{}".format(VERSION) # type: str
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------


from ._sip_routing_client import SipRoutingClient
from ._generated.models import SipTrunkRoute
from ._models import SipTrunk

__all__ = [
'SipRoutingClient',
'SipTrunk',
'SipTrunkRoute'
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from ._sip_routing_service import SIPRoutingService
__all__ = ['SIPRoutingService']

# `._patch.py` is used for handwritten extensions to the generated code
# Example: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md
from ._patch import patch_sdk
patch_sdk()
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from typing import TYPE_CHECKING

from azure.core.configuration import Configuration
from azure.core.pipeline import policies

if TYPE_CHECKING:
# pylint: disable=unused-import,ungrouped-imports
from typing import Any

VERSION = "unknown"

class SIPRoutingServiceConfiguration(Configuration): # pylint: disable=too-many-instance-attributes
"""Configuration for SIPRoutingService.
Note that all parameters used to create this instance are saved as instance
attributes.
:param endpoint: The communication resource, for example
https://resourcename.communication.azure.com.
:type endpoint: str
:keyword api_version: Api Version. Default value is "2021-05-01-preview". Note that overriding
this default value may result in unsupported behavior.
:paramtype api_version: str
"""

def __init__(
self,
endpoint, # type: str
**kwargs # type: Any
):
# type: (...) -> None
super(SIPRoutingServiceConfiguration, self).__init__(**kwargs)
api_version = kwargs.pop('api_version', "2021-05-01-preview") # type: str

if endpoint is None:
raise ValueError("Parameter 'endpoint' must not be None.")

self.endpoint = endpoint
self.api_version = api_version
kwargs.setdefault('sdk_moniker', 'siproutingservice/{}'.format(VERSION))
self._configure(**kwargs)

def _configure(
self,
**kwargs # type: Any
):
# type: (...) -> None
self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs)
self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs)
self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs)
self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs)
self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs)
self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs)
self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs)
self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs)
self.authentication_policy = kwargs.get('authentication_policy')
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# coding=utf-8
# --------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# --------------------------------------------------------------------------

# This file is used for handwritten extensions to the generated code. Example:
# https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md
def patch_sdk():
pass
Loading

0 comments on commit 7058612

Please sign in to comment.