This set of samples shows how to add or modify views for vSphere objects, and how to implement PropertyProviderAdapter to get data from vCenter or other data sources.
This plugin extends some VM and Host views and displays additional properties using simple data requests. No java code is required because the data models include only primitive vSphere object properties. The code illustrates common Data Access Framework (DAM) APIs.
Import the project views-properties-ui in Eclipse, build and deploy the bundle to the server. Start a client session and select any VM in your inventory. The Summary page displays a new portlet "Sample Summary Section View" with the running state of your VM guest:
Click on the Monitor tab to see the new sub-tab "VMSampleMonitorView", showing various VM properties:
Select a Host, its Summary page displays also a new portlet "Sample Summary Section View". It contains the list of datastores for that host:
Click on the Host's Monitor tab to see the new sub-tab "HostSampleMonitorView", showing the list of powered VMs:
In plugin.xml: the sample adds a VM portlet using the extension point vsphere.core.vm.summarySectionView. The portlet name is hard-coded and the componentClass points to the view VmSampleSummarySectionView.
In VmSampleSummarySectionView.mxml: the variable vmGuestState holds the value of the guest state which will be queried in the mediator class.
In VmSampleSummarySectionViewMediator.as:this class must implement IContextObjectHolder in order to be aware of the selected object. The method set contextObject gets called by the framework with a reference to the selected VM, which is cached locally in _contextObject. Then the data is queried with PropertyRequest event since only one property is requested. Notice the last parameter requestInfo which sets the data binding mode to "implicit", which means that the request will be issued automatically to refresh the view when the user invokes an operation.
Dispatching a PropertyRequest event works only if the class also declares that event with the [Event] tag at the top:
// Meta-tag to register this class as a source of DataRequest [Event(name="{com.vmware.data.query.events.PropertyRequest.REQUEST_ID}", type="com.vmware.data.query.events.PropertyRequest")] public class VmSampleSummarySectionViewMediator ...
The data is returned through a ResponseHandler which must be declared with the event's RESPONSE_ID:
[ResponseHandler(name= "{com.vmware.data.query.events.PropertyRequest.RESPONSE_ID}")] public function onDataRetrieved(request:PropertyRequest, result:StringDataObject, error:Error):void { ...
All data returned for vSphere objects is wrapped into one of the com.vmware.core.model.DataObject classes (here it is StringDataObject)
because it contains some extra information about the object itself (such as its reference in the provider field). The actual value we are interested in is in the value field.
If you are not sure what type will be returned in the response handler for a particular property you can declare result as Object and set a breakpoint to examine the actual variable type that is serialized back from Java.
In plugin.xml: the sample adds a Monitor sub-tab by using the extension point vsphere.core.vm.monitorViews. The view under that tab is implemented in VmSampleMonitorView.
In VmSampleMonitorView.mxml: an instance of the data model VmMonitorData holds the different values used in that view. It is always recommended to associate a data model with a view, more complex views may use more than one data models.
VmMonitorData.as shows how to declare a DAM data model, i.e. a data structure with metadata tags mapping object properties to specific fields.
In VmSampleMonitorViewMediator.as: the pattern is the same as before, the data is requested once the contextObject is known to the view. But since we use a data model here the correct API is DataByModelRequest. The result in the ResponseHandler method has the same VmMonitorData type so it's simple to assign it directly to the view variable vmData.
In plugin.xml: the sample adds a Host portlet using the extension point vsphere.core.host.summarySectionView. The content of the portlet is implemented by the view HostSampleSummarySectionView.
In HostSampleSummarySectionView.mxml: we use the standard Flex DataGrid to display a list of objects. Its dataProvider is bound to the datastoreItems array variable that will be initialized in the mediator class. The model class DatastoreDataItems defines the data fields "name" and "type" displayed in the list.
HostSampleSummarySectionViewMediator.as is the associated mediator class where the query is handled. It uses the more advanced DataByConstraintRequest API because we need to define a constraint representing the datastores associated with a host, i.e. the objects targeted by the query will be the array of datastores in the host's datatore property. The QuerySpecUtil utility methods provided in this sample can be copied and re-used in other plugins!
// First create a constraint to find all datastores for this host var constraint:Constraint = QuerySpecUtil.createConstraintForRelationship(_contextObject, "datastore"); // Then create a DataByConstraintRequest to get the DatastoreDataItem properties for each datastore var request:DataByConstraintRequest = DataByConstraintRequest.newInstance(constraint, DatastoreDataItem);
The result in the ResponseHandler has the type ArrayCollection because the query is for a list of object. The array items are of type DatastoreDataItem since this is the data model used in DataByConstraintRequest. Then, filling up the list in the UI is just a matter of doing the assignment _view.datastoreItems = result;.
In plugin.xml: the sample adds a Host Monitor sub-tab using the extension point vsphere.core.host.monitorViews. The content of the tab is implemented by the view HostSampleMonitorView.
HostSampleMonitorViewMediator.as is the associated mediator class where the query is handled. It demonstrates the use of DataByConstraintRequest and gives an example of a compositeConstraint. This is a little more complex but hopefully self-explanatory!
// Constraint for the "vm" relationship on a host, i.e. this will fetch the list of VMs. var vmListConstraint:Constraint = QuerySpecUtil.createConstraintForRelationship(_contextObject, "vm", "VirtualMachine"); // Constraint for the "runtime.powerState" property of a VM to keep only the poweredOn VMs var vmPowerStateConstraint:Constraint = QuerySpecUtil.createPropertyConstraint("VirtualMachine", "runtime.powerState", Comparator.EQUALS, "poweredOn"); // Combine the 2 constraints, in order to filter the list of VMs with the poweredOn ones var compositeConstraint:Constraint = QuerySpecUtil.createCompositeConstraint( [vmListConstraint, vmPowerStateConstraint], Conjoiner.AND, "VirtualMachine"); // Send the data request to the server using the VmdataItem model for the properties to retrieve. var vmListRequest:DataByConstraintRequest = DataByConstraintRequest.newInstance( compositeConstraint, VmDataItem, requestInfo);
This sample demonstrates how to use the vSphere Web Service SDK (WSSDK) on the server side to access vCenter data that you may not be able to get using the Data Request models shown before. More generally the WSSDK API provides access to the vSphere managed objects that can be used to manage, monitor, and control life-cycle operations of all virtual infrastructure components (vms, datacenters, datastores, networks, etc.). This sample shows how to retrieve object properties but the same WSSDK could be used to implement specific vCenter operations in your plugin.
This sample uses the VMware's WSSDK library vim25.jar, located in /vsphereviews/vsphere-wssdk-provider/lib. In order for the Virgo server to load this library during development it must be copied first in the /server/repository/usr directory, see How to use 3rd party libraries for details. (The other library, commons-logging-1.1.1.jar is already part of the Virgo repository.)
To run this sample in Eclipse/STS import both projects vsphere-wssdk-ui and vsphere-wssdk-provider, build them and deploy the bundles to the server; vsphere-wssdk-provider must be added first since vsphere-wssdk-ui requires it to be deployed successfully. Start a client session and select any VM in your inventory. The Monitor page has a new sub-tab view "wssdk-ui sample" showing some VM data returned by vsphere-wssdk-provider:
The UI code is close to the VmSampleMonitorVIew sample above. The main difference is that VsphereWsSdkVmMonitorViewMediator uses a PropertyRequest to retrieve a custom property named samples:vmData. This sample is not querying directly vSphere object properties as before, it implements its own PropertyProviderAdapter on the java side to handle the requests for "samples:vmData". Note that your custom properties should always include a namespace to avoid possible collisions with vSphere property names or other plugins' properties.
VmDataProviderImpl.java is the interesting java code to review. Here are some key implementation aspects:
The rest of the code is specific to the WSSDK API so we recommend that you follow that API documentation to become more familiar with it.
This sample demonstrates the use of a web service in the data provider, to fetch data from a source other than vCenter. It also shows how to pass a parameter in a PropertyRequest and how to return DataException with the result.
This sample uses the Google library gson-2.0.jar, located in /vsphereviews/custom-property-provider/lib. In order for the Virgo server to find this external library during development you should copy it first in the /server/repository/usr directory (see How to use 3rd party libraries for details).
To run the sample in Eclipse/STS, import both projects custom-properties-ui and custom-properties-provider, build them and deploy the bundles to the server; custom-properties-provider must be added first since custom-properties-ui requires it to be deployed successfully. Start a client session and select a Host from your inventory. The Monitor page has a new sub-tab view "Host Elevation" showing a form when you can enter the latitude and longitude of the host's location. Click "Get Host Elevation" and see the elevation returned.
If you don't get any elevation data it is usually because of a connection error trying to access the Google Maps web service (you should see the error dialog below and also errors in the Virgo log). Your work place may require a proxy to let Virgo to access the internet. There are 2 ways to do that:
In plugin.xml: the sample adds a Host Monitor sub-tab using the extension point vsphere.core.host.monitorViews. The content of the tab is implemented by the view CustomPropertyHostView.
CustomPropertyHostView.mxml contains a simple form to enter Latitude and Longitude parameters (tip: it's easy to find yours by search "[your city] latitude longitude" with Google!). Notice the hostElevationData variable used to display the result, it will be set in CustomPropertyHostViewMediator.as when the server call returns.
CustomPropertyHostViewMediator.as uses a PropertyRequest to retrieve a custom property named samples:elevationData. This code is not querying vSphere API properties as before, it implements its own PropertyProviderAdapter on the java side to handle property "samples:elevationData".
Notice also the addition of a parameter to the data request before dispatching the event. You can pass any object this way:
hostElevationDataRequest.parameter = earthLocation;
The ElevationData.as class is mapped to its counterpart ElevationData.java class using the RemoteClass metadata tag to ensure correct Flex-Java serialization of the object.
CustomHostPropertyProviderImpl registers itself with DataServiceExtensionRegistry and declares the types and properties it can handle. The platform's Data Service will call this provider whenever a request is sent for property "samples:elevationData" on objects of type "HostSystem".
See also how the GoogleService is injected in the constructor, this is the recommended way to access other beans.
Notice the exception handling using the DataException API. For instance if the connection to Google Map doesn't work you would get the error message from the image above.
try { ElevationData data = _googleService.getElevationData(location.latitude, location.longitude); ... } catch (Exception e) { _logger.error("CustomHostPropertyProviderImpl.getProperties error", e); // Passing the exception in the result allows to display an error notification in the UI. DataException de = DataException.newInstance(e, propertyRequest.objects, propertyRequest.properties[0].propertyNames); result.error = de; }
GoogleService.java implements the call to the Google Maps API, converting the Json result into the ElevationData object that the UI is expected.
See also: Other samples - SDK Tutorial - FAQs - Flex API docs - Java API docs