I got a comment on my jclouds and OpenStack post about how to get the Tenant ID via jclouds. The first solution that popped to my mind was to get the Tenant ID out of the access data structure that gets returned upon authentication. This turned out to be a bit trickier than expected as jclouds automatically authenticates on your first actual interaction with a cloud (i.e. the very first time you call a method that needs to talk to the cloud). To get the access data structure I needed to manually authenticate. Here’s how to do it.
Get jclouds
First off, get the jclouds JAR files.
- Ensure you are using the Java Development Kit (JDK) version 6 or later.
*
javac -version
- Ensure you are using Maven version 3 or later.
*
mvn -version
- Create a directory to try out jclouds.
*
mkdir jclouds
*cd jclouds
- Make a local copy of this pom.xml file in the jclouds directory.
*
mvn dependency:copy-dependencies "-DoutputDirectory=./lib"
- You should now have a directory with the following structure:
*
jclouds/
pom.xml
lib/
*.jar
Manual Authentication
Put this code in your jclouds directory to do manual authentication. An explanation follows.
import org.jclouds.ContextBuilder; | |
import org.jclouds.compute.ComputeService; | |
import org.jclouds.compute.ComputeServiceContext; | |
import org.jclouds.domain.Credentials; | |
import org.jclouds.openstack.keystone.v2_0.domain.Access; | |
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint; | |
import org.jclouds.openstack.keystone.v2_0.domain.Service; | |
import org.jclouds.openstack.nova.v2_0.NovaApi; | |
import org.jclouds.openstack.nova.v2_0.NovaAsyncApi; | |
import org.jclouds.rest.RestContext; | |
import com.google.common.base.Function; | |
import com.google.inject.Key; | |
import com.google.inject.TypeLiteral; | |
/** | |
* To authenticate using jclouds you need to provide your credentials to a Context as in the init() method below. | |
* Normally, authentication occurs on your first actual interaction with a cloud (i.e. the very first time | |
* you call a method that needs to talk to the cloud). Once you are authenticated you receive a token that is | |
* cached and you won't reauthenticate for subsequent calls. If your token expires before the JVM quits, jclouds | |
* will automatically handle reauthentication and get a new token for you. | |
* | |
* If authentication doesn't work, the call will result in an org.jclouds.rest.AuthorizationException | |
* | |
* This example demostrates how you would manually authenticate via username and password or API key with an | |
* OpenStack powered cloud. Authenticating manually allows you to get a hold of the OpenStack access data structure | |
* that includes the user, tenant, token, and service catalog information. | |
* | |
* @author Everett Toews | |
*/ | |
public class JCloudsManualAuthentication { | |
private ComputeService compute; | |
private RestContext<NovaApi, NovaAsyncApi> nova; | |
/** | |
* To get a username and API key see http://www.jclouds.org/documentation/quickstart/rackspace/ | |
* | |
* The 1st argument (args[0]) must be the provider that configures jclouds to use a cloud. | |
* openstack-nova for OpenStack Compute (Nova) | |
* rackspace-cloudservers-us for Rackspace Cloud US | |
* rackspace-cloudservers-uk for Rackspace Cloud UK | |
* The 2nd argument (args[1]) must be your identity for your cloud | |
* tenantname:username for OpenStack | |
* username for Rackspace | |
* The 3rd argument (args[2]) must be the credential for your cloud | |
* Password for OpenStack | |
* API key for Rackspace | |
* The 4th argument (args[3]) must be the endpoint if you're using OpenStack | |
* | |
* Examples: | |
* OpenStack - java -cp ".:lib/*" JCloudsManualAuthentication openstack-nova demo:demo devstack http://123.123.123.123:5000/v2.0/ | |
* Rackspace - java -cp ".:lib/*" JCloudsManualAuthentication rackspace-cloudservers-us myRackspaceUsername myRackspaceAPIKey | |
*/ | |
public static void main(String[] args) { | |
JCloudsManualAuthentication authentication = new JCloudsManualAuthentication(); | |
try { | |
authentication.init(args); | |
} | |
finally { | |
authentication.close(); | |
} | |
} | |
private void init(String[] args) { | |
String provider = args[0]; | |
String username = args[1]; | |
String credential = args[2]; | |
ContextBuilder contextBuilder = ContextBuilder.newBuilder(provider) | |
.credentials(username, credential); | |
if (provider.startsWith("openstack")) { | |
String endpoint = args[3]; | |
contextBuilder.endpoint(endpoint); | |
} | |
ComputeServiceContext context = contextBuilder.buildView(ComputeServiceContext.class); | |
Function<Credentials, Access> auth = context.utils().injector().getInstance(Key.get(new TypeLiteral<Function<Credentials, Access>>(){})); | |
Access access = auth.apply(new Credentials.Builder<Credentials>().identity(username).credential(credential).build()); | |
System.out.println(access); | |
System.out.println(" User Name = " + access.getUser().getName()); | |
System.out.println(" User ID = " + access.getUser().getId()); | |
System.out.println(" Tenant Name = " + access.getToken().getTenant().get().getName()); | |
System.out.println(" Tenant ID = " + access.getToken().getTenant().get().getId()); | |
System.out.println(" Token ID = " + access.getToken().getId()); | |
System.out.println(" Token Expires = " + access.getToken().getExpires()); | |
for (Service service: access) { | |
System.out.println(" Service = " + service.getName()); | |
for (Endpoint endpoint: service) { | |
System.out.println(" Endpoint = " + endpoint.getPublicURL()); | |
} | |
} | |
} | |
/** | |
* Always close your service when you're done with it. | |
*/ | |
public void close() { | |
if (compute != null) { | |
compute.getContext(); | |
} | |
} | |
} |
- Compile.
*
javac -cp ".:lib/*" JCloudsManualAuthentication.java
- Run on OpenStack.
*
java -cp ".:lib/*" JCloudsManualAuthentication openstack-nova demo:demo devstack http://123.123.123.123:5000/v2.0/
- Run on Rackspace as this code works equally well with any OpenStack powered provider.
*
java -cp ".:lib/*" JCloudsManualAuthentication rackspace-cloudservers-us myRackspaceUsername myRackspaceAPIKey
The key to the example is lines 93 & 94. Because jclouds normally handles the authentication manually we have to use a bit of Guice-fu on line 93 to get a hold of the Function that can manually authenticate by taking our Credentials and returning the Access data structure. On line 94 we execute that Function and the authentication happens. After that we can run through the Access object and get the information we need.
Coda
It’s rare that you would need to authenticate manually in jclouds. Most of the time letting jclouds automatically handle the auth for you suffices. However, if you do need to authenticate manually, this method will give you a lot of information about your OpenStack environment.