Managing vSphere Client plugin dependencies to 3rd party libraries

Whenever you integrate a solution with an existing platform there is always the question of how you deliver external dependencies required for the operation of your app/plugin/etc.

Selection of the right libraries and their versioning are particularly important to ensure the continuity, robustness and compatibily of your solution.

In the context of vSphere Client plugins these are the Java libraries which are used as OSGi bundles but most of the details discussed in this post are applicable also to plugin frontend libraries and any other product integrations.

Standard usage of libraries by plugins

Normally you would just add a required library bundle X to the set of plugin bundles and expect it to be reachable at runtime after deploying the plugin. Then your service bundle Y would have a MANIFEST.MF dependency to a package com.mycompany.mypackage exported by bundle X:
Import-Package: com.mycompany.mypackage
Upon deployment bundle Y should wire against com.mycompany.mypackage from bundle X and get access to all available classes and APIs.

Dissecting the edge cases

So what could go wrong?

In short it is one word: interoperability. It might work perfectly on your lab containing a specific version of vSphere Client and only your plugin to test but might fail on specific vSphere customer environments which normally use a wide variety of versions and multiple plugin solutions – myriad of setup combinations that noone can exhaust in the testing phase.

These issues are normally manifested as library dependency failures. Here are a few common scenarios together with what a plugin could do to prevent them:

  1. The package com.mycompany.mypackage is already delivered by the vSphere Client.
    • A) If the provided version is sufficient for the needs of your plugin ⇒ add a dependency to it and do not deliver the  bundle X library with the plugin.
    • B) If the plugin requires a different version ⇒ the Client’s version of the library will be deployed first and will become the source of com.mycompany.mypackage for the OSGi container. To use your version of the package you need to embed the library inside the service bundle Y which depends on it and add it to its Bundle-Classpath (effectively skipping OSGi):
      Bundle-Classpath: .,libraryX.jar
      Note that in this case libraryX is not a bundle, does not have a MANIFEST.MFand its classes are directly available for the classes in bundle Y. This ensures compatibility and availability of the lib but is not always a possible option and skips any possibility to reuse the library in another context without bloating your plugin in size.
  2. The library is already delivered by another plugin.
    • A) If the Client is vSphere Client (HTML) version 6.5U1 or above ⇒ OSGi Sandboxing feature makes sure your plugin cannot clash with the existing one on this common dependency as each plugin is deployed in its own dedicated dependency scope. In this case just deliver your library as an OSGi bundle X with the plugin.
    • B) If the Client is vSphere Client (HTML) version earlier than 6.5U1 or vSphere Web Client (Flex) ⇒ During deployment of your plugin your version of com.mycompany.mypackage will be ignored and your services will be wired against the existing package version from the other plugin. Generally, this leads to undefined behavior – most commonly sporadic failures at runtime. The reason is that the plugin is not written with the provided package version in mind and might use API that does not exist in this version.

While 1B) and 2A) do not require strictly following OSGi dependency best practices those are not always possible and available options. For example vSphere Client delivers Spring Framework at its core and does not allow plugins to bring in their own version of it.

On the other hand 1A) and 2B) demand a versioning policy with the following specifics:

  • It needs to be not too tight to preserve the plugin’s backward compatibility with new vSphere Client versions which might be using an upgraded com.mycompany.mypackage version. Keeping libraries updated to new versions is a common requirement for platform vendors for various reasons (e.g. security vulnerabilities discovered in old versions).
  • It needs to be not too loose to prevent claiming support for vSphere Client versions which are actually not supported and where the plugin fails. Otherwise the plugin solution does not fail fast and leaves the user in the dark of what is really supported and working.

Defining the package dependency and versioning

Let’s go through the stages of defining the dependency and analyze them:

Import-Package: com.mycompany.mypackage ⇒ Not a good idea! This is an invitation to wire our bundle Y against any version of the package available, even ones which don’t contain the needed classes and APIs at runtime.

Import-Package: com.mycompany.mypackage;version="1.3" ⇒ This means that bundle Y will be wired against package version 1.3 or above. It is better than not specifying a version but it is very likely that the plugin will not work if wired against, say, com.mycompany.mypackage version 2.5 that contains many changes to the classes and APIs being used.

Import-Package: com.mycompany.mypackage;version="[1.3,1.3]" ⇒ This is a closed range containing a single version. Let’s say you checked version 1.3 is delivered by the vSphere Client so this is what you use to explicitly state the version bundle Y is guaranteed to work with. So far so good – the plugin will be robust on the current Client version but what happens if a new vulnerability is found in version 1.3 ? The next vSphere Client release will probably contain an update to bundle X which exports com.mycompany.mypackage with version 1.4 and the plugins compatibility will be broken.

Import-Package: com.mycompany.mypackage;version="[1.3,2.0)" ⇒ That’s more like it! Like in the previous two options we limit the required versions of com.mycompany.mypackage. This time, though, we can be confident that any version between 1.3 and 2.0  would work for bundle Y because the standard API lifecycle for libraries insists on doing backward incompatible API changes only on major versions of the library. It has the responsibility to always preserve backward compatibility across minor/patch versions. There is no 100% guarantee for that but most libraries are and should be good citizens in that regard – otherwise consider moving away from using them.

One note on the version specification: the range end indicates version 2.0 but excludes it as it may contain disruptive API changes while still allowing support for all minor and patch versions of major version 1.x of the library.

Rule of thumb: Define dependency versioning as a range starting from the lowest version you support (inclusive) and ending on the lowest version you don’t claim support for (exclusive)!

 

All of the above examples are based on OSGi but the mentioned approach is applicable to a wide variety of use cases – both for vSphere Client plugins and for other platforms and services.

For instance, the same recommendation stands for defining a plugin’s dependency to the vSphere Client version in the plugin-package.xml:

<dependencies>
<pluginPackage id="com.vmware.vsphere.client" version="6.0.2" match=“greaterOrEqual" />
<pluginPackage id="com.vmware.vsphere.client" version=“6.7.0" match=“lessThan" />
</dependencies>

Wrapping up

Dependency management of plugins in the vSphere Client is a topic with sufficient complexity within the current architecture. The SDK and the underlying platform are continuously improving in that regard but following good dependency practices is always the right way to ensure stable and robust operation of plugins.

Here are some links with nice details on this topic from the official SDK & plugins documentation:

If you have questions, suggestions or war stories to share from the field please comment in the section below.

Vladimir Velikov

I am a leading software engineer in the vSphere Client SDK & Plugins team at VMware. I like good object-oriented designs, API & extensibility development and UX workflows with neat usability but most of all I enjoy helping out plugin developers, getting their feedback and solving their real-world problems.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.