Creating a Backup Response Group for Lync Pool Failover

One of the common issues I have come across is the ability to have a failover Response Group Service when your primary Lync Pool becomes unavailable. Users have the ability to register to a secondary pool so they can still make and receive calls, but Response Groups currently have no failback or replication ability across pools to allow seamless functionality.

So how do we over come RGS failure? The basic solution I come up with is to create a second RGS on another pool and translate the inbound primary DID RGS number to a secondary DID number. This allows the incoming RGS number to be rerouted to an alternate Mediation Server. I guess you can call this a workaround of sorts but at the end of the day you want an inbound call to be answered by something rather than dead air and this workaround does provide a solution. There are a few issues that present themselves when considering a backup solution:

1) No two RGS work flows can have the same Tel URI.

2) For the purposes of outbound routing a gateway can only be associated with one Mediation Server or Mediation Pool.

3) Agents that were part of the original RGS call flow can not be part of our backup RGS unless they can still register with the Primary registrar, which we are assuming is down. This would mean that the RGS agents would now be registering with their secondary registrar and therefor have no presence availability. So for the purposes of this discussion we will assume that once the primary registrar pool is down our agents that were part of the original RGS are down for the purposes of taking part in the RGS back up service.

To work around these issue we need to consider three things. How do we translate our RGS inbound DID to a new number, how does the Mediation Server accepts inbound connections from Gateways not directly associated with it and lastly what do we do with the call once we have it in a new RGS service.

 

image

In our example we have two Mediation Server pools collocated with my Front Ends. I mentioned that outbound Mediation Servers are limited in the fact you can only associated a gateway against one pool but inbound a Mediation server will accept an inbound request from a gateway as long as it is part of the topology. It’s a handy little know fact that I come across when I wrote “Adding CUCM subscribers to Lync Topology Builder” post. 

Below is a basic set of outbound dial peers and translation rules that can be used for a Cisco gateway setup to provide DID service to Lync. In this case I am providing a basic route to a destination starting with 425 and only translating calls to the response group DID when using the backup dial peer. Its nothing to complicated. The preference command allow dial peers to hunt for an available Mediation Server. If you using AudioCodes or NET or another certified gateway they should all be able to provide similar hunt group functionality.

!
voice translation-rule 203
description Translate RGS to backup RGS
rule 1 /4255555551/ /4255555552/
!
voice translation-profile BackUpRGS
translate called 203

!
!dial-peer voice 101 voip
description to Lync Mediation server
preference 1
destination-pattern 425.......
session protocol sipv2
session target ipv4:10.10.10.11
session transport tcp
dtmf-relay rtp-nte
codec g711ulaw
no vad
!
!
dial-peer voice 102 voip
description to Lync Backup Mediation server
preference 10
translation-profile outbound BackUpRGS
destination-pattern 425.......
session protocol sipv2
session target ipv4:10.10.20.12
session transport tcp
dtmf-relay rtp-nte
codec g711ulaw
no vad

So now that you have delivered the number to a backup Mediation Server to be resolved it’s a matter of building a new RGS workflow to satisfy the need of the business. Of course this is a DR situation so your intention of whether to deliver it to a live person my differ but you have options of where to send the call:

  1. Create a agent group with new agents that will be available on the backup pool.
  2. Exchange UM group mailbox
  3. Exchange AA
  4. PSTN number to an alternate service with announcements to let callers know they are being rerouted
  5. etc, etc etc

So lots of options.

This is really just a solution born out of straight forward telecom engineering rather than a grand workaround. But if your new to telecom engineering this may be something that you hadn't considered before. Sometimes backup solutions are not all that fancy but still meet business requirements. Just because the RGS is not replicated across pools doesn’t mean your dead in the water.

What has been your back up to RGS service interruptions?

VoIPNorm

Cisco’s Mobility Chaos

We have all seen the Cisco mobile post by Michael Smith about how he was underwhelmed by Microsoft’s Lync mobile solution or the Cisco versus Microsoft post by Zeus but what are they not telling you about the Cisco’s solution? What does Cisco not want you to know?

To quote Michaels blog, “With Cisco Jabber, the UC capabilities are consistent across PC, Mac, tablets and phones.” But is it really? Lets take a look.

Cisco’s PC and MAC Story

While this blog post is mainly focused on Mobility I just wanted to highlight that Cisco’s patch work of clients tie you to their only available web conferencing solution and how Michaels statement really is a stretching the truth. And to be exact if I were to remove WebEx because Michael distinctly calls out Jabber it looks some what of a different story

With WebEx support:

  Windows Mac
Presence CUPC Jabber for Mac
IM CUPC Jabber for Mac
VoIP CUPC Jabber for Mac
Voicemail CUPC Jabber for Mac
Video CUPC or WebEx WebEx only
Desktop Sharing CUPC Jabber for Mac
App Sharing WebEx WebEx
Web Conferencing WebEx WebEx
Federation IM/P Only IM/P Only
VPN Less Connect No No

Without WebEx:

  Windows Mac
Presence CUPC Jabber for Mac
IM CUPC Jabber for Mac
VoIP CUPC Jabber for Mac
Voicemail CUPC/Jabber Jabber for Mac
Video CUPC/Jabber No
Desktop Sharing CUPC/Jabber Jabber for Mac
App Sharing No No
Web Conferencing No No
Federation IM/P Only IM/P Only
VPN Less Connect No No

So, no WebEx cloud = no Web Conferencing. Or do we need another client for that or is that another “it’s coming” moments?

Cisco’s Smartphone and Tablet Consistency

Below is what Cisco Jabber currently offers across the most popular platforms.

  iPhone iPad Android Phone/Tablet
Presence Jabber IM for iPhone No ( iPhone client) No
IM Jabber IM for iPhone No ( iPhone client) No
VoIP Jabber Voice for iPhone No ( iPhone client) Jabber for Android
Voicemail Jabber Voice for iPhone No ( iPhone client) No
Video WebEx for iPhone WebEx for iPad No
Desktop
Sharing
WebEx for iPhone
(view only)
WebEx for iPhone
(view only)
WebEx for Android
(View Only)
App
Sharing
WebEx for iPhone
(view only)
WebEx for iPhone
(view only)
WebEx for Android
(View Only)
Web Conferencing WebEx for iPhone WebEx for iPad WebEx for Android
(View Only)

 

WP7 BB Symbian
Presence No Jabber IM for BB Cisco Mobile for Nokia
IM No Jabber IM for BB Cisco Mobile for Nokia
VoIP No BBMVC Client Cisco Mobile for Nokia
Voicemail No No Cisco Mobile for Nokia
Video No No No
Desktop
Sharing
No WebEx for BB (View Only) WebEx for Nokia (View Only)
App
Sharing
No WebEx for BB WebEx for Nokia (View Only)
Web Conferencing No WebEx for BB WebEx for Nokia (View Only)

Looks pretty inconsistent to me with no on-premise solution for many of the options mentioned forcing you to only have a cloud option with WebEx. If you remove WebEx your left with only IM/P and voice but not consistently across all platforms. In fact, if video is the new voice then they have only one platform that delivers video with Jabber/CUPC and that is the Windows PC client. But isn't this the “Post PC era” according to Cisco? Well there is the Cius I guess but wait is that with Cisco Telepresence or Jabber, I am confused, maybe another app.

So I actually have a Android tablet that I use for testing and thought great I might actually download the Android application and give a spin in a lab where I have access to CUCM. Well its not that easy. I have an ASUS Tablet and Cisco’s Jabber only officially supports Samsung’s Galaxy Android devices. Bummer. I couldn’t even download the application on to my tablet to try it out. I just got a big warning that my device wasn’t compatible. So more limitations. But didn’t Michael say they had the most consistent story???

One Client To Rule Them All

Cisco Jabber

Cisco require multiple applications for Mobile UC- Jabber for IM, Jabber for VoIP and WebEx Meeting. Three clients to complete a UC solution and not all platforms are created equal.

    • Some platforms have IM, voice, VoIP and WebEx and some don’t. This mix of features creates complexity at the help desk and lacks insight on the complexity of deploying applications that don’t carry the same feature sets. This is a complex issue for any software vendor across multiple OS’s for sure. Even Cisco’s own Cuis doesn’t support video with WebEx. How confusing is that?
    • Some platforms use Cisco Secure Connect (requires Cisco ASA hardware) feature and others require AnyConnect/VPN. More complexity. Depending on what version of Anywhere Connect and whether you are running it on IOS or ASA affects your ability to allow these applications to work.
    • iPhone, iPad require AnyConnect with the Cisco ASA. So now to take advantage of Jabber you need Cisco  hardware, you already needed Cisco UCS servers for CUPS so why stop there.

I noticed in the comments on Michaels post that Cisco choose to deliver the features in separate applications . When I talk with companies this isn't what they want. They want to be able to leverage UC from a single mobile application. Which leads me to the conclusion that this wasn’t really a choice but due to their compartmentalized UC infrastructure this was their only way to deliver these features.

Why did I write this blog?

My intention here is to highlight “ don’t throw stones in glass houses”. Cisco execs think posting on a blog and spreading miss-information about their own products is okay while analyst with poorly researched articles are no less guilty. I noticed in the comments of Michaels blog there was a lot of “it’s coming” to a lot of points raised around where they fell short. No mention of that in the article it self though.

So yeah, I work for Microsoft and happy to say I have a strong opinion of where UC is heading and what companies are looking for when it comes to UC. Cisco compartmentalized infrastructure carries through to their mobility story and I am pretty happy about that. The chaos they create in their self proclaimed “Post PC” era makes my job a hell of a lot easier. Thanks Cisco.

VoIPNorm

Update: “Busy Here” Scripting Project Phase II

I have had some interesting comments and emails around the first phase of the script. Some people had issues getting it working and others had issues with PSTN URI’s but hopefully this latest update will solve a lot of those issues along with adding a new UM lookup feature. This update removes the User.txt file and blanket enables for the whole deployment.

Download the script:

https://skydrive.live.com/redir.aspx?cid=25a5ce54e91be979&resid=25A5CE54E91BE979!715&parid=25A5CE54E91BE979!714

Again a big shout out to Angela and Jay from Melding Technology for taking the time to work on the script and make improvements. I am super grateful for the time and effort these guys have put into making this script both easier to use and added functionality. MSPL scripting is a great skill to have and these guys are proving through this community project what champions they are at it. If you would like some help on a project like this or general Lync deployment services and like what you see in this post please reach out to Melding Tech at Sales@MeldingTech.com

Please let us know if you have any ideas or questions around the scripts use or functions. If you wish to make additional changes to the script please send me an email with updates. This is a community project so any updates, comments and changes are welcomed and remember to test in a lab first.

Below is extract from an email exchange I had with Jay around the improvements to the script. Please note that the script is downloadable from the link I provided above and below is only an extract of the entire script.

This is a new iteration on the script. It has more substantial changes than before. There are some key things that are different:

 

·         Removed user filtering based on the users.txt file. Now the filter will apply to everybody. This makes easier handling both Lync calls and external phone calls.

·         Fixed issues that prevented it to work when dialing Phone numbers directly vs Lync calls (we were using the incorrect uri to query for End points).

·         The proxyByDefault option was changed to false. Now the script is responsible for redirecting as appropriate. Need to be careful when modifying to make sure the script does not generate dead ends.

·         Added the following logic: If user is UM enabled, redirect to Voice mail right away, otherwise send busy response.

 

Important note: Since the script now redirects to Voice mail, there is a check to ignore requests going to the Voice mail itself to prevent a potential loop.  When using the script it is necessary to replace the highlighted URI with the URI for Voice mail in your environment.

 

Below is highlighting the more relevant areas:

 

 

<?xml version="1.0" ?>

<lc:applicationManifest

lc:appUri="http://www.meldingtechnology.com/busybusy"

xmlns:lc="http://schemas.microsoft.com/lcs/2006/05">

  <lc:allowRegistrationBeforeUserServices action="true" />

  <lc:requestFilter methodNames="INVITE"

                          strictRoute="true"

                          registrarGenerated="true"

                          domainSupported="true" />

  <lc:responseFilter reasonCodes="NONE" />

  <lc:proxyByDefault action="false" />

  <lc:scriptOnly />

 

  <lc:splScript>

    <![CDATA[

       // Function that returns true if the given content has the SDP audio m lines

       // and false otherwise

       function contentHasSDPAudio(content) {

              // SDP format is strict enough that the following check is a valid

              // way to determine if the offer includes audio.

              if (ContainsString(content,"\nm=audio ", false) ||

                     ContainsString(content,"\rm=audio ", false)) {

                     //Log( "Debug", false, "***BusyBusy***: found m=audio" );

                     return true;

              }

              return false;

       }

 

       //Log ("Event", false, "***BusyBusy***: started script");

       Log( "Debug", false, "***BusyBusy***: We have a request - ", sipRequest.Method );

 

       // Check if this is a re-INVITE and exit if so

       foreach ( sessionExpires in GetHeaderValues( "Session-Expires" ) ) {

         if ( ContainsString( sessionExpires, "refresher", true ) ) {

                Log( "Debugr", false, "***BusyBusy***: skipped; This is a session refreshing invite" );

                return;

         }

       }

 

//

// Get Sip URI string for the user in the To: header.

//

toUri = GetUri(sipRequest.To);

 

Log( "Debugr", false, "***BusyBusy***: toUri - ", toUri );

Log( "Debug", false, "***BusyBusy***: RequestUri ", sipRequest.RequestUri);

 

// Prevent a loop by ignoring requests to the Voice mai

// ***** Replace with your Exchange UM account

if (ContainsString(sipRequest.RequestUri, "sip:MTLync@mtex.MeldingTech.Com", false))

{

       Log("Debug", false, "***BusyBusy***: ignoring Voice mail request" );

       ProxyRequest();

       return;

}

 

if (sipRequest.StandardMethod == StandardMethod.Invite) {

       // Determine if this request is for an audio session

       hasBody = false;

       hasAudio = false;

       foreach (header in GetHeaderValues (StandardHeader.ContentType)) {

              // Found a content-type header, so we know it has a body.

              hasBody = true;

              if (IndexOfString (header, "multipart/", true) == 0) {

                     //Log( "Debugr", false, "***BusyBusy***: Found multipart body. Content-Type:", header );

                     i = 0;

                     while (i<MultiPartItem.Count && BindMultiPartBodyItem(i)) {

                           if (ContainsString(MultiPartItem.ContentType, "application/sdp", true)) {

                                  //Log("Debugr", false, "***BusyBusy***: Found SDP content-type in Multipart item count: ", i);

                                  if (contentHasSDPAudio(MultiPartItem.Content)) {

                                         //Log("Debug", false, "***BusyBusy***: content has audio" );

                                         hasAudio = true;

                                         break;

                                  }

                           }

                           i=i+1;

                     }

              }

       }

 

       if ( hasAudio ) {

           Log("Debug", false, "***BusyBusy***: this is an audio call" );

       }

       else if (!hasBody) {

           // An INVITE without a body is taken as an implied audio INVITE.

           Log("Debug", false, "***BusyBusy***: content has no body, implied to be an audio call" );

       }

       else {

          // not an audio call return now

          Log("Debug", false, "***BusyBusy***: this is not an audio call!" );

          ProxyRequest();

          return;

       }

}

 

 

totalEndpoints = 0;

anyEndpointBusy = false;

 

foreach (dbEndpoint in QueryEndpoints(toUri)) {

   totalEndpoints = totalEndpoints + 1;

  

   Log( "Debugr", false, "***BusyBusy***: endpoint.EPID        - ", dbEndpoint.EPID );

   Log( "Debugr", false, "***BusyBusy***: endpoint.ContactInfo - ", dbEndpoint.ContactInfo );

   //Log( "Debugr", false, "***BusyBusy***: endpoint.Instance    - ", dbEndpoint.Instance    );

 

 

   publication = QueryCategory(toUri, 2, "state", dbEndpoint.Instance);

   //Log( "Debugr", false, "***BusyBusy***: State - ", publication );

 

   if (IndexOfString(publication, "on-the-phone") >= 0) {

      Log( "Debugr", false, "***BusyBusy***: endpoint in a call change to busy state" );

      anyEndpointBusy = true;

      break;

   }

   else {

      Log( "Debugr", false, "***BusyBusy***: endpoint not in call stay in free state" );

   }

 

}

 

//Log( "Debugr", false, "***BusyBusy***: found ", totalEndpoints, " endpoint(s)" );

 

 

// If any point is busy respond with voice mail of busy signal

if (anyEndpointBusy) {

  if (RequestTarget.Aor != "BENOTIFY") {

       // Check if user is enabled for UM

       userProperties = QueryCategory(toUri, 1, "userProperties", 0);

       Log( "Debugr", false, "***BusyBusy***: User Properties - ", userProperties );

       if (ContainsString(userProperties , "1</exumEnabled>", false))

       {

           Log( "Debugr", false, "***BusyBusy***: Redirecting to voice mail for ", toUri);

          toVoiceMail = Concatenate( toUri, ";opaque=app:voicemail");

           ProxyRequest(toVoiceMail);

           return;

       }

       else

       {

           Respond( 486, "Busy here" );

           Log( "Debugr", false, "***BusyBusy***: Busy response given for ", toUri);

           //log a request which was replied with busy signal

           Log( "Event" , true,  "***BusyBusy***: Busy response given for ", toUri);

           return;

       }

    }

 

}

 

Log( "Debugr", false, "***BusyBusy***: finished script.. no action taken");

ProxyRequest();

return;

   

]]>

  </lc:splScript>

</lc:applicationManifest>

 

 

VoIPNorm