Finding vRA Virtual Machines upon successful Catalog Item Request Completed event

Purpose

When it comes to capturing events from vRA 7.x+ through the means of EBS and performing an action through vRO, we need to be specifically aware of the different type of events and what kind of attributes they will carry. Overall vRA provides a decent information during subscription creation, however, some of the event attributes might pose challenges working with.

In addition some of the events could be blocking ones, which means they would block the vRA execution until the vRO WF has completed with successful status. These events are useful when you want control over the vRA process and ability to influence it's completion.

I've recently had to design a method in which the vRA Blueprint, containing several VMs are automatically placed in vSphere DRS VM Affinity groups after the Blueprint is successfully provisioned. For this purpose I've decided I have to wait for the complete Blueprint to be provisioned and only after that to hook in and perform the orchestration. Because my vRO WF would perform certain validation, I had to keep the control and hook in a blocking type of event so that any errors the vRO WF throws would revert the Blueprint provisioning and clean up the environment.

This post will walk you through the steps to find out all the VMs that are provisioned out of the Blueprint and share with you common pitfalls of taking other, more obvious, routes.

Setup

For this post, I'm using following configuration:
  • vRA 7.2.0.4659752
  • vRO 7.2.0.4629841
  • vRO Plugins:
    • vCACCAFE 7.2.0.4602407
    • vCAC 7.2.0.4601797
The blueprint I have in vRA, for which I want to find machines, could be of any kind, but for the purpose of simplicity I'll use the following setup:

As you can see the blueprint consist of two vSphere Component VMs (vm-1 and vm-2). Here vm-2 would be a Clustered VM and of that definition we'll have exactly 2 VMs provisioned.

To complete our setup, we need to create an EBS Subscription:


  1. Create a placeholder vRO Workflow that might look something like that
  2. Create a new subscription in vRA

    1. Select event "Catalog item request completed"
    2. On the next screen you can narrow down the conditions on which this subscription is called. I'm filtering on bluperint id
    3. Select your target vRO WF
    4. Since I need control on the overall process, I'm finally creating a blocking subscription
With above setup we get following output of the vRO WF:


[2017-05-06 13:52:47.467] [I] Received key='taskType' = 'PROVISION'
[2017-05-06 13:52:47.468] [I] Received key='subtenant' = '26fe6dbe-2e06-49d3-8dbb-af3e2e659633'
[2017-05-06 13:52:47.469] [I] Received key='completionDetails' = ''
[2017-05-06 13:52:47.471] [I] Received key='requestId' = '108aca12-68c6-4cae-ab8f-177ab2c70694'
[2017-05-06 13:52:47.472] [I] Received key='success' = 'true'
[2017-05-06 13:52:47.473] [I] Received key='deploymentId' = 'b94c28ec-2116-4416-9899-0cde933a6b3e'
[2017-05-06 13:52:47.474] [I] Received key='blueprintId' = 'multimachineblueprint'
[2017-05-06 13:52:47.476] [I] Received key='tenant' = 'vsphere.local'
[2017-05-06 13:52:47.477] [I] Received key='requestStatus' = 'SUCCEEDED'

What's happening here?!?

Ok, maybe some explanation is due for the new-guys in the field. The setup piece above is skipping some steps in regards to Blueprint publishing, entitlement and assigning to service, these are all basic steps you can find in vRA documentation or online.

Also on step 2.1 and 2.3 you will see discrepancy between the subscription parameters and the vRO WF inputs. Yes that is fine initially, as EBS will pass on all event parameters through the "payload" Properties object, which gives us a chance to list print them all. However this payload will not include any of the "__asd_*" parameters accompanying the request.

Finally, don't forget to publish your subscription, otherwise it has no effect.

Dude, where's your Catalog Resource?

Now what happens once the user makes a Catalog Item Request (roughly):

  1. The request is performed through vRA Cafe API (and more specifically Catalog-Service).
  2. vRA internally will contact the Composition Service to orchestrate the different providers based on the Blueprint components in play.
  3. Composition Service will create the root-level Catalog Resource object representing the top-level deployment.
  4. Each provider will complete Component provisioning and notify Composition Service with provider's binding id.
  5. EBS will propagate the catalog item request completed event - this is where we are hooking up.
  6. Finally the Composition Service will create the child Catalog Resources under the top-level one, based on the providers' input.
  7. With the Catalog Resource objects created, the user can now see them under Items tab in vRA.
The important thing to note here is that we cannot rely on the Catalog Service to provide any meaningful information about the newly provisioned VMs. This is because the EBS event is propagated right before the meaningful representation objects are populated in the inventories of the service. And since we are blocking the completion with our subscription, this final step will happen right after (and only if) our vRO WF completes successfully.

So why is this important?

Well normally when you receive the Provider Binding Id (deploymentId attribute) for that resource, you would simply query for it's children as follows:

  1. First find the top-level Catalog Resource. In the workflow example output above we would use the provider bindingId (the deploymentId) to find it. For example with: consumer/resources?$filter=providerBinding/bindingId eq '{deploymentId}'
  2. Then request it's child Catalog Resources. For example with: consumer/resources?$filter=parentResource eq '{topLevelResourceId}'
  3. Then use the provider bindingId of each resource to find the VM object from IaaS by it's VirtualMachineID field.
However at the time the EBS event is propagated the top-level Catalog Resources is not fully setup, so all of the above steps are not possible.

Enough talk, show me some code...

Ok, let's get right into it. For the sake of simplicity let's assume:
- cafeHost is an instance of the the tenant's vCACCAFE:VCACHost
- iaasHost is an instance of vCAC:VCACHost

First we need to query the Composition Service to find it's representation of the deployment:
var compClient = cafeHost.createCompositionClient();
var deployment = compClient.getWithVariables("deploymentresources/{deploymentId}?includeComponentResourceData={getCompData}", [deploymentId, false]);

Note that at this step we are not requesting additional data, as that is not available and vRA will get mean to us.

This will produce response similar to:
{
&nbsp"id": "b94c28ec-2116-4416-9899-0cde933a6b3e",
  "name": "multi-machine-blueprint-96835153",
  "description": null,
  "blueprintId": "multimachineblueprint",
  "cafeResourceId": "b0f1605d-23b3-4a8e-942a-5ac56a75efda",
  "provisioningReasons": null,
  "provisioningDescription": null,
  "componentResourceData": null
}

The cafeResourceId is the top-level partially-setup Catalog Resource object. However it at this time it has not child Catalog Resources objects, so our next step would be to get it:

var catClient = cafeHost.createCatalogClient();
var catalogResource = catClient.getWithVariables("consumer/resources/{resourceId}", [cafeResourceId]);
Which returns something similar to:
{
  "id": "b0f1605d-23b3-4a8e-942a-5ac56a75efda",
  "iconId": "composition.blueprint.png",
  "resourceTypeRef": {
    "id": "composition.resource.type.deployment",
    "label": "Deployment"
  },
  "name": "multi-machine-blueprint-96835153",
  "description": null,
  "status": "ACTIVE",
  "catalogItem": {
    "id": "d1b84687-e7c6-4bfc-84b8-ab925c8a6c07",
    "label": "multi-machine-blueprint"
  },
  "requestId": "89c1d150-e15e-439a-91d3-41cb6241fce6",
  "providerBinding": {
    "bindingId": "b94c28ec-2116-4416-9899-0cde933a6b3e",
    "providerRef": {
      "id": "7fc82013-855e-4146-91a8-d2ccf34da04b",
      "label": "Blueprint Service"
    }
  },
  "owners": [
    {
      "tenantName": "vsphere.local",
      "ref": "Administrator@corp.local",
      "type": "USER",
      "value": "Administrator Administrator"
    }
  ],
  "organization": {
    "tenantRef": "vsphere.local",
    "tenantLabel": "vsphere.local",
    "subtenantRef": "26fe6dbe-2e06-49d3-8dbb-af3e2e659633",
    "subtenantLabel": "Configuration Administrators"
  },
  "dateCreated": "2017-05-06T11:29:14.484Z",
  "lastUpdated": "2017-05-06T11:40:08.453Z",
  "hasLease": true,
  "lease": {
    "start": "2017-05-06T11:29:14.445Z"
  },
  "leaseForDisplay": null,
  "hasCosts": true,
  "totalCost": null,
  "hasChildren": true,
  "operations": [],
  "forms": {
    "catalogResourceInfoHidden": false,
    "details": {
      "type": "external",
      "formId": "composition.deployment.details"
    }
  },
  "resourceData": {
    "entries": []
  },
  "destroyDate": null,
  "pendingRequests": []
}
This object contains a reference to the actual requestId which is not provided to the vRO WF during execution. That parameter is kept as a custom property on each VM in IaaS, so we can use it to find those VMs.

var vmEntities = vCACEntityManager.readModelEntitiesBySystemExpandQuery(iaasHost.id, "ManagementModelEntities.svc", "VirtualMachines", "VirtualMachineProperties/any(p:p/PropertyName eq '__Cafe.Root.Request.Id' and p/PropertyValue eq '" + requestId + "')", null, null, null, null, 0, null);

The last call will produce an array of 3 elements of type vCAC:Entity representing the IaaS VMs result of the provisioning, which was our original goal.

Comments

  1. Quality articles is the important to be a focus for the users to go to see the website, that's what this website is providing. sign in to gmail

    ReplyDelete

Post a Comment