You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
common-smartgears/src/main/java/org/gcube/smartgears/managers/ContainerManager.java

230 lines
6.6 KiB
Java

package org.gcube.smartgears.managers;
import static org.gcube.smartgears.Constants.container_profile_file_path;
import static org.gcube.smartgears.lifecycle.container.ContainerState.active;
import static org.gcube.smartgears.lifecycle.container.ContainerState.down;
import static org.gcube.smartgears.lifecycle.container.ContainerState.failed;
import static org.gcube.smartgears.lifecycle.container.ContainerState.stopped;
import static org.gcube.smartgears.provider.ProviderFactory.provider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.List;
import java.util.Set;
import org.gcube.common.events.Observes;
import org.gcube.common.events.Observes.Kind;
import org.gcube.smartgears.configuration.Mode;
import org.gcube.smartgears.context.application.ApplicationContext;
import org.gcube.smartgears.context.container.ContainerContext;
import org.gcube.smartgears.handlers.ProfileEvents;
import org.gcube.smartgears.handlers.container.ContainerHandler;
import org.gcube.smartgears.handlers.container.ContainerLifecycleEvent;
import org.gcube.smartgears.handlers.container.ContainerPipeline;
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
import org.gcube.smartgears.lifecycle.container.ContainerState;
import org.gcube.smartgears.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Coordinates management of the container as a gCube resource.
*
* @author Fabio Simeoni
*
*/
public class ContainerManager {
private static Logger log = LoggerFactory.getLogger(ContainerManager.class);
public static ContainerManager instance = new ContainerManager();
private ContainerContext context;
private ContainerPipeline pipeline;
private ContainerManager() {}
/**
* Starts container management.
*/
public ContainerContext start(ContainerContext context) {
this.context = context;
try {
if (context.configuration().mode()!=Mode.offline)
validateContainer(context);
saveContainerState();
List<ContainerHandler> handlers = provider().containerHandlers();
log.trace("managing container lifecycle with {}", handlers);
startHandlers(handlers);
context.lifecycle().moveTo(active);
return context;
} catch (RuntimeException e) {
log.error("cannot manage container (see cause)", e);
if (context != null)
context.lifecycle().moveTo(failed);
throw e;
}
}
private void saveContainerState() {
File file = context.persistenceWriter().file(container_profile_file_path);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {
oos.writeObject(context.id());
} catch (Exception e) {
log.error("error serializing cointainer state");
throw new RuntimeException(e);
}
}
private void validateContainer(ContainerContext context) {
// List<String> tokensToRemove = new ArrayList<String>();
context.configuration().validate();
Set<String> foundContexts;
try {
foundContexts = context.authorizationProvider().getContexts();
} catch (Exception e) {
log.error("error authorizing container", e);
throw new RuntimeException("error authorizing container, moving the container to failed", e);
}
if (foundContexts.isEmpty()) {
log.error("no valid contexts found, moving the container to failed");
throw new RuntimeException("no valid contexts found, moving the container to failed");
}
}
public void manage(ApplicationContext app) {
app.events().subscribe(this);
}
@Observes(value = { ApplicationLifecycle.failure, ApplicationLifecycle.stop }, kind = Kind.critical)
void monitorApplication(ApplicationLifecycle lifecycle) {
context.lifecycle().tryMoveTo(ContainerState.partActive);
}
/**
* Stops container management on remote request.
*
*/
public void stop() {
stop(false);
}
/**
* Stops container management on remote request or container shutdown.
*
*/
public void stop(boolean shutdown) {
// two cases: stop-on-shutdown and stop-on-request, some listeners will be
// selective about this,
// shutdown is triggered by probe app, which is notified among other apps
// if other app have been already notified, the container may already be
// part-active.
// apps still to notify will listen only on stop, hence won't react to this but
// will go down when their turn arrives.
if (context == null)
return;
log.info("stopping container management");
try {
context.lifecycle().tryMoveTo(shutdown ? down : stopped);
stopHandlers();
// no further reactions
log.info("stopping container events");
context.events().stop();
Utils.scheduledServicePool.shutdownNow();
} catch (RuntimeException e) {
log.warn("cannot stop container management (see cause)", e);
}
}
// helpers
private void startHandlers(List<ContainerHandler> handlers) {
try {
pipeline = new ContainerPipeline(handlers);
pipeline.forward(new ContainerLifecycleEvent.Start(context));
} catch (RuntimeException e) {
context.lifecycle().tryMoveTo(failed);
throw e;
}
}
private void stopHandlers() {
if (pipeline == null)
return;
// copy pipeline, flip it, and
ContainerPipeline returnPipeline = pipeline.reverse();
// start lifetime pipeline in inverse order with stop event
returnPipeline.forward(new ContainerLifecycleEvent.Stop(context));
}
/*
* private void loadKeyForToken(List<String> tokens) { String initialToken =
* SecurityTokenProvider.instance.get();
*
* //TODO: change this String filePath = "/tmp/keys"; File PathDirs = new
* File(filePath+"/"); PathDirs.mkdirs(); try{ for (String token : tokens) {
* try{ SecurityTokenProvider.instance.set(token); File key =
* authProvider.getSymmKey(filePath);
* log.trace("loading key {} file name ",key.getAbsolutePath());
* log.trace("loaded key {} file name ",key.getAbsolutePath()); }catch(Exception
* e){ log.warn("error loading key for token {}", token, e); } }
* loadFileIntoClasspath(PathDirs); }finally{
* SecurityTokenProvider.instance.set(initialToken); } }
*
*
* private void loadFileIntoClasspath(File file){ try { URL url =
* file.toURI().toURL();
*
* ClassLoader currentClassloader =
* Thread.currentThread().getContextClassLoader().getParent()==null?
* Thread.currentThread().getContextClassLoader() :
* Thread.currentThread().getContextClassLoader().getParent();
*
* URLClassLoader classLoader = (URLClassLoader)currentClassloader; Method
* method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
* method.setAccessible(true); method.invoke(classLoader, url); } catch
* (Exception ex) { log.error("error loading file into classpath",ex); } }
*/
}