04-04-2018 10:10 AM - edited 03-01-2019 06:48 AM
API Document containing information about Generic API Task, its usage and examples.
UCSD has always been a repository of many out of the box tasks. These tasks are built around specific operations for a particular device. These have got pre-defined inputs and pre-defined outputs. These tasks are developed by developers who understand UCSD framework and also have domain expertise around the device for which the task is meant for.
In certain situations these out-of-the box task doesn’t suffice the user requirements.
For example:
To circumvent these situations, UCSD provides a custom task framework where users can utilize cloupia script to write any device specific logic and achieve the desired result.
Custom tasks do provide the required flexibility but at the same time requires users to have good understanding about the UCSD exposed APIs and at the same time good knowledge of writing logic in cloupia script (which is mainly Java Script).
There are generic tasks available in UCSD like “SSH task” which allows user to automate operations on device which can be accessed via SSH. Since SSH is a standard way of interacting with devices, users can easily automate such operations in case there is no out-of-the-box task available for the same.
Most of the devices which requires the use of custom tasks expose their functionalities via APIs (XML/JSON). The standard way of consuming any API is a normal HTTP/HTTPs based call which clients like Postman etc. provides in a very simple way.
Currently, a generic API task using which a user can make a normal HTTP/HTTPs call to a device or service is missing in UCSD.
Generic API task tries to fill this gap and helps users to consume any API in a standard HTTP/HTTPs manner.
Any HTTP/HTTPs based API consists of a pre-defined structure:
As we see in the above snapshots, the Generic API task provides an additional page to user to define the API structure and required variables.
User can choose to define outputs based on the xPath or JsonPath of the variables inside the API response. User can also choose to output the complete response as an output or hide the complete response during task execution.
Let’s say we execute a login API for the UCSM account using generic API task. The successful response for the API will be something like:
<aaaLogin
response="yes"
outCookie="<real_cookie>"
outRefreshPeriod="600"
outPriv="aaa,ext-lan-policy,ext-lan-qos,ext-san-policy,operations,
pod-policy,pod-qos,read-only"
outDomains="mgmt02-dummy"
outChannel="noencssl"
outEvtChannel="noencssl">
</aaaLogin>
Now we want the value of outCookie attribute from this response which can be used as parameter for further operations.
The xPath for the outCookie attribute will be: /aaaLogin/@outCookie
So we can define an output variable like:
Let’s take an example of making a JSON based Login REST API call to an APIC device.
The JSON response for a successful login API call to APIC device will look something like below:
RESPONSE:
{
"imdata" : [{
"aaaLogin" : {
"attributes" : {
"token" :
"GkZl5NLRZJl5+jqChouaZ9CYjgE58W/pMccR+LeXmdO0obG9NB
Iwo1VBo7+YC1oiJL9mS6I9qh62BkX+Xddhe0JYrTmSG4JcKZ4t3
bcP2Mxy3VBmgoJjwZ76ZOuf9V9AD6Xl83lyoR4bLBzqbSSU1R2N
IgUotCGWjZt5JX6CJF0=",
"refreshTimeoutSeconds" : "300",
"lastName" : "Washington",
"firstName" : "George"
},
"children" : [{
...
...
}
We want to fetch the value for the “token” attribute as it is the value which is required to perform any other API calls to the device.
Since the response is a JSON response, we shall find out the JsonPath for the “token” attribute. The JsonPath is similar to xPath where we traverse the element from the parent element. The JsonPath for the “token” attribute in above response will be:
JsonPath: $.imdata[0].aaaLogin.attributes.token
We can define the output inside the Generic API task as below:
Using xPath or JsonPath built-in filtering capability
xPath and JsonPath provides some in-built filtering capability. We can define the xPath or JsonPath of an element and provide some filtering criteria as well.
For example, let’s say an API execution results in a JSON response having list of employee details.
Response:
[
{
'name': 'John',
'address1': null,
'empId': 10,
'salary': 0.0
},
{
'name': 'George',
'address1': null,
'empId': 11,
'salary': 0.0
},
{
'name': Frank',
'address1': null,
'empId': 12,
'salary': 0.0
}
]
We want to output the employee id of the employee with employee name “Frank”.
The following JsonPath expression will help find out the employee object in the above response and provide the required employee id:
$.[?(@.name=="Frank")].empId
We can than define the task output with above JsonPath expression:
NOTE: If in case there are multiple employees with name “Frank”, the output will be a comma separated Employee IDs of the employees with name as “Frank”. Example: [13, 14, 20]
Similar to above example, we can use xPath filtering capabilities as well to filter XML response and output the desired node/element value from the response.
User can define variables inside a task definition using following format:
@{INPUT VARIABLE} For e.g. @{Username}, @{Employee Name}
Variables can be used in following places:
User can define variables inside the API path which will form the URL for the API call. These variables become task input. The API Path is evaluated during task execution.
User can define variables inside the request body content. These variables become task Input. The body content is evaluated during the task execution.
User can define variables inside the output xPath or JsonPath expression. These variables become task input. The output path is evaluated during task execution and used to find required output from XML or JSON response.
These variables will become task input and the values for the same can be fed either as a mapped input or task input.
Examples for defining variables in various sections
Let’s say we need to execute an API available at following URL:
https://[IP]:[Port]/getEmployeeDetails/[Employee ID]
Now since we want to be able to execute this API for different values of employee ID, we would need the employee id as a variable and should be able to provide the value at run time.
The IP Address and Port values are also required but can be static in nature.
We can define the above API structure using the Generic API task in below manner –
The @{Employee_ID} notation will create a task input named Employee_ID and now we can map the input to either WF input or define the value statically as task input.
Most of the HTTP API calls requires a body content to be sent as a payload. The payload contains the information required to perform the operation (Post, Put etc.).
Let’s take an example of getting a session id information from UCS Manager which can further be used as a parameter to perform other operation.
The API Path required to get session id is /nuova. The request content which need to be sent to the URL is:
<aaaLogin inName= [User Name] inPassword= [Password] />
Below is the API structure defined using Generic API Task to perform the above operation:
<aaaLogin inName= @{User_Name} inPassword= @{Password.encrypt} />
Here the variables defined using User_Name and Password becomes the task input and the values can be provided either statically or as mapped input.
The .encrypt keyword can be used to make sure the generated task input type for the defined variable is password and will not be visible inside the task or during execution of the task.
By default the generated task input type for the defined variables is generic text.
For managed devices in UCSD, the above request content can also be defined using below keywords:
<aaaLogin inName= @{Account.username} inPassword= @{Account.password} />
OR
<aaaLogin inName= @{CredPolicy.username} inPassword= @{CredPolicy.password} />
The @{Account.username} and @{Account.password} keywords can be used to provide information from an already managed account in UCSD. The generic API task fetches the information internally for the selected account and use the same during API execution. These keywords don’t become task input, as values are fetched internally within UCSD.
The @{CredPolicy.username} and @{CredPolicy.password} keywords can be used if user wants to provide credential information from a credential policy defined inside UCSD. This can be used for devices which are not managed by UCSD but credential information is fed from the credential policy within UCSD. These keywords also don’t become task input as values are fetched internally within UCSD.
There are certain situations where we want to use variables inside the xPath or the JsonPath of the element value which we want from the response. For example, let’s take the same example as above where an API execution results in a JSON response having list of employee details.
Response:
[
{
'name': 'John',
'address1': null,
'empId': 10,
'salary': 0.0
},
{
'name': 'George',
'address1': null,
'empId': 11,
'salary': 0.0
},
{
'name': Frank',
'address1': null,
'empId': 12,
'salary': 0.0
}
]
Now we want to output the employee ID of an employee with a particular name. As we saw in above examples, the JsonPath to find out the same will be:
$.[?(@.name=="Frank")].empId
But let’s say the employee name is a variable and we want to provide employee name at run time and want the employee Id for the same as task output.
Generic API task allows us to define variables inside the output path definition as well. We can define variable using @{Variable_Name} notation.
In above example, the JsonPath to find employee Id for a variable employee name would become like:
$.[?(@.name=="@{Employee_Name}")].empId
The variable Employee_Name will become a task input and can get value as a task input or a mapped input. The variable value will be evaluated at runtime during task execution and then the JsonPath will be evaluated based on the JSON Response. Finally the evaluated JsonPath value will be outputted as task output.
Similar variable usage is possible inside xPath definition as well while defining the output of the Generic API task.
Any HTTP/HTTPs based API execution may require some information present inside the HTTP header.
Generic API task allows user to define the header names required for API execution. All the header parameters become task input automatically and can get value statically or as a mapped input during run time.
In situations where the header value might require some fixed and some variable part, we can use the normal dollar variable ($) concept to define the value for the particular header.
For example, in the below screenshot, there are two headers parameters required for API Execution:
Both these header parameters will automatically become task input and the values can be provided either statically or as a mapped input.
Now let’s say the value required the Cookie parameter is of following format:
X-Device-Token=[TOKEN_VALUE]
Here the X-Device-Token is a fixed part and TOKEN_VALUE is a value which can be a variable. In order to define this value for the “Cookie” task input, we can use dollar variable to provide a fixed value and at the same time define a variable value:
In certain situations, API execution may require authentication parameters to be passed using HTTP basic authentication method.
HTTP Basic Authentication is a standard way to authenticate clients with server. The authentication information is passed using an “Authorization” header parameter that contains the word Basic
word followed by a space and a base64-encoded string username:password.
Generic API task allows user to define basic authentication mechanism in following ways:
In this case, two task inputs are auto-generated (Auth_Username and Auth_Password) and user can provide the required values as task input or mapped input.
NOTE: Generic API task automatically adds the required header for HTTP Basic authentication (Authorization) with required formatted value while making the API call. User don’t need to define this header manually.
Generic API Task, like any other task in UCSD, also provides a way to define rollback. The rollback can be defined in two ways:
Hi,
I am trying to trigger an API call to "System Center Service Manager". However I always get "Connection refused"
It is not firewall related, as when I perform a call from the UCSD console, I get the expected feedback.
I have tried multiple ways for authentication, but none seem to work.
An option in the Generic API call, to enable verbose mode could be helpfull...
The hash below is a BASE64 conversion of "domain\user:password"
The command when run from the UCSD Console (running in verbose mode)
curl -H "application/json;odata=verbose" -H "Authorization:Basic dZG9tYWluXHVzZXI6cGFzc3dvcmQ=" https://ServerName:9090/00000000-0000-0000-0000-000000000000/Runbooks -v
Settings used in the API call
ip address: ServerName
port: 9090
API path: 00000000-0000-0000-0000-000000000000/Runbooks
Protocol: https
Request type: Get
Content Type: JSON
Headers:
Authorization: Basic ZG9tYWluXHVzZXI6cGFzc3dvcmQ=
Content-Type: application/json;odata=verbose
ERROR: Task: DEV_SmaApiCall (Execute Generic API) failed with error - Connection refused (Connection refused), selectedContext=<None>
For those, interested in the related infra Manager log:
2018-07-12 11:51:39,891 [WFExec-9266-0] INFO run(WorkFlowExecutor.java:81) - Executing Step 1 of 3 for SR 9266
2018-07-12 11:51:39,896 [WFExec-9266-0] INFO run(WorkFlowExecutor.java:132) - Workflow 9266 is currently being repopulated
2018-07-12 11:51:39,896 [WFExec-9266-0] INFO run(WorkFlowExecutor.java:134) - Completed workflow Step 1 of 3 for SR 9266
2018-07-12 11:51:39,898 [WFExec-9266-0] INFO run(WorkFlowExecutor.java:211) - Workflow 9266 finished repopulating
2018-07-12 11:51:42,898 [WFExec-9266-1] INFO run(WorkFlowExecutor.java:81) - Executing Step 2 of 3 for SR 9266
2018-07-12 11:51:42,905 [WFExec-9266-1] INFO invoke(ServiceBinder.java:199) - Executing method getLogin; operationTimeout=90000
2018-07-12 11:51:42,913 [WFExec-9266-1] INFO invoke(ServiceBinder.java:199) - Executing method getProductAccess; operationTimeout=90000
2018-07-12 11:51:42,989 [WFExec-9266-1] INFO invoke(ServiceBinder.java:199) - Executing method getLogin; operationTimeout=90000
2018-07-12 11:51:42,996 [WFExec-9266-1] INFO invoke(ServiceBinder.java:199) - Executing method getLogin; operationTimeout=90000
2018-07-12 11:51:43,001 [WFExec-9266-1] INFO invoke(ServiceBinder.java:199) - Executing method getAllProductAccess; operationTimeout=90000
2018-07-12 11:51:43,011 [WFExec-9266-1] INFO setSubmitterDetails(CustomActionTriggerContext.java:2071) - API Login profile::{"userId":"user@domain.com","firstName":"firstname","lastName":"lastname","email":"firstname.lastname@domain.com","groupName":null,"groupId":0,"role":"Admin"}
2018-07-12 11:51:43,014 [WFExec-9266-1] INFO executeCustomAction(GenericAPIExecuteHandler.java:98) - Generic REST API Execution ConfigID 3745
2018-07-12 11:51:43,014 [WFExec-9266-1] INFO executeAPI(GenericAPIExecuteHandler.java:466) - Sending query to host/device servername.domain.com:9090
2018-07-12 11:51:43,018 [WFExec-9266-1] ERROR executeAPI(GenericAPIExecuteHandler.java:496) - Exception occurred
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:668)
at com.cloupia.lib.util.easytrust.EasySSLProtocolSocketFactory.createSocket(EasySSLProtocolSocketFactory.java:107)
at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:706)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:386)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:170)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:396)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
at com.cloupia.feature.customactions.handlers.GenericAPIExecuteHandler.executeAPI(GenericAPIExecuteHandler.java:469)
at com.cloupia.feature.customactions.handlers.GenericAPIExecuteHandler.executeCustomAction(GenericAPIExecuteHandler.java:189)
at com.cloupia.service.cIM.inframgr.workflowhandlers.CustomActionTriggerWorkFlowHandler.executeWorkFlowStep(CustomActionTriggerWorkFlowHandler.java:291)
at com.cloupia.service.cIM.inframgr.workflowmgr.WorkFlowExecutor.run(WorkFlowExecutor.java:96)
2018-07-12 11:51:43,018 [WFExec-9266-1] ERROR executeWorkFlowStep(CustomActionTriggerWorkFlowHandler.java:357) - Custom handler exception; Task: DEV_SmaApiCall (Execute Generic API) failed with error -
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:668)
at com.cloupia.lib.util.easytrust.EasySSLProtocolSocketFactory.createSocket(EasySSLProtocolSocketFactory.java:107)
at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:706)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:386)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:170)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:396)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
at com.cloupia.feature.customactions.handlers.GenericAPIExecuteHandler.executeAPI(GenericAPIExecuteHandler.java:469)
at com.cloupia.feature.customactions.handlers.GenericAPIExecuteHandler.executeCustomAction(GenericAPIExecuteHandler.java:189)
at com.cloupia.service.cIM.inframgr.workflowhandlers.CustomActionTriggerWorkFlowHandler.executeWorkFlowStep(CustomActionTriggerWorkFlowHandler.java:291)
at com.cloupia.service.cIM.inframgr.workflowmgr.WorkFlowExecutor.run(WorkFlowExecutor.java:96)
2018-07-12 11:51:43,042 [WFExec-9266-1] INFO run(WorkFlowExecutor.java:132) - Workflow 9266 is currently being repopulated
2018-07-12 11:51:43,042 [WFExec-9266-1] INFO run(WorkFlowExecutor.java:134) - Completed workflow Step 2 of 3 for SR 9266
There are several places to select http vs https and places to type 443 . I got hung up on that.
As root (ssh) on UCSD can you issue this
telnet servername.domain.com 9090
and does that connect?
Also on the community site
https://communities.cisco.com/docs/DOC-56419
Item 453 and 454 and 455 and 456 all use the generic API task.
I just posed all of those as examples.
I checked all those examples, and the telnet as root also works fine. Even the ssh rest call as root works (see curl command)...
I see the curl command uses servername:9090 and the generic api call uses servername.domain.com:9090
Can UCSD resolve the FQDN?
just a typing error.... servername is of course not my real servername... I am using the FQDN name everywhere.
I already tested the name resolution by adding the task "DNS name to IP Resolver" and this worked as expecte
Both servers are in the same subnet (no firewalls in between)
Then I would load the trace
# yun install traceroute
-bash: yun: command not found
# yum install traceroute
Loaded plugins: fastestmirror
Setting up Install Process
Loading mirror speeds from cached hostfile
base: mirror.dal10.us.leaseweb.net
epel: mirror.compevo.com
extras: mirrors.gigenet.com
updates: mirror.us.oneandone.net
Resolving Dependencies
--> Running transaction check
---> Package traceroute.x86_64 3:2.0.14-2.el6 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
===============================================================================================================
Package Arch Version Repository Size
===============================================================================================================
Installing:
traceroute x86_64 3:2.0.14-2.el6 base 51 k
Transaction Summary
===============================================================================================================
Install 1 Package(s)
Total download size: 51 k
Installed size: 80 k
Is this ok :
That is not going to help much!
IT IS WORKING from the commandline (ssh as root to UCSD appliance)
It is NOT working on with the UCSD task
You are correct – my bad – I meant tcpdump.
That could tell you what is going out and what gets received and maybe why it is refused on the other end.
It took me a while to get the APIC/ACI thing going between token and challenge token and ports and IP and and.. (speaking of IP – did you try the IP vs. the FQDN?)
With the tcpdump trace, It looks like UCSD still tries to connect on port 443, instead of port 9090 that I provide…
There aren’t that many locations that you can set this parameter?
I changed my remote server, to listen on port 443 instead of port 9090, and now my action in UCSD works, without changing anything to the action! According to the WF log, it is still sending the query to port 9090, while it is actually using port 443...
From the UCSD WF log
Jul 12, 2018 15:56:20 CEST Sending query to host/device server.dom.int:9090
But still .... it connects on port 443... BUG?
Send me the tcp log and some screen shots that I can send to the BU. Ogelbric@cisco.com<mailto:Ogelbric@cisco.com>
As it turns out there is a bug for https and it send always on port 443. The next UCSD patch (6.6.0.1)will fix this issue.
I have a hot fix for any one that is interested.
We have this requirement in our backlog - we'll look into the possibility of adding support for response headers in the upcoming releases.
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: