APIs

API v310.64 Documentation Available

Greetings,

The v310.64 API documentation is now available on Tintri’s GitHub site. So what’s new:

  • Four new systemProperty APIs which allows customization of the following system properties:
    • used percent alert low threshold
    • used percent aler high threshold
    • reserves used percent alert threshold
    • use percent disable snapshots threshold
    • use percent disable replication threshold
  • more Datastore statistics
    • snapshot space saving factor
    • space savings factor including snapshot savings

For more explanations on system properties, go to the systemProperites Data Transfer Object (DTO) documentation; and for more information on the new snaphot factors, go to the DatastoreStat DTO documentation.

Currently the PowerShell Toolkit and the Python SDK do not support the system property APIs except in raw API form.  See SysPropertyManger.ps1 for an example. However, the new information in the Datastore DTO is available to the Python SDK and the PowerShell Toolkit.

Happy coding,

– Rick –

Advertisements

Invoke-RestMethod Exception Handling with Tintri APIs

Greetings,

Recently, I’ve been working in PowerShell.  Tintri has a great PowerShell Toolkit, but unfortunately some APIs cannot be invoked via the Toolkit.  So to invoke APIs that are not in the Toolkit, you can use Microsoft’s Invoke-RestMethod.  In this blog, I’m only going to discuss exception handling.

Try {
    $resp = Invoke-RestMethod -Uri $url -Method Delete -WebSession $session -ContentType $JSON_CONTENT
}
Catch {
    # Obtain some information
    $expMessage = $_.Exception.Message
    $failedItem = $_.Exception.Source
    $line = $_.InvocationInfo.ScriptLineNumber

    # Check if there is a response.
    if ($_.Exception.Response -eq $null) {
        Write-Host "At $($line):`r`n$expMessage" -ForeGroundColor Red
    }
    else {
        # Get the response body with more error detail.
        $respStream = $_.Exception.Response.GetResponseStream()
        $reader = New-Object System.IO.StreamReader($respStream)
        $respBody = $reader.ReadToEnd() | ConvertFrom-Json
        $errorCode = $respBody.code
        $errorMessage = $respBody.message
        $causeDetails = $respBody.causeDetails
       Write-Host "At line $($line):`r`n$expMessage`r`n$($errorCode): $errorMessage`n`r $causeDetails" -ForegroundColor Red
    } 
}

Take the example code above where we invoking a GET API.  The variable $session is the session ID and $url is of course the API URL.

If there is an Invoke-RestMethod() error, the exception is thrown and the Catch block is executed.  When a Tintri API error occurs Invoke-RestMethod does not return any data, and there is more information in the API response.  See the Error Handling section in the API documentation where the error response is documented:

{"typeId":"com.tintri.api.rest.v310.dto.domain.beans.TintriError",
 "code":"ERR-API-8001",
 "message":"Failed to find requested resource of type VirtualMachine with id: 'xxxxddd'",
 "causeDetails":"",
 "title":"Resource not found"
}

So how do you get that error information in the response?  Fortunately Chris Wahl shared some great information on his blog.  As you can see, the first three bold lines in the second part of  the Catch block is directly from Chris.  The italicized part is what I added for Tintri errors.

The code now checks Exception.response; therefore, this Catch block can now handle both non-Tintri and Tintri errors.  I changed Write-Error to Write-Host with a red foreground color for simpler output.

The response stream returns a string.  To get the error code and the error message, the split function would need to be used twice within a loop; or just call ConvertFrom-JSON which which gives us a nice dictionary to easily pluck out errorCode, errorMessage, and causeDetails.

Until next time,

– Rick –

 

Private Cloud Automation

I want to point out a set of 4 postings by Matthew Geddes, a Hyper-V architect, on Automation and Private Cloud.

  1. Part 1: sets the stage: a number of production SQL Server instances where some nightly reporting jobs are run. These reporting jobs are quite heavyweight and impact other users during their large processing window. What we want to do is to have the reporting jobs run on non-production VMs with that day’s production data.
  2. Part 2: shows how how to use syncVM from Tintri’s PowerShell Toolkit.  Matt breaks down usage of the PowerShell cmdlet, Sync-TintriVDisk; and then shows how to integrate it into a small script.
  3. Part 3: adds more code to the small script and wraps it into a function so that it can be used for multiple reports.
  4. Part 4: adds more automation with by showing how to parameterize the reports.  Matt summarizes and gives you some homework.

I like the way Matt goes through presents the use case, and then goes through the code step by step.

Until next time,

– Rick –

Automation, Cloud, Containers, and PySDK

Greetings,

November has started with a bang of announcements and publications:

  1. Tintri Raises the Bar for Enterprise Cloud Build on Web Services Architecture and RESTful APIs” discusses Tintri’s architecture, automation, container support, analytics, and public cloud integration.  There will be a webinar on November 10th at 11 am Pacific with Kieran Harty and Steve Herrod.
  2. The Register’s article on Tintri’s Chatbot , automation, cloud, and container support talks about Tintri’s Web Services approach that makes everything API-accessible which makes automation , container support, public cloud integration, and chat-bot possible.
  3. ComputerWeekly.com published an article of “Tintri adding VMware and Flocker persistent container storage” which discusses Tintri’s container Flocker support in more detail.
  4. Tintri announced the release of the Python SDK (PySDK). This PySDK was used in the above mentioned chat-bot. With PySDK, Tintri will be able to integrate easier with automation platforms like OpenStack.
  5. Tintri published a white paper on Tintri’s vRealize Orchestrator Plugin. Now VMware’s vRealize orchestrator can manage Tintri storage.  This allows scripts in vRealize to invoke Tintri management APIs.

This is just the beginning of Tintri’s cloud announcements.  More will be coming in the next months.  Until next time,

– Rick –

VM Scale-out Code Examples

There is a new blog about automating VM scale-out migration recommendations on the corporate Tintri site. Along with that script I wrote another script to set VM affinity for VM scale-out migration rules. These rules allow you to exclude VMs from being considered for migration.

Let’s look at a use case. Suppose there is one Flash VMstore, and 2 hybrid VMstores in a VMstore pool. VDI is running in your Flash VMstore, and you don’t what the VDI VMs to migrate to the hybrid VMstores, therefore, the VDI VMs are put into a Service Group by name pattern. Unfortunately, the script would have to be executed periodically because affinity is set at the VM level.  When a VM is added to the Service Group, the script needs to be executed.

VMs are excluded with --affinity set to ‘never‘.  VMs are specified by a service group, --sg, by a list of VM name, --vms, or by pattern matching with --name. To clear the affinity set --affinity to ‘clear‘.

So let’s look at the script, set_reco_vm_affinity.py.

# Let's get to work
try:
    if (len(vms) > 0):
        print("Collecting VMs from list")
        vm_uuids += get_vms_in_list(server_name, session_id, vms)

    if (service_group != ""):
        print("Collecting VMs from service group")
        sg_uuid = get_sg_by_name(server_name, session_id, service_group)
        if (sg_uuid == ""):
            raise tintri.TintriRequestsException("Can't find service group " + service_group)

        vm_uuids += get_vms_by_sg(server_name, session_id, sg_uuid)

    if (vm_contains_name != ""):
        print("Collecting VMs from name")
        vm_uuids += get_vms_by_name(server_name, session_id, vm_contains_name)

    if (len(vm_uuids) == 0):
        raise tintri.TintriRequestsException("No VMs to set rules")

    if debug_mode:
        count = 1
        for uuid in vm_uuids:
            print(str(count) + ": " + uuid)
            count += 1

    # Process according to affinity
    if (affinity == "never"):
        set_vm_affinity_never(server_name, session_id, vm_uuids)
    elif (affinity == "clear"):
        clear_vm_affinity(server_name, session_id, vm_uuids)
    else:
        raise tintri.TintriRequestsException("Bad affinity rule: " + affinity)

except tintri.TintriRequestsException as tre:
    print_error(tre.__str__())
    sys.exit(4)
except tintri.TintriApiException as tae:
    print_error(tae.__str__())
    sys.exit(5)

In the above snippet, the code figures out the list of VMs and processes for the specified affinity.

The crux of this script is how to set the affinity:

# A helper function  that sets the VM affinity rule for migration recommendations.
def set_vm_affinity(server_name, session_id, vm_uuids, affinity_rule):
    url = "/v310/vm/"

    for vm_uuid in vm_uuids:
        rule_url = url + vm_uuid + "/affinity"

        r = tintri.api_put(server_name, rule_url, affinity_rule, session_id)
        if r.status_code != 204:
            tintri.api_logout(server_name, session_id)
            message = "The HTTP response for put affinity rule to the server is not 204."
            raise tintri.TintriApiException(message, r.status_code,
                                            rule_url, str(affinity_rule), r.text)
        sys.stdout.write(".")
    print("")

# Set the VM affinity rule to never for a list of VMs.
def set_vm_affinity_never(server_name, session_id, vm_uuids):
    print("Setting " + str(len(vm_uuids)) + " VMs to never migrate")

    affinity_rule = \
        {"typeId" : beans + "vm.VirtualMachineAffinityRule",
         "ruleType" : "NEVER"
        }

    set_vm_affinity(server_name, session_id, vm_uuids, affinity_rule)

# Clear the VM affinity rule for a list of VMs
def clear_vm_affinity(server_name, session_id, vm_uuids):
    print("Clearing " + str(len(vm_uuids)) + " VMs affinity rules")

    affinity_rule = \
        {"typeId" : beans + "vm.VirtualMachineAffinityRule",
        }

    set_vm_affinity(server_name, session_id, vm_uuids, affinity_rule)

In the function set_vm_affinity(), we see the API invoke /v310/vm/{vm_uuid}/affinity. For each VM UUID in the input list, the API is invoked. There are two helper functions set_vm_affinity() and clear_vm_affinity to facilitate.

Although it has been discussed before, you can review how to get the VMs in a service group with this snippet of code.

# Return a list of VM UUIDs based on a service group name.
def get_vms_by_sg(server_name, session_id, sg_uuid):
    vm_uuids = []
# Get a list of VMs, but return a page size at a time
vm_filter = {"includeFields" : ["uuid", "vmware"],
             "serviceGroupIds" : sg_uuid
            }
vm_uuids = get_vms(server_name, session_id, vm_filter)

return vm_uuids

# Return VM items constrained by a filter.
def get_vms(server_name, session_id, vm_filter):
vm_uuids = []

# Get a list of VMs, but return a page size at a time
get_vm_url = "/v310/vm"
vm_paginated_result = {'next' : "offset=0&limit=" + str(page_size)}

# While there are more VMs, go get them, and build a dictionary
# of name to UUID.
while 'next' in vm_paginated_result:
    url = get_vm_url + "?" + vm_paginated_result['next']

    r = tintri.api_get_query(server_name, url, vm_filter, session_id)
    print_debug("The JSON response of the VM get invoke to the server " +
                server_name + " is: " + r.text)

    # For each VM in the page, print the VM name and UUID.
    vm_paginated_result = r.json()
    print_debug("VMs:\n" + format_json(vm_paginated_result))

    # Get the VMs
    items = vm_paginated_result["items"]
    for vm in items:
        vm_uuids.append(vm["uuid"]["uuid"])

return vm_uuids

Before I close this post, I would like to mention that you can post API questions on Tintri’s Hub. Until next time,

– Rick –

Adding VMs to a Service Group

Greetings,

A colleague, Adam  Cavaliere, wrote a Python script that adds VM name from a CSV file to a TGC Service Group. The script, set_service_group_members.py is now on Tintri’s GitHub site.

This script asks for the user name and password interactively instead being on the command line.  The command line only has the TGC server name, the TGC service group to put the names into, and the CSV file name that contains the VM names.

Let’s look at the salient part of the code.

if service_group_exists:
    target_sg_api = "/v310/servicegroup/" + target_sg + "/members/static"
    print("Service Group Found")

payload = {'typeId':'com.tintri.api.rest.v310.dto.CollectionChangeRequest', \
           'objectIdsAdded': uuid_list
}

# Set the static members.
tt.api_put(server_name, target_sg_api, payload, session_id)

Here we have the API invoke to update the static members of the specified service group with a list of VM UUIDs.  The list of VM UUIDs are added to payload before the api_put() call.

The code below obtains the target_sg for the update service group static members API URL  It performs a GET servicegroup and looks for the specified service group and extracts the service group UUID.

# Get List of Service Groups
api = "/v310/servicegroup"
results = tt.api_get(server_name, api, session_id)
service_groups = results.json()

service_group_exists = False

# setup API for adding VMs to proper Service Group
for item in service_groups["items"]:
    if item["name"] == service_group:
        service_group_exists = True
        target_sg = item["uuid"]["uuid"]
        break

From a list VM names, the VM UUIDs are collected in the get_vm_uuids() function. This function takes as input a list of VM names and returns a list of found VM names and their UUIDs.  The GET vm API is is used.  I have discussed this in previous blogs. The UUID list is used in the payload above.

That pretty much covers it,

– Rick –

GitHub API Python Examples Updated

Greetings,

The API python examples on the Tintri GitHub site have been updated.

The library, python_1_1.py has been updated to disable SSL warnings. To facilitate this, a new method, api_version(), has been added to the library. It replaces the /info GET invoke.

All the API python client examples have been updated to use the python_1_1.py library and api_version() method. Since api_version() returns the same values as /info, the change is minimal. Here is an example diff:


 - r = tintri.api_get(server_name, '/info')
 + r = tintri.api_version(server_name)
      json_info = r.json()
      product_name = json_info['productName']

A new API client example, set_qos_tgc_service_groups.py is now available. This example shows how to use the new QoS TGC Service Group APIs. With the new APIs, configuring QoS for Service Groups has been simplified. The blog, TGC Service Groups and QoS Redux discusses this new QoS example.

Regards,

– Rick –

Some API differences with Virtually Aware Flash Storage

Greetings,

Tintri has just announce the T5000 All-Flash series.  This means that customers that desire all-flash storage now can have it all: flash, and virtually aware storage (VAS).  I recently blogged about some API and UI changes.

I wanted to go into a little more detail about the API changes.  The All-Flash code snippet in the blog is from an updated appliance_info.py. All the python files in the  Tintri API GitHub repo were updated with a more common python location for easy script running.

As for dedupeFactor and cloneDedupeFactor in the DatastoreStat object discussion, I hope the tables below clarify.  The first table shows the responses when invoking the following APIs from a VMstore.

  • GET /v310/datastore
  • GET /v310/datastore/{uuid}/statsHistoric
  • GET /v310/datastore/{uuid}/statsRealtime
  • GET /v310/datastore/{uuid}/statsSummary
Responses from VMstore
Field All-Flash Hybrid (4.0) Hybrid (3.2)
dedupFactor Valid Valid Not Available
cloneDedupFactor 1.0 Valid Valid

As you know, Tintri Global Center (TGC) and VMstore have the share some above API endpoints, but the responses can be different. Here is the table for the TGC responses:

Responses from TGC
Field All-Flash Hybrid (4.0) Hybrid (3.2)
dedupFactor Valid Valid 1.0
cloneDedupFactor 1.0 Valid Valid

As you can see, invoking the APIs via a TGC masks the “Not Available” for a consistent return for all fields.

Until next time,

– Rick –

PowerShell Automation Toolkit 2.0

Greetings,

Just a quick note to inform you that the PowerShell Automation Toolkit version 2.0 is now in Tech Preview.  Tech Preview means that the toolkit is available for download and we want your feedback.  In brief, the PowerShell Toolkit 2.0 includes these features:

  1. TGC Service Groups
  2. Setting QoS policies per VM
  3. Hyper-V VM Cloning
  4. High Frequency Snapshots
  5. Deleting Snapshot Schedules
  6. SSO authentication with VMstore
  7. SyncVM

When the new GitHub code examples are available, I’ll let you know.

Regards,

– Rick –

Orchestration and Tintri APIs

Greetings,

I’d like to point out two orchestration examples that are using Tintri APIs.

The first one is by Nick Colyer on vRrealize orchestration. Nick created vRealize workflows that use Tintri APIs.  The series of posts show workflows that create a Tintri session, obtain a Tintri VM UUID, and perform a Tintri snapshot.

The second by is by a company called Emitrom, which create an orchestrator call Integra.  David LaMotta of Emitrom created a workflow that backs-up a VM to the AWS.  He also did a workflow that restores the VM from the AWS.  These workflows use the Tintri PowerShell Toolkit which is imported into Integra which allows each PowerShell commandlet to be a command in Integra.

I hope you can make use of these examples in your admin environments,

– Rick –