cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
5874
Views
5
Helpful
2
Comments
robedwa
Level 4
Level 4
Task NameThis is a collection of tasks for interacting with Cisco Spark.
Description

These will enable UCS Director add people to Spark groups and also post messages into specific spark rooms.

Updated: 3rd Feb 2015 based on feedback

Prerequisites

Tasks have been updated and tested on version 5.4.0.1

CategorySpark (Tasks)
Components

Instructions for Regular Workflow Use:

  1. Download the attached .ZIP file below to your computer. *Remember the location of the saved file on your computer.
  2. Unzip the file on your computer. Should end up with a .WFD file.
  3. Log in to UCS Director as a user that has "system-admin" privileges.
  4. Navigate to "Policies-->Orchestration" and click on "Import".
  5. Click "Browse" and navigate to the location on your computer where the .WFD file resides. Choose the .WFD file and click "Open".
  6. Click "Upload" and then "OK" once the file upload is completed. Then click "Next".
  7. Click the "Select" button next to "Import Workflows". Click the "Check All" button to check all checkboxes and then the "Select" button.
  8. Click "Submit".
  9. A new folder should appear in "Policies-->Orchestration" that contains the imported workflow.

NOTE: This post has been updated to reflect new tasks and updates to ensure they function with UCS Dirctor 5.4.0.1

I have been looking to show how UCSD can integrate with various tools and their API's, I had an idea for Cisco Spark (collaboration tool) a while back and have been waiting for the publication of the Rest API.  Well in December the API was released.

I decided to create some workflows that would add people to Spark rooms and post messages (including pictures) to the room. If you look at the following screen shot you will see in the Spark chat client a user 'dsmith@miggins.com' has been added to the room and then a message (including an image) posted straight after.

I have also created a video showing some of the integration from an end-user perspective - or a recorded customer session.

If you want more information about the Spark API I would highly recommend the documentation at https://developer.ciscospark.com/index.html

In the process of ensuring these tasks work with 5.4 I have decided to rewrite them a bit and try and make the code a little bit more reusable (I plan to look to creating a script module for these). I have also created some additional functionality that I didn't originally have the 1st time around.

I have also added rollback functionality to the applicable tasks (typically as an option as some of the demos we have we don't want to delete posted messages when the workflow is rolled back).

The list of tasks are;

Type ActionDescription
RoomCreateCreates a room. The authenticated user is automatically added as a member of the room.
DeleteDeletes a room, by ID.
DetailsShows details for a room, by ID.
MessageCreatePosts a plain text message, and optionally, a media content attachment, to a room.
DeleteDeletes a message, by message ID.
DetailsShows details for a message, by message ID.
MembershipCreateAdd someone to a room by Person ID or email address; optionally making them a moderator.
DeleteDeletes a membership by ID.
DetailsGet details for a membership by ID.
PeopleDetails

Shows details for a person, by ID.

To use the tasks you will need to provide a number of inputs that are consistant to all the tasks and some that a specific to the task being called. The comming inputs are;

Input Name
Description
Token

This is your (or another generic account like I have done) API token to authenticate access against spark. It looks some thing like (and no this isnt my real one, I made it up);

Bearer YzBmZjdhZGYtMjiuBiubIUiubIUBE0MWItNzNlOTgwMDE5NmVjMjQ2OTgxM2UtZmRl


It can be obatined from https://developer.ciscospark.com/getting-started.html. The curl example is along the lines of (I have highlighted the token section);


curl https://api.ciscospark.com/v1/messages -X POST -H "Authorization:Bearer YzBmZjdhZGYtMjiuBiubIUiubIUBE0MWItNzNlOTgwMDE5NmVjMjQ2OTgxM2UtZmRl" --data "toPersonId=722bb271-d7ca-4bce-a9e3-471e4412fa77" --data "text=Hi%20Sparky"

Proxy HostIf your UCS Director instance is sat in a lab that has no direct access to the Internet (like me) you will need to enter your poxry server destination in this input.
Proxy PortAs above you will also need to specific the porxy port (for example 80).

The optional inputs often require you to know what the specifc ids of things are (roomId for example), this can be obtained from the useful, inline, help pages - https://developer.ciscospark.com/endpoint-rooms-get.html.

I do plan to look at how I can improve these tasks so that it makes obtaining this information much easier. I have a few ideas but just need to test them out so watch this space.

The CloupiaScripts are also stored on my GitHub repo (probably updated more often than will be here) - Cloupiascripts/Spark at master · clijockey/Cloupiascripts · GitHub

The next Spark project will be to create a 'chatbot' so that I can make use of the UCSD API as well and request items. Although this is a bit bigger and will require some thought - although we do have it working as a proof of concept .

Previous Version

The original version 5.3 example is as follow. You can make use of the below scripts and create your own custom tasks. The code was put together pretty quickly for a PoC so im sure lots of room for improvements.

The example workflow used two custom tasks;

  • Spark_Membership_Create
  • Spark_Message_Post

The Spark_Membership_Create task will add a user to a specific spark group. The inputs required are;

Input
Description
tokenSpark API Token for authentication reasons
member emailThe email address of the person you want to add to the Spark room
spark_room_idThe ID of the Spark room.
proxy server [optional]The address of your proxy server if UCSD is sat behind a proxy
proxy server port [optional]The port of the proxy

//=================================================================

// Title:               Spark_Membership_Create

// Description:         This will add a user to a specific spark group

//

// Author:                Rob Edwards (@clijockey/robedwa@cisco.com)

// Date:                18/12/2015

// Version:             0.1

// Dependencies:

// Limitations/issues:

//=================================================================

importPackage(java.util);

importPackage(java.lang);

importPackage(java.io);

importPackage(com.cloupia.lib.util);

importPackage(com.cloupia.model.cIM);

importPackage(com.cloupia.service.cIM.inframgr);

importPackage(org.apache.commons.httpclient);

importPackage(org.apache.commons.httpclient.cookie);

importPackage(org.apache.commons.httpclient.methods);

importPackage(org.apache.commons.httpclient.auth);

// Inputs

var token = input.token;

var fqdn = "api.ciscospark.com";

var member = input.member;

var roomId = input.roomId;

var proxy_host = input.proxy;

var proxy_port = input.proxy_port;

// Build up the URI

var primaryTaskPort = "443";

var primaryTaskUri = "/v1/memberships";

// Request Parameters to be passed

var primaryTaskData = "{\"roomId\" : \""+roomId+"\",\

    \"personEmail\" : \""+member+"\", \

    \"isModerator\" : false}";

// Main code start

// Perform primary task

logger.addInfo("Request to https://"+fqdn+":"+primaryTaskPort+primaryTaskUri);

logger.addInfo("Sending payload: "+primaryTaskData);

var taskClient = new HttpClient();

if (proxy_host != null) {

    taskClient.getHostConfiguration().setProxy(proxy_host, proxy_port);

}

taskClient.getHostConfiguration().setHost(fqdn, primaryTaskPort, "https");

taskClient.getParams().setCookiePolicy("default");

taskMethod = new PostMethod(primaryTaskUri);

taskMethod.setRequestEntity(new StringRequestEntity(primaryTaskData));

taskMethod.addRequestHeader("Content-Type", "application/json");

taskMethod.addRequestHeader("Accept", "application/json");

taskMethod.addRequestHeader("Authorization", token);

taskClient.executeMethod(taskMethod);

// Check status code once again and fail task if necessary.

statuscode = taskMethod.getStatusCode();

resp=taskMethod.getResponseBodyAsString();

logger.addInfo("Response received: "+resp);

if (statuscode == 400) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": The request was invalid or cannot be otherwise served. An accompanying error message will explain further.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else if (statuscode == 401) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": Authentication credentials were missing or incorrect.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else if (statuscode == 403) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": The request is understood, but it has been refused or access is not allowed.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else if (statuscode == 404) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": The URI requested is invalid or the resource requested, such as a user, does not exist. Also returned when the requested format is not supported by the requested method.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else if (statuscode == 409) {

    logger.addWarn("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": The request could not be processed because it conflicts with some established rule of the system. For example, a person may not be added to a room more than once.");

    logger.addInfo("Response received: "+resp);

} else if (statuscode == 500) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": Something went wrong on the server.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else if (statuscode == 501) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": Server is overloaded with requests. Try again later.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else {

    logger.addInfo("All looks good. HTTP response code: "+statuscode);

    //logger.addError("Return code "+statuscode+": Something unknown happend!!");

    // Set this task as failed.

    //ctxt.setFailed("Request failed.");

}

taskMethod.releaseConnection();

The Spark_Message_Post task will post a message to a specific spark group. The inputs required are;

InputDescription
tokenSpark API Token for authentication reasons
messageMessage to post to Spark
spark_room_idThe ID of the spark room you want to post into
fileThe file you want to post with the message
proxy [optional]As my UCSD instance sits behind a poxy I need to communicate via it, as a result need to specific in the CloupiaScript.
proxy port [optional]The port of the proxy

//=================================================================

// Title:               Spark_messages_post

// Description:         This will post a message to a specific spark group

//

// Author:              Rob Edwards (@clijockey/robedwa@cisco.com)

// Date:                18/12/2015

// Version:             0.1

// Dependencies:

// Limitations/issues:

//=================================================================

importPackage(java.util);

importPackage(java.lang);

importPackage(java.io);

importPackage(com.cloupia.lib.util);

importPackage(com.cloupia.model.cIM);

importPackage(com.cloupia.service.cIM.inframgr);

importPackage(org.apache.commons.httpclient);

importPackage(org.apache.commons.httpclient.cookie);

importPackage(org.apache.commons.httpclient.methods);

importPackage(org.apache.commons.httpclient.auth);

// Inputs

var token = input.token;

var fqdn = "api.ciscospark.com";

var message = input.message;

var file = input.file;

var roomId = input.roomId;

var proxy_host = input.proxy;

var proxy_port = input.proxy_port;

// Build up the URI

var primaryTaskPort = "443";

var primaryTaskUri = "/v1/messages";

// Data to be passed

var primaryTaskData = "{\"roomId\" : \""+roomId+"\",\

    \"file\" : \""+file+"\", \

    \"text\" : \""+message+"\"}";

// Main code start

// Perform primary task

logger.addInfo("Request to https://"+fqdn+":"+primaryTaskPort+primaryTaskUri);

logger.addInfo("Sending payload: "+primaryTaskData);

var taskClient = new HttpClient();

if (proxy_host != null) {

    taskClient.getHostConfiguration().setProxy(proxy_host, proxy_port);

}

taskClient.getHostConfiguration().setHost(fqdn, primaryTaskPort, "https");

taskClient.getParams().setCookiePolicy("default");

taskMethod = new PostMethod(primaryTaskUri);

taskMethod.setRequestEntity(new StringRequestEntity(primaryTaskData));

taskMethod.addRequestHeader("Content-Type", "application/json");

taskMethod.addRequestHeader("Accept", "application/json");

taskMethod.addRequestHeader("Authorization", token);

taskClient.executeMethod(taskMethod);

// Check status code once again and fail task if necessary.

statuscode = taskMethod.getStatusCode();

resp=taskMethod.getResponseBodyAsString();

logger.addInfo("Response received: "+resp);

if (statuscode == 400) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": The request was invalid or cannot be otherwise served. An accompanying error message will explain further.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else if (statuscode == 401) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": Authentication credentials were missing or incorrect.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else if (statuscode == 403) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": The request is understood, but it has been refused or access is not allowed.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else if (statuscode == 404) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": The URI requested is invalid or the resource requested, such as a user, does not exist. Also returned when the requested format is not supported by the requested method.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else if (statuscode == 409) {

    logger.addWarn("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": The request could not be processed because it conflicts with some established rule of the system. For example, a person may not be added to a room more than once.");

    logger.addInfo("Response received: "+resp);

} else if (statuscode == 500) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": Something went wrong on the server.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else if (statuscode == 501) {

    logger.addError("Failed to configure Spark. HTTP response code: "+statuscode);

    logger.addInfo("Return code "+statuscode+": Server is overloaded with requests. Try again later.");

    logger.addInfo("Response received: "+resp);

    // Set this task as failed.

    ctxt.setFailed("Request failed.");

} else {

    logger.addInfo("All looks good. HTTP response code: "+statuscode);

    //logger.addError("Return code "+statuscode+": Something unknown happend!!");

    // Set this task as failed.

    //ctxt.setFailed("Request failed.");

}

taskMethod.releaseConnection();

The example workflow will first add the user and then post a message;

An example input (you will need to obtain your own API key by following the instructions);

Comments
Orf Gelbrich
Cisco Employee
Cisco Employee

This is very cool.  Have you tried this in UCSD 5.4 already?

robedwa
Level 4
Level 4

Thanks Orf, I got a bit too excited about the Spark API

I am upgrading our labs to 5.4 this week and will be testing these tasks then. I will update with any tweaks when tested.

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community:

Quick Links

Review Cisco Networking for a $25 gift card