The Commvault Rest API - Getting Started

6 minute read

In the previous post I briefly discussed using the Commvault Rest API with PowerShell but I didn’t really expand upon one of the key points to understand when automatinng with the Rest API. The token must be extracted from the login process to utilize for future authorization of Rest calls.

In addition, I expand on a couple of examples of getting the id based on the name of items such as Plans and Server Groups. Usually, the id is required to distinguish and complete action against an item.

To do anything with the Rest API we will need a token. To get a token requires logging in to Commvault and then parsing the response back. The response back will contain the token as well as some extra characters we need to strip out. Once we have the token, we can store it in a variable and put that into our header each time we need to interact with the Rest API for the remainder of the script.

Let’s take a look at a couple of examples of this process via PowerShell and Python.

Getting A Token in Powershell

Use the following to ignore SSL errors if you are using the default self-signed certificate. Otherwise comment out the line below.

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

Here is an example way to obtain your Commvault credentials securely but requires user-interaction. If user-interaction is not possible there are other ways to safely store a password.

$credential = Get-Credential -Message "Enter Commvault Admin Credentials"
$username = $credential.UserName
$password = $credential.GetNetworkCredential().password

The password then needs to be converted to base64 format for login to be successful. The following commands will convert to the correct format for use by Commvault

$password = [System.Text.Encoding]::UTF8.GetBytes($password)
$password = [System.Convert]::ToBase64String($password)

The next step is creating the header and body for login. The steps are generic for creating the header, but the body will include the Commvault login data that we stored in $credential.

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Accept", "application/json")
$headers.Add("Content-Type", "application/json")
$body = "{`n  `"password`": `"$password`",`n  `"username`": `"$username`",`n  `"timeout`" : 30`n}"

The Invoke-RestMethod is the primary method PowerShell uses to interact with the Rest API. We can make a call to the Web Console API login page. Since we are completing an action that requires our input, we are completing a POST call. We provide the header and body data and store the response we get so we use to parse out the token.

$response = Invoke-RestMethod 'http://mycommserve.mycompany.lab/webconsole/api/Login' -Method 'POST' -Headers $headers -Body $body

We can strip out the token from the response by expanding out one of the properties. The response is an object with properties in PowerShell.

$token = $response | Select-Object -ExpandProperty token

The last item to complete is to strip out the first five characters of the token for use in Commvault otherwise you will get an error. The variable $token now has everything we need to complete further actions with the Rest API

$token = $token.substring(5)

We can now build the header with the token we now have. Go get some tea!

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Accept", "application/json")
$headers.Add("Authtoken", "$token")
$headers.Add("Content-Type", "application/json")

Getting a Commvault Rest API Token using Python

Python has two primary ways of interacting with the Commvault Rest API via different libraries. The two primary libraries are requests and http.client. Neither is particularly better but different ways of accomplishing the same thing. I would say, however, that the requests library seems to be more popular and thus there is more information available on the internet.

Python Requests Library

It is necessary in Python to specify the libraries required by the script at the beginning. Also, by default requests may not be installed. You can run pip install requests if necessary

import requests
import json
import getpass
import base64
import ssl

If the Web Console is using self-signed certs than add the following line to avoid error otherwise comment out.

ssl._create_default_https_context = ssl._create_unverified_context

The following will obtain the username and password via user-interaction. The password will be stored securely (encrypted).

username = input("Enter username:")
password = getpass.getpass()

It is necessary to convert the password into base64 format as Commvault requires this.

b = base64.b64encode(bytes(password, 'utf-8'))
fixed = (b.decode('ascii'))

We can store the Web Console (Command Center) URL in a variable. Usually, the Command Center URL is on the CommServe but not always

url = "https://mullen/webconsole/api/Login"

The final step for login is to create a header and body for our POST login call to the Rest API.

body = {'password': fixed,  'username': username, 'timeout': 30}
body = json.dumps(body)
headers = {
  'Accept': 'application/json',
  'Content-Type': 'application/json'
}

We now have everything we need to make a POST call to the Rest API including the URL, header, and body. NOTE: It is required to add verify=False if using a self-signed cert on the server.

response = requests.request("POST", url, headers=headers, data=body, verify=False)

Once the response is stored in a variable, we can extract the token. First, we will need to convert the response from JSON to text. From there we can extract the token and strip the first 5 characters just as we did with PowerShell earlier.

jsres = json.loads(response.text)
x = (jsres['token'])
token = x[5:]

Below is an example of building the header with the token we now have.

url = "http://mullen/webconsole/api/v2/Plan"

body={}
headers = {
  'Accept': 'application/json',
  'Authtoken': token
}

response = requests.request("GET", url, headers=headers, data=body)

jsres = json.loads(response.text)
print(jsres)

Python Http Library

Python has two primary ways of interacting with the Rest API via different libraries. The following process details obtaining a token via the http.client library

import getpass
import http.client
import json
import base64
import ssl

If the Web Console is using self-signed certs than add the following line to avoid error.

ssl._create_default_https_context = ssl._create_unverified_context

The following will obtain the username and password via user-interaction. The password will be obtained and stored securely (encrypted).

username = input("Enter username:")
password = getpass.getpass()

It is necessary to convert the password into base64 format as Commvault requires this format

b = base64.b64encode(bytes(password, 'utf-8')) # bytes
# Convert from object to text
fixed = (b.decode('ascii'))

The process to create the body and header for login is different than the requests library. Specify the FQDN or hostname for the conn object which creates the connection.

conn = http.client.HTTPSConnection("FQDN")
body = {'password': fixed,  'username': username, 'timeout': 30}
body = json.dumps(body)
headers = {
  'Accept': 'application/json',
  'Content-Type': 'application/json',
}

The next step is to make the login call to the Commvault Rest API. Instead of directly referencing the URL you specify everything after the FQDN as the previous connection was established

conn.request("POST", "/webconsole/api/Login", body, headers)
res = conn.getresponse()
data = res.read()
jsres = json.loads(data)

Finally, we can extract and store the token for use.

x = (jsres['token'])
token = x[5:]

Various Techniques

Obtaining an Id. Some JSON will require and Id for an object such as a Plan or Server Group. You will have the name but not the Id. Below are a couple of examples of obtaining an Id.

Obtaining a Plan Id

In this case we have a Plan name and if we find it in the list of Plans received via the Rest GET call, we will extract the Id and store it in a variable for later use

$planName = "Basic30_Day"
$commserve = "MyCommServe.local"

$response = Invoke-RestMethod "http://$commserve/webconsole/api/Plan" -Method 'GET' -Headers $headers
$plan = $response.plans.plan | Where-Object planName -eq $planName
if ($plan) {
    $planId = $plan.planId
} else {
    Write-Host "Plan not found."
}

Obtaining a Server Group Id

In this case we have a Server Group name and if we find it in the list of Server (Client) Groups received via the Rest GET call, we will extract the Id and store it in a variable for later use

$accessNodes = "AccessNodeServerGroup"
$commserve = "MyCommServe.local"

# Get the Client Group ID
$response = Invoke-RestMethod "http://$commserve/webconsole/api/ClientGroup" -Method 'GET' -Headers $headers

# Accessing the "groups" array
$groups = $response.groups

#Loop through the groups to find the one we want that matches $accessNodes
foreach ($group in $groups) {
    if ($group.name -eq $accessNodes) {
        $groupId = $group.Id
    }
}