Question

I'm trying to use Jclouds in my application in such a way that it can work with multiple providers at the same time. Specifically, I'm trying to use the "openstack-nova" provider and the "rackspace-cloudservers-us" provider so that I can provision nodes in two different clouds at runtime. However, it appears that the providers are stomping on one another; when I include both dependencies in my Maven build, the Rackspace provider is the only one available in the provider list:

  <dependency>
    <groupId>org.apache.jclouds.provider</groupId>
    <artifactId>rackspace-cloudservers-us</artifactId>
    <version>1.7.0</version>
  </dependency>
  <dependency>
    <groupId>org.apache.jclouds.api</groupId>
    <artifactId>openstack-nova</artifactId>
    <version>1.7.0</version>
  </dependency>

Commenting out the Rackspace provider dependency will allow the openstack-nova to work. Is there not a way to have multiple providers with Jclouds at the same time?

Was it helpful?

Solution 2

I figured this out, but forgot that I'd asked this question. Here's what happened.

The jClouds providers register themselves with Java ServiceLoaders. This means that theres a little file in the META-INF/services directory that has provider classname which the jClouds core injects at runtime. I was making a fat JAR with Shade, which meant that the contents of this file were overwritten in the final JAR.

This left one entry instead of two, so at runtime jClouds couldn't find the other provider. I had to add a configuration option to make sure Shade didn't stomp out this file. This was something I was already doing for Spring, so once I realized what jClouds was doing it was a pretty simple fix.

Here's what my plugin config looked like for anyone that's curious:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>shade</goal>
        </goals>
        <configuration>
          <createDependencyReducedPom>false</createDependencyReducedPom>
          <transformers>
            <!--Need to do this to make sure spring schemas dont stomp on each other-->
            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
              <resource>META-INF/spring.handlers</resource>
            </transformer>
            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
              <resource>META-INF/spring.schemas</resource>
            </transformer>
            <!-- Need to make sure jClouds providers play nicely -->
            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
              <resource>META-INF/services/org.jclouds.apis.ApiMetadata</resource>
            </transformer>
            <!--Executable JAR-ify this-->
            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
              <mainClass>com.example.Main</mainClass>
            </transformer>
          </transformers>
        </configuration>
      </execution>
    </executions>
  </plugin>

OTHER TIPS

That should work perfectly. You should be able to create a context by passing "rackspace-cloudservers-us" to the ContextBuilder or "openstack-nova" (in fact openstack-nova is a transitive dependency of the rackspace provider so you'll have it in the classpath even if you don't explicitly declare it). What concrete issues are you having?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top