Posts

Cloudflare Calls API to SIP broker

Update: Given the amount of time I sacrifice to game development outside of collaboration work, my site has become defunct.

Cloudflare has a calls beta. My intention is to create a SIP to API broker for the CMS and try to get their CDN working with it's anycast to beat out GeoDNS solutions. I will probably post more about this later here, however, don't expect me to be overly timely on it.

Also, why is the Cisco Meeting Server doesn't grey out UI items that have been configured in the API so people don't make mistakes and cause conflicts? Why is it that Cisco doesn't publish the methodology by which all cospaces are assigned to callbridges/nodes at the time of build. I have many questions for many things that don't make sense these days and a lot of rants, but I will save those for some knowledge drops in the future.

Take care everyone!

Replacing default paste behavior in Windows 11

Clipboard URL Shortener Implementation Guide

Clipboard URL Shortener Implementation Guide

Powershell Script

This PowerShell script checks the clipboard for a YouTube URL. If it finds one, it converts it to a shortened youtu.be URL and updates the clipboard with this new URL.

Add-Type -AssemblyName System.Windows.Forms

$clipboardText = Get-Clipboard

if ($clipboardText -match 'https://(www\.|music\.)?youtube\.com/watch\?v=([a-zA-Z0-9_-]+)') {
    $videoID = $matches[2]
    $shortUrl = "https://youtu.be/$videoID"
    Set-Clipboard -Value $shortUrl  # Update the clipboard with the shortened URL
} else {
    Set-Clipboard -Value $clipboardText  # Retain the original clipboard text if it's not a YouTube URL
}
        

AutoHotkey Script

This AutoHotkey script intercepts the Ctrl+V keystroke to execute the PowerShell script and then perform a paste operation using Shift+Insert.

^v::
{
    RunWait("C:\Users\joe\bin\yurl.ps1", "", "Hide") ;
    Send("+{Insert}")  ; Perform paste operation using Shift+Insert
}
return
        

How It Works

When you press Ctrl+V, the AutoHotkey script runs the PowerShell script. If the clipboard contains a YouTube URL, the PowerShell script converts it to a shortened youtu.be URL and updates the clipboard. The AutoHotkey script then simulates a Shift+Insert keystroke to paste the (potentially modified) clipboard content, replacing the default Windows paste behavior with shortened URLs. To avoid breaking pasting images, simply use shift+insert if you know the content is graphical. Still working around this.

Well... chatGPT, collab, automation, monolithic code and bad APIs

Let's just be honest about the state of things from an automation standpoint:

import pandas as pd
import re

# Variable Definitions
template_file_name = 'phonebuttontemplate.csv'
device_file_name = 'deviceprofile.csv'
modified_device_file_name = 'deviceprofile_modified.csv'
replacement_value = 'DELETED'
end_column_number = 89
print_line_counts = False  # Flag this if you encounter issues and want to print the Line count for each row in the template csv
first_column_name = 'Device Profile Name'

# Read phonebuttontemplate.csv
print("Reading phonebuttontemplate.csv...")
template_df = pd.read_csv(template_file_name)

# Store header row
header_row_template = list(template_df.columns)

# Initialize a dictionary to store the values
template_dict = {}

# Loop through the DataFrame rows
for _, row in template_df.iterrows():
    name = row.get('NAME', None)
    # Check if the row has a NAME and is not empty
    if pd.notna(name):
        # Check each column for "Line", "Speed Dial", or "None" under the "TYPE OF FEATURE \d{1,2}" pattern
        count = 0
        empty_value_encountered = False
        for col in header_row_template:
            if re.match(r'TYPE OF FEATURE \d{1,2}', col):
                value = row[col]
                if value == 'Line':
                    count += 1
                elif value == 'None':
                    empty_value_encountered = True
                    break
        # If an empty value was encountered, stop counting and break the loop
        if empty_value_encountered:
            break
        template_dict[name] = {'count': count + 1}  # Start the count from 1
        # If print_line_counts is True, print the name of the template and the count of its lines
        if print_line_counts:
            print(f"{name}: {count + 1} lines")

# Read deviceprofile.csv
print("Reading deviceprofile.csv...")
device_df = pd.read_csv(device_file_name)

# Store header row
header_row_device = list(device_df.columns)

# Iterate over the rows in deviceprofile.csv
for index, row in device_df.iterrows():
    template_name = row['Phone Button Template']
    device_profile_name = row[first_column_name]

    if pd.notna(template_name) and pd.notna(device_profile_name):
        # Check if the template name exists in the template_dict
        if template_name in template_dict:
            template_info = template_dict[template_name]
            count = template_info['count']
            directory_number_col = f'Directory Number {count}'
            call_id_presentation_col = f'Calling Line ID Presentation When Diverted {end_column_number}'
            device_df.loc[index, directory_number_col:call_id_presentation_col] = replacement_value

# Write the DataFrame to a new file
device_df.to_csv(modified_device_file_name, index=False)

print("Processing completed successfully.")

The prominent issue in terms of coding is chatGPT, which needs to be addressed when considering collaboration (collab).

To begin with, it would be beneficial to develop a universal UC API that can merge various methods and functions, enabling the automation of any task. Although this idea is intriguing, it necessitates the complete rewriting of these large-scale applications. The goal would be to leverage AI and prioritize an API-first approach.

Once this is accomplished, a standardized UC dashboard could be implemented. This would unify platforms like Webex and CUCM, allowing for seamless provisioning, integration, and communication without the need for intermediary components. These components were not specifically designed for the purpose and still rely on outdated Unix code, essentially being rooted in the Tandberg system.

I propose a significant transformation, a genuine movement empowered by AI, to bring UC up to date and in line with current advancements.

Anyhow, that's my hot-take.  I am working on automating all the provisioning in my lab, check back here in a couple months.  Maybe I will have a solid solution.  As it stands right now I just have a certificate generation, request and load API for various UC devices.  

That is the start of my ucEngineersToolKit API

Good day and may it be a great one!

Lab Rebuild

So, we have been rebuilding the lab, ESXi is back up and I am getting my VM's ready.
I will post an update once I am ready :)

So I thought I would have this lab ready by now...

But obviously, that won't be quite ready today. Spinning up 2 CUCM clusters, to set parameters on the SIP trunks and make a LUA scripting post... I also hit a really nice BUG with FIPS on 14 SU2, haven't confirmed it's on SU1, and working on that in a production environment has taken up more time than I like to admit.

Update, we have both call managers stood up, it will be an A side to B side across a trunk from Jabber clients injects and parsing key value pairs via LUA.

LUA Scripting... Labbing... Moved... Long time no see.

So it's been ages since I posted last, and covid and a great many things happened. Lest we shall blissfully ignore this all and go back to collabing. So recently I had to implement a LUA script that takes custom headers from an IVR and passes them as such, they are key value pairs to the application. There are multiple transparency references out there, but once I have my lab back up, I will resume and test some implementation so I can properly document them. Unfortunately, everything I implemented was proprietary to their SaaS IVR.

So onto the labbing... the states of things:

\

Do take notice, it's not done and I am travelling for work for the next few weeks. Let's hope it goes better from here and the site when it comes to updates again. And oh yeah, labs shut down, what was the point of this site if no one can get their CCIE? Well, there's my excuse, bye!

Policy Based Routing on a Nexus

First of all, let's just admit, I am a collab guy, doing work on a Nexus is a foreign experience. While some things are intuitive not everything follows RFC's and the Nexus platform is a bit more restrictive.

First of all, to get PBR going, I had to change the hardware profile, since I have no intention of using QoS internally in my lab, I decided to steal from it:

hardware profile tcam region qos 0
hardware profile tcam region pbr 256

This then requires a reboot. 

After this is done and the pbr feature is enabled:
feature pbr

You can get into creating the route-maps.  However, unlike IOS devices you can only use permits in your acl's and then use a deny statement on the route map itself:

ip access-list PBR_DENY
statistics per-entry
10 permit ip any 192.168.1.0/24

ip access-list PBR_PERMIT
 statistics per-entry
 10 permit ip any any

route-map PBR_RULE pbr-statistics
route-map PBR_RULE deny 10
 match ip address PBR_DENY
route-map PBR_RULE permit 20
 match ip address PBR_PERMIT
 set ip next-hop 192.168.10.1

Google Domains, no API and a lot of collab edge sadness

Not that it's not something that can't be worked around, but I was enjoying using Google Domains' own name servers and not having to manage my own.  However, given the fact I use Let's Encrypt and I would rather not renew my own certs every 90 days and the fact you need A records for each SAN... well, I guess I have to spin up my own External DNS server.  Luckily, Google Domains use DNS SEC, so I will have to do that this weekend.

I found that my old ASA Let's Encrypt script was not perfect, I will also update that this weekend with more logical checks.  It will need to be ran as a sudoer as well, as there is some mkdir commands that need to happen.  I have gotten to a point, where I will test it as a cron job. 

In the mean time, someone has asked me to automate Windows Server 2016 installs for their lab, so I guess I will do that tonight.

I haven't been posting lately, because I am leading a game development team outside of work, studying for the lab and frankly, no clue where I have any time to do even this post.

Script to quickly create a pastable list of AD users in Powershell.

I might rewrite this in powershell at some point, but due to my familiarity with python, I tossed this together to create a pastable list of AD users for a collaboration lab environment spin up.  Hopefully this saves someone time.

#!/usr/bin/python3
list = ["John Doe", "Jane Doe"]
for fullName in list:
   nameList = fullName.split(" ")
   firstName = nameList[0]
   lastName = nameList[1]
   print("$Attributes = @{")
   print("    Enabled = $true")
   print("    ChangePasswordAtLogon = $false")
   print("    PasswordNeverExpires = $true")
   print("    UserPrincipalName = \"" + lastName.lower() + firstName[0].lower() + "@join.com\"")
   print("    Name = \"" + lastName.lower() + firstName[0].lower() + "\"")
   print("    GivenName = \"" + firstName + "\"")
   print("    Surname = \"" + lastName + "\"")
   print("    DisplayName = \"" + fullName + "\"")
   print("    Office = \"Remote\"")
   print("    Company = \"Company\"")
   print("    Department = \"Support\"")
   print("    Title = \"Test User\"")
   print("    City = \"New York\"")
   print("    State = \"New York\"")
   print("    AccountPassword = \"CHANGEME\" | ConvertTo-SecureString -AsPlainText -Force")
   print("}")
   print("New-ADUser @Attributes")
   print("Set-ADUser -Identity " + lastName.lower() + firstName[0].lower() + " -Add @{\"msRTCSIP-PrimaryUserAddress\" =\"sip:" + lastName.lower() + firstName[0].lower() + "@join.com\"}")
   print("")

Policy Based Routing on a Cisco Switch

While policy based routing is available on a great many Cisco switches, you will need the right firmware that supports it.  For my home lab, a 3560X is my main switch, it requires 15.1-15.3 to work, currently 15.2 has MD releases, which is what I used.  A quick show sdm prefer will output the features you have available, ensure ip routing is enabled as well.

Lastly, as far as creating an access list for policy based routing, ensure you deny your internal networks in the ACL prior to implementation or a lot of things won't work.

access-list 100 deny   ip 192.168.1.0 0.0.0.255 192.168.0.0 0.0.255.255
access-list 100 permit ip 192.168.1.0 0.0.0.255 any

This ACL will allow you to policy route all traffic that is external to a next hop.

Enjoy!

Vsphere 6.7 OVA issues.

In the new release of VMWare's Vsphere which is currently a release candidate you may get many OVA errors.  In many collaboration OVA's there are dual purpose sections where the XML portion may include a comma.  Currently, Vsphere will report errors when importing them, you need to copy the section entirely, remove the comma and have both.

This section will create errors:

      <Item ovf:configuration="CUCM_10000,CUCM_2500_small_disk">
        <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
        <rasd:Description>Number of Virtual CPUs</rasd:Description>
        <rasd:ElementName>4 virtual CPU(s)</rasd:ElementName>
        <rasd:InstanceID>1</rasd:InstanceID>
        <rasd:Reservation>7200</rasd:Reservation>
        <rasd:ResourceType>3</rasd:ResourceType>
        <rasd:VirtualQuantity>4</rasd:VirtualQuantity>
      </Item>
To fix:

      <Item ovf:configuration="CUCM_10000">
        <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
        <rasd:Description>Number of Virtual CPUs</rasd:Description>
        <rasd:ElementName>4 virtual CPU(s)</rasd:ElementName>
        <rasd:InstanceID>1</rasd:InstanceID>
        <rasd:Reservation>7200</rasd:Reservation>
        <rasd:ResourceType>3</rasd:ResourceType>
        <rasd:VirtualQuantity>4</rasd:VirtualQuantity>
      </Item>
      <Item ovf:configuration="CUCM_2500_small_disk">
        <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
        <rasd:Description>Memory Size</rasd:Description>
        <rasd:ElementName>3072MB of memory</rasd:ElementName>
        <rasd:InstanceID>2</rasd:InstanceID>
        <rasd:Reservation>3072</rasd:Reservation>
        <rasd:ResourceType>4</rasd:ResourceType>
        <rasd:VirtualQuantity>3072</rasd:VirtualQuantity>
      </Item>


Now just do a sha1sum on the updated ovf, update the manifest and reimport it into your OVA.

No more 180 day trial licensing....thanks Cisco :(

Here are the new licensing options.  If you request a license type more than once, you will now only get offered a 30 day license unless you request approval for a longer license.

Limitations of passing SQL across the Unified OS CLI

I have found that if you pass around 500 SQL updates via the CLI, you will get the following memory fault, 10.5.2, I have not yet tested with any other version:

Exception in thread "main" run(): caught exception Stream closed
java.lang.OutOfMemoryError: unable to create new native thread
        at java.lang.Thread.start0(Native Method)
        at java.lang.Thread.start(Thread.java:714)
        at com.cisco.cpi.common.util.cmExecCommand.exec(cmExecCommand.java:937)
        at com.cisco.cpi.common.util.cmExecCommand.exec(cmExecCommand.java:842)
        at com.cisco.iptplatform.cli.cmdBaseDbOSI.setDbLogMessageMethod(cmdBaseDbOSI.java:57)
        at com.cisco.iptplatform.cli.cmdBaseDbOSI.<init>(cmdBaseDbOSI.java:49)
        at com.cisco.iptplatform.cli.cmdRunSql.<init>(cmdRunSql.java:38)
        at sun.reflect.GeneratedConstructorAccessor8.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
        at java.lang.Class.newInstance(Class.java:383)
        at com.cisco.iptplatform.cli.cmdClassThread.setCmdInstance(cmdClassThread.java:105)
        at com.cisco.iptplatform.cli.CliClassLauncher.execute(CliClassLauncher.java:285)
        at sdMain.main(sdMain.java:1881)


However, I wrote a script that simply splits the loop into 400 command segments and then logs out and back in.  I will look to see if the API has the same issue as well and update this post at a later time.

ISE 2.3 for TACACS

This is just a quick post on how to get TACACS working in 2.3; using AD in this example.  For this, we will follow the guide provided here and supplement it below:

https://www.cisco.com/c/en/us/support/docs/security/identity-services-engine/200208-Configure-ISE-2-0-IOS-TACACS-Authentic.html

But for Configuring TACACS Authorization Policy, I am going to provide some screenshots in order.

Step 1

Step 2
Step 3











Step 4

Restoring from OVA backups, and changing IP, losing communications between nodes and how to restore

On occasion you might want to re-IP your lab environment and while the steps are fairly easy, ensuring you change it on the GUI prior to CLI changes and rebooting the subscriber node first.  You may still find you run into errors when trying to check the dbreplication runtimestate post IP change.  If you get the error, "Runtime state cannot be performed on a cluster with a single active node; aborting operation", you can fix it by ensuring you have the cluster publisher IP set in the subscriber and restarting the cluster manager service on both nodes.

set network cluster publisher ip <IP ADDRESS>
utils service restart Cluster Manager


After this, you should be able to see the proper status when issuing show network cluster:

admin:show network cluster
<IP> hq-sub.collab.life hq-sub Subscriber authenticated
<IP> hq-pub.collab.life hq-pub Publisher authenticated


Enjoy!

ISE 2.x Python API example EndPointGroup creation

Here is just a quick tidbit I tossed together for interfacing with the ISE 2.x API.n  Sadly, Parent Groups are not yet defined in the API.

#!/usr/bin/python3
import json, requests
from requests.auth import HTTPBasicAuth
#modify your values here
username = '<USERNAME>'
password = '<PASSWORD>'
fqdn = '<FQDN>'
name = '<GROUPNAME>'

description = '<DESCRIPTION>'
#actual script
url = 'https://' + fqdn + ':9060/ers/config/endpointgroup'
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
payload = {
        "EndPointGroup" : {
                "id" : "id",
                "name" : name,
                "description" : description,
                "systemDefined" : False
        }
}
resp = requests.post(url=url,
        data=json.dumps(payload),
        headers=headers,
        verify=False,
        auth=HTTPBasicAuth(username, password)
)
data = resp.text
if resp.status_code == 201:
        print('EndPointGroup ' + name + ' added!')
else:
        print('Status Code ' + str(resp.status_code))
        print(data)

Scheduled my CCIE Collab Lab for January 19th 2018

I don't normally post about myself, because really, I don't find my life important or fascinating.  However, on the scale of great accomplishments, I will be taking my CCIE lab soon.  After as much procrastination as possible, I will have to focus solely on studying.  Due to this, expect no updates until later in 2018!  See you then.  Feel free to leave a comment/request.


HP Proliant G7 (Old Server) madness and 10Gig NICs

I am just going to make a quick post after a long bit of sacrifice.  Should one every buy a new 10G NIC for their server in their CCIE lab, a couple of things you will want to know up front.

1)  What is the current firmware version on the card and does ESXi support it?
2)  What method does it require to upgrade the firmware, how will I go about doing this?

Once you have those out of the way, you may need some tools.  What I recommend for older cards is to use WinToUSB Enterprise with a version of Windows Server Evaluation that you can get from Microsoft's website.  You will need a 64GB thumbdrive as a lot of server hardware that is older will not boot from an external USB drive, but a thumbdrive will work.  Lastly, check your hardware's USB support prior to all this to ensure if you must flash it that it will work.  Otherwise you may need to slot the card in different hardware so you can flash it.

While there are methods using Linux to flash the firmware, I found those to be problematic if the drivers used .src.rpms or source based code that had to compile against the kernel due to differences in the original release and the packages now available.

Once you have all this done, you should be able to install the proper vib/driver in ESXi and get the host to recognize the card.  You can easily use a loopback plug to test your optics prior to wiring everything up and as always, make sure you clean your fiber ends prior to plugging them in to ensure you don't get dust into your transceivers!

CCIE Lab Licensing.... 6 month demo licensing FTW

So as many people know or aware, you can install CUCM and most nodes with demo licensing, and redeploy as needed for your labs.  However, Cisco offers 6 month demo licenses through their license management portal (which has steadily improved over the last few years).  Simply go to PLM, generate a license request and paste it into the port under the request demo license drop down.


You get 20 CUWL Pro for both Unity and CUCM.  Perfect for your CCIE Lab!

Using Cisco Jabber on a shared machine

While there are many ways to possibly solve the issue of a shared machine, one is to simply create a bat file that clears the current shared user's folder every time Cisco Jabber launches.  To do this you will need to use a text editor and input the following:

rmdir /s /q C:\Users\%USERNAME%\AppData\Roaming\Cisco\
"C:\Program Files (x86)\Cisco Systems\Cisco Jabber\CiscoJabber.exe"


Save this as a .bat file and then create a shortcut to it.  Once you have done this, you can update the shortcut properties to change both the Icon and Run Minimized so the command prompt window does not open when running it.  This is a quick and dirty work around for using Cisco Jabber on a shared machine.