package org.apache.usergrid.chop.webapp.coordinator.rest; import java.io.IOException; import java.io.StringWriter; import java.util.Properties; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.usergrid.chop.api.CoordinatorFig; import org.apache.usergrid.chop.stack.CoordinatedStack; import org.apache.usergrid.chop.stack.ICoordinatedCluster; import org.apache.usergrid.chop.stack.Instance; import org.apache.usergrid.chop.stack.SetupStackState; import org.apache.usergrid.chop.webapp.coordinator.StackCoordinator; import com.google.inject.Inject; import com.google.inject.Singleton; /** * A resource that uses path parameters to expose properties for a stack build. This will be * used when starting runners to have them pick up properties needed to hit stack clusters. * Note that this is used with the archaius configuration property: * * -Darchaius.deployment.environment=CHOP * -Darchaius.deployment.region=${region} * -Darchaius.deployment.datacenter=${} * -Darchaius.deployment.applicationId=chop-runner * -Darchaius.deployment.stack=${stackId} * -Darchaius.configurationSource.additionalUrls= * https://${endpoint}:${port}/properties/${user}/${groupId}/${artifactId}/${version}/${commitId} */ @Singleton @Produces( MediaType.TEXT_PLAIN ) @Path( CoordinatorFig.PROPERTIES_PATH_DEFAULT ) public class PropertiesResource { private static final char DELIMITER = ' '; @Inject StackCoordinator coordinator; @GET @Path( "{user}/{groupId}/{artifactId}/{version}/{commitId}" ) public Response getProperties( @PathParam( "user" ) String user, @PathParam( "groupId" ) String groupId, @PathParam( "artifactId" ) String artifactId, @PathParam( "version" ) String version, @PathParam( "commitId" ) String commitId ) throws IOException { // Get the stack matching these parameters CoordinatedStack stack = coordinator.findCoordinatedStack( commitId, artifactId, groupId, version, user ); if( stack == null ) { return Response.ok().entity( "No stack could be found that matches given parameters" ).build(); } else if( stack.getSetupState() != SetupStackState.SetUp ) { return Response.ok().entity( "Stack's setup state is: " + stack.getSetupState() ).build(); } StringWriter writer = new StringWriter(); Properties properties = new Properties(); // flatten out and set the stack properties here before storing for ( ICoordinatedCluster cluster : stack.getClusters() ) { String keyBase = cluster.getName() + ".cluster"; StringBuilder privateAddresses = new StringBuilder(); StringBuilder publicAddresses = new StringBuilder(); StringBuilder privateHostnames = new StringBuilder(); StringBuilder publicHostnames = new StringBuilder(); for ( Instance instance : cluster.getInstances() ) { privateAddresses.append( instance.getPrivateIpAddress() ).append( DELIMITER ); publicAddresses.append( instance.getPublicIpAddress() ).append( DELIMITER ); privateHostnames.append( instance.getPrivateDnsName() ).append( DELIMITER ); publicHostnames.append( instance.getPublicDnsName() ).append( DELIMITER ); } properties.setProperty( keyBase + ".private.addresses", privateAddresses.toString() ); properties.setProperty( keyBase + ".public.addresses", publicAddresses.toString() ); properties.setProperty( keyBase + ".private.hostnames", privateHostnames.toString() ); properties.setProperty( keyBase + ".public.hostnames", publicHostnames.toString() ); } // TODO should we also include runner instances or are they not needed? properties.store( writer, "Generated by ChopUI" ); return Response.ok().entity( writer.toString() ).build(); } }