#1 – request
Request is the easiest way to make REST calls. It runs server-side to hide your token and if you use Postman to test the HTTP request, it can even generate the code for you!
https://www.npmjs.com/package/request
Example Request Using Spark Messages API:
var request = require(‘request’);
var req = {
auth: { bearer: ‘sparkTokenHere’ },
url: ‘https://api.ciscospark.com/v1/messages’,
json: true,
body: {
‘roomId’: roomId,
‘text’: message
}
};//end setuprequest.post(req, function(err, res) {
if(err) {
console.log(err);
} else {
}
});//end rest call
#2 – picker
Picker is a server side router for Meteor that works alongside middleware to easily provide an API or webhook into your application.
https://atmospherejs.com/meteorhacks/picker
Example Webhook with JSON parsing using body-parser:
Picker.middleware(bodyParser.json());
Picker.middleware(bodyParser.urlencoded({extended: false}));
Picker.route(‘/myWebhook’, function(params, request, response) {
personEmail = (request.body.data.personEmail);
msgid = (request.body.data.id);
#3 – Q
Before getting too far ahead with node.js, you’ll need to grasp the underlying language, javascript. Javascript is a synchronous language, meaning it runs functions all at the same time, which can make a mess of things if you don’t use callbacks properly. Q uses something called promises to run things asynchronously in the order you tell it. To learn more about callbacks and why this package is so necessary, check out callbackhell.com
http://documentup.com/kriskowal/q/
Example of promises with Q:
Q.fcall(promisedStep1)
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
// Do something with value4
})
.catch(function (error) {
// Handle any error from all above steps
})
.done();
#4 – bert
Bert makes notifications simple
https://github.com/themeteorchef/bert
Bert.alert({
title: ‘Conference Now’,
message: ‘Connecting to Tropo…’,
type: ‘info’,
style: ‘growl-bottom-right’,
icon: ‘fa-phone’
});
#5 – fontawesome
fontawesome is a collection of 675 icons in unicode that can be embedded in your site with a single tag. Most people will use their built in CDN (content delivery network) to make deployment even easier.
http://fontawesome.io/icons/
<i class=fa fa-camera-retro”></i>
#6 – nodemailer
nodemailer is the best email package hands down. It supports an html body and allows you to specify options within the app.
https://www.npmjs.com/package/nodemailer
var nodemailer = require(‘nodemailer’);
// create reusable transporter object using the default SMTP transport
var transporter = nodemailer.createTransport(‘smtps://user%40gmail.com:pass@smtp.gmail.com:587’);// setup e-mail data with unicode symbols
var mailOptions = {
from: ‘”Fred Foo š„” <foo@blurdybloop.com>’, // sender address
to: ‘bar@blurdybloop.com, baz@blurdybloop.com’, // list of receivers
subject: ‘Hello ā’, // Subject line
text: ‘Hello world š“’, // plaintext body
html: ‘Hello world š“‘ // html body
};// send mail with defined transport object
transporter.sendMail(mailOptions, function(error, info){
if(error){
return console.log(error);
}
console.log(‘Message sent: ‘ + info.response);
});
#7 – validator
Need to check if an email is actually an email? A dollar amount is actually a dollar amount? Validator has a ton of built-in methods to check for you.
https://www.npmjs.com/package/validator
var validator = require(‘validator’);
validator.isEmail(‘foo@bar.com’); //=> true
#8 – csv
While ECMA 5 has native XML and JSON support, a lot of Cisco applications still rely on CSV (comma seperated values). This package aims to bridge the gap.
https://www.npmjs.com/package/csv
var csv = require(‘csv’);
csv.parse(data, function(err, data){
csv.stringify(data, function(err, data){
process.stdout.write(data);
});
});
#9 – bootstrap
Boostrap is so useful, I wish it was just included in HTML period. Any buttons, menus, fonts, tables, grids, layouts, etc. are super easy with Bootstrap.
https://www.npmjs.com/package/bootstrap
Just include the bootstrap code below to utilize their CDN:
<!– Latest compiled and minified CSS –>
<link rel=”stylesheet” href=”https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css” integrity=”sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u” crossorigin=”anonymous”><!– Latest compiled and minified JavaScript –>
<script src=”https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js” integrity=”sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa” crossorigin=”anonymous”></script>
#10 – jsPDF
PDFs are still the industry standard for “digital hard copies” of documents. jsPDF makes generating PDFs easy.
https://parall.ax/products/jspdf
<script src=”https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.2/jspdf.debug.js”></script>
var pdf = new jsPDF();
pdf.text(30, 30, ‘Hello world!’);
pdf.save(‘hello_world.pdf’);
I did a post not too long ago on the vlookup function and how it can be used to extract data by matching on a row and returning data x number of columns away. The same exists using the hlookup command to match on a column and return data x number of rows away.
HLOOKUP(lookup_value, table_array, row_index_num, [range_lookup])
The use case for this is simple: you’re doing a parallel upgrade of Call Manager using the import/export method and you want to copy over all the tables that exist in the old database, but if they don’t exist, you still need the table headers. To do this you’ll need the old phone.csv and a blank export of the new phone.csv side by side.
You’ll paste this on the new phone.csv in A2 and drag to the right and down to populate the database.
=hlookup(a$1,(old-phone!$a$1:$dyt$5000),(row(a2)),false)
When you’re done you should copy all values to a new sheet to clean up any #N/A values it may create and thats your new phone.csv
A lot of apartment buildings have callboxes that will dial a tenant and allow the tenant to open the door by pressing a key sequence. I have had to use this to call myself before when I left my keys upstairs, or that time I lost my keys for a week (but thats another story). So what happens if you don’t have your phone or your keys? Or what about when you have guests that arrive early and you’re still in the shower, getting ready or can’t get to your phone in time?
In this example, the callbox dials Tropo instead of your phone, uses the built-in IVR to ask for a password. If the password is correct, it dials the dtmf digits to open the door and sends a text message to your phone alerting you of company.
var
result = ask(“The password is?”, {
choices: “sausages”
});
if(result.value == “sausages”){
say(“that is correct”);
say(“https://evolution.voxeo.com/library/audio/prompts/dtmf/Dtmf-9.wav”);
message(“A Guest has Arrived”, {
to:”+19192223323″,
network:”SMS”
});
}
else{
say(“there is a nice bench outside for you to sleep on”);
}
I recently posted about the Jabber Problem Report Tool and the csf-unified.log that turned out to be one of my most popular posts. I had some feedback asking for more info on specific troubleshooting after home cluster is found, so here it is.
Service Discovery Failure Codes (csf-unified.log)
[table id=2 /]
Service Discovery Cache File (service-location.xml)
Located in %appdata%\Cisco\Unified Communications\Jabber\CSF\Config
<?xml version=”1.0″?>
<UCServices>
<DomainName>pnslabs.com</DomainName>
<UCService>
<type>CUCM</type>
<connectionInformation>
<name>_cisco-uds</name>
<scope>UNKNOWN</scope>
<address>cucm.pnslabs.com</address>
<protocol>_tcp</protocol>
<port>8443</port>
</connectionInformation>
</UCService>
</UCServices>
IMS Result Codes
Client Profile Agent Logs pulled from IM&P Server EPASSoapXXXXX.log
[table id=3 /]
Anyone who has deployed Jabber knows of the cisco-uds SRV record that Jabber uses (or Expressway-C in the case of MRA) to discover it’s services. It’s also used for directory searches, and home cluster lookup with ILS.
UDS or User Data Services is a simple REST based API for CUCM. While the UDS API is not as extensive as what you can do with AXL through SOAP and WSDL, it makes a great use case for a front end to allow end users to manage their own devices: Change their single number reach destination, password, speed dials, and conference pins.
For security reasons, most browsers will block an XMLHttpRequest served on one page and originating on another (in the case of a front end making UDS calls to CUCM). To get around this, you would use CORS or Cross Origin Resource Sharing, defining the front end URL inside CUCM.
UDS supports REST queries POST/PUT/GET/DELETE in XML format. Some calls do not require authentication and some do. Ones that do will use Basic authentication built into the browser which encodes the username:password in Base64 format.
UDS resources that do not require authentication
clusterUser, installedLocales, models, options, phoneService(s), servers, timezones, users, version
GET https://{host}:8443/cucm-uds/users?last=Smit
GET https://{host}:8443/cucm-uds/clusterUser?username={userId}
UDS resources that require authentication
credentials, device(s), extension(s), remoteDestination(s), speedDial(s), subscribedService(s), user, userPolicy
POST https:Ā//{host}:8443/cucm-uds/user/{userId}/speedDials
<!–add speedDials example request body–>
<speedDials>
<speedDial>
<index>1</index>
<number>1234567890</number>
<label>Manager</label>
</speedDial>
<speedDial>
<index>2</index>
<number>1234567899</number>
<label>Assistant</label>
</speedDial>
</speedDials>
CUCM UDS API Reference
CUCM UDS Developer Guide
CUCM UDS Authentication Guide
Base64 Encoder/Decoder
You’ve probably heard a lot of buzzwords lately: API, JSON, and REST among them, however truth be told, REST or Representational State Transfer has always been around as the “language of the internet” (a REST HTTP GET brought you this page!), so it goes without saying that in the age of Internet of Things, REST would become infinitely more important.
REST is made up of 4 things
URI: https://api.ciscospark.com/v1/rooms
Request Type: POST, GET, PUT, etc
Header: Authorization (API key), Content-Type (html, application/xml, application/json)
Body: { “function” : “sendMessage”, “message” : “this is a message”}
JSON is the preferred format over XML because its more efficient. With PHP methods json_encode() and json_decode() for instance, it’s very easy to parse arrays into JSON format and vis a visa.
One of the great things about REST is that when a call is made, it sends a response, which can then in turn be a variable in a second response and so on. It’s not client-server, it’s a conversation.
Check out my demo’s for Spark API and Tropo API for a full writeup of how to write some simple REST calls using an html form and some PHP.
CiscoĀ has a good writeup on CUC SQL queries, which are very useful to determine which voicemail accounts are active and which are just taking up a license, and perhaps could be skipped over during migrations. To get everything you need, use the query below:
listsĀ all message counts, durations, size, and dates per alias:
run cuc dbquery unitymbxdb1 select alias as UserID, count (*) as TotalMessages, sum(case when deleted=’0′ then 1 else 0 end) as Inbox, sum(case when deleted=’1′ then 1 else 0 end) as Deleted,Ā min (arrivaltime) as OldestMessageTime, vw_mailbox.bytesize, sum(duration/1000) as TotalDuration_In_sec from vw_message,vw_mailbox, unitydirdb:vw_mailbox, unitydirdb:vw_user where vw_message.mailboxobjectid=vw_mailbox.mailboxobjectid and vw_mailbox.mailboxobjectid in (select mailboxid from vw_mailbox where unitydirdb:vw_user.objectid = unitydirdb:vw_mailbox.userobjectid) group by alias, vw_mailbox.bytesize order by TotalMessages desc
MRA (Mobile and Remote Access) is a technology that allows phone registrations without raw sip signaling sent over the internet. I compare it to RPC over HTTPS proxy, aka “Outlook Anywhere.” Email came first, now I’m not sure if anyone remembers having to VPN in for Outlook to work.
After having several MRA projects back to back, I’ve found that most of the lessons I’ve learned were dealing with project management than the technical pieces. No other piece of hardware or software requires so many different groups of people: the datacenter guy, the firewall guy, the certificate guy, the dns guy, the voice guy. Throw in a business analyst and a project manager and it gets messy. I literally had projects ongoing for months and months when I was able to get MRA working in my lab in just a couple hours. Anytime I finish a project I look at how it could’veĀ been done better, so here it is:
First: It’s better to think of MRA as 5 separate, independent tasks because almost nothing depends on anything else.
- VM Deployment
- Networking
- Certificates
- DNS
- Firewall
Second: Clearly define roles and responsibilities per task at the onset of the project. The certificate guy doesn’t care about ip addresses or storage so just gather contact information and give role takers hyper-specific information to keep their attention. Limit emails.
Third: Make the configuration as cookie-cutter as possible. I wouldn’t even mention single NIC with some nat reflexion workaround, you use the advanced networking key with an outside and an inside interface. Public Certs on everything. It’s always a cluster, even if its a cluster of one; you never know when they will scale up. I assume inside out, everything is allowed through the firewall; this is usually the case and customers get confused with the lengthy cisco documentation. I usually give something like below:
Purpose |
Protocol |
Internet Endpoint (source) |
Expressway-E (listening) |
XMPP |
TCP |
>=1024 |
5222 |
XMPP federation |
TCP |
>=1024 |
5269 |
HTTP proxy (UDS) |
TCP |
>=1024 |
8443 |
SIP media |
UDP |
>=1024 |
36002 to 59999 |
SIP signaling |
TLS |
>=1024 |
5061 |
HTTPS (Unity) |
TCP |
>=1024 |
443 |
Also, I posted before aboutĀ Flexible Jabber ID, which allows for multiple presence domains. That can cause holdups if you aren’t allowed to sign for these domains for your cup-xmpp certificate. It becomes an all-or-nothing service model. The best thing to do is get ahead of this and remove services from domains that you cannot sign for! You can run aĀ whois lookupĀ to ensure the technical contact has some relationship with the customer.
For a list of all jabber users and their last login time, you can run the following query:
run sql select e.userid, cd.timelastaccessed from enduser as e, credentialdynamic as cd, credential as cr where e.pkid=cr.fkenduser and e.tkuserprofile=1 and e.primarynodeid is not null and cr.tkcredential=3 and cr.pkid=cd.fkcredential order by cd.timelastaccessed
This date is in something called “epoch” format. To convert to something that makes sense, you’ll need toĀ use the following formula:
=(((B2/60)/60)/24)+DATE(1970;1;1)+(-5/24)
This is for Eastern Standard Time where -5 = UTC -5, you can change this accordingly.