I'm trying to integrate Apache jClouds into a Java project so I can access the OpenStack API. The following code fails:
neutronApi = ContextBuilder.newBuilder("openstack-neutron")
.credentials(USERNAME, API_KEY)
.endpoint(AUTH_URL)
.modules(modules)
.buildApi(NeutronApi.class);
With the following error message:
Java.util.NoSuchElementException: key [openstack-neutron] not in the list of providers or apis: {providers=[ultradns-ws], apis=[swift, swift-keystone]}
This is apparently a common problem, however the suggestions offered in jClouds troubleshooting don't resolve it. There's another StackOverflow discussion about this problem but does not have an accepted answer.
A few useful points:
- Our Java project uses Ant, whereas jClouds is based on Maven. The jClouds Installation Guide provides directions to install using Ant, but none of them work correctly. Instead, I compiled jClouds from source (https://github.com/jclouds/jclouds) and copied the .jar files into a folder on my classpath. Now I can access the jClouds objects in my code.
- The default jclouds source does not include OpenStack Neutron objects. I eventually found these in the OpenStack Labs source (https://github.com/jclouds/jclouds-labs-openstack). Compiled from source, copied the openstack-neutron-1.9.1.jar file into classpath folder, now I can access Neutron objects.
- All online sources suggest this is a classpath/dependency problem. I've verified the openstack-neutron-1.9.1.jar library is available in both my .classpath and build.xml files. No resolution.
I'd appreciate any ideas or suggestions!
When you pass a provider/api id as a string to the ContextBuilder
, the java ServiceLoader will be used to load the api classes. It will scan the META-INF/services
folder in the classpath and look for implementations of ApiMetadata
and ProviderMetadata
.
Can you verify that in your environment there are no class loading issues that could prevent the ServiceLoader from operating normally?
As an alternative, you can bypass the ServiceLoader lookup and provide directly the concrete ApiMetadata implementation. In your case it would be something like:
NeutronApi neutron = ContextBuilder.newBuilder(new NeutronApiMetadata())
.credentials(USERNAME, API_KEY)
.endpoint(AUTH_URL)
.modules(modules)
.buildApi(NeutronApi.class);
If you have the openstack-neutron jar in your classpath this should work. And if it does, it also indicates that there is something in your project that is preventing the ServiceLoader from operating properly. It won't affect jclouds, as it only uses it when creating the context, but it is something you may want to fix.
There are some examples here:
https://github.com/jclouds/jclouds-examples/blob/master/rackspace/src/main/java/org/jclouds/examples/rackspace/cloudnetworks/CreateNetwork.java
They use maven, but they are a good starting point to compare code/dependencies.
Also, maybe you can use something like this to manage jclouds dependencies as an alternative? https://maven.apache.org/ant-tasks/
You can also try to download jclouds-neutron from maven, instead of compiling it:
https://search.maven.org/#artifactdetails%7Corg.apache.jclouds.labs%7Copenstack-neutron%7C1.9.1%7Cbundle
What problems are you hitting with the ant instructions?
If you're using maven, you should add the following dependency:
<dependency>
<groupId>org.apache.jclouds.provider</groupId>
<artifactId>aws-ec2</artifactId>
<version>${jclouds.version}</version>
</dependency>
and then, package from the command line:
mvn clean package
and add the dependencies:
mvn dependency:copy-dependencies -DoutputDirectory="./lib"
and execute:
java -cp "target/jar-with-dependencies.jar:lib/*" YourClass