Commit 507f5613 authored by Joerg Domaschka's avatar Joerg Domaschka

Merge pull request #14 from cloudiator/ps-167

Ps 167
parents 7a3b2def 7094ce82
......@@ -29,10 +29,7 @@ import de.uniulm.omi.cloudiator.lance.lifecycle.LifecycleHandlerType;
import de.uniulm.omi.cloudiator.lance.lifecycle.detector.DetectorState;
import de.uniulm.omi.cloudiator.lance.lifecycle.detector.PortUpdateHandler;
import de.uniulm.omi.cloudiator.lance.lifecycle.detector.StartDetector;
import de.uniulm.omi.cloudiator.lance.lifecycle.handlers.InstallHandler;
import de.uniulm.omi.cloudiator.lance.lifecycle.handlers.PostInstallHandler;
import de.uniulm.omi.cloudiator.lance.lifecycle.handlers.PreInstallHandler;
import de.uniulm.omi.cloudiator.lance.lifecycle.handlers.StartHandler;
import de.uniulm.omi.cloudiator.lance.lifecycle.handlers.*;
public final class BashBasedHandlerBuilder {
......@@ -66,6 +63,12 @@ public final class BashBasedHandlerBuilder {
case START:
retVal = new BashStartHandler(os, commands);
break;
case PRE_STOP:
retVal = new BashPreStopHandler(os, commands);
break;
case STOP:
retVal = new BashStopHandler(os, commands);
break;
case INIT:
default:
throw new UnsupportedOperationException();
......@@ -139,12 +142,46 @@ final class BashStartHandler implements StartHandler {
private static final long serialVersionUID = -5666019177853948866L;
private final OperatingSystem os;
private final List<String[]> commands;
BashStartHandler(OperatingSystem osParam, List<String[]> commandsParam) {
os = osParam;
commands = commandsParam;
}
@Override
public void execute(ExecutionContext ec) {
BashExecutionHelper.executeBlockingCommands(os, ec, commands);
}
}
final class BashStopHandler implements StopHandler {
private static final long serialVersionUID = -5666019177853948866L;
private final OperatingSystem os;
private final List<String[]> commands;
BashStopHandler(OperatingSystem osParam, List<String[]> commandsParam) {
os = osParam;
commands = commandsParam;
}
@Override
public void execute(ExecutionContext ec) {
BashExecutionHelper.executeBlockingCommands(os, ec, commands);
}
}
final class BashPreStopHandler implements PreStopHandler {
private static final long serialVersionUID = -5666019177853948866L;
private final OperatingSystem os;
private final List<String[]> commands;
BashPreStopHandler(OperatingSystem osParam, List<String[]> commandsParam) {
os = osParam;
commands = commandsParam;
}
@Override
public void execute(ExecutionContext ec) {
BashExecutionHelper.executeBlockingCommands(os, ec, commands);
......
......@@ -18,7 +18,7 @@
package de.uniulm.omi.cloudiator.lance.container.standard;
import org.slf4j.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.uniulm.omi.cloudiator.lance.lca.GlobalRegistryAccessor;
......@@ -35,6 +35,7 @@ import de.uniulm.omi.cloudiator.lance.lifecycle.LifecycleStore;
import de.uniulm.omi.cloudiator.lance.util.state.StateMachine;
import de.uniulm.omi.cloudiator.lance.util.state.StateMachineBuilder;
import de.uniulm.omi.cloudiator.lance.util.state.TransitionAction;
import static de.uniulm.omi.cloudiator.lance.container.standard.StandardContainerHelper.checkForBootstrapParameters;
import static de.uniulm.omi.cloudiator.lance.container.standard.StandardContainerHelper.checkForCreationParameters;
......@@ -47,189 +48,221 @@ import static de.uniulm.omi.cloudiator.lance.container.standard.StandardContaine
public final class StandardContainer<T extends ContainerLogic> implements ContainerController {
private static final Logger LOGGER = LoggerFactory.getLogger(ContainerController.class);
static Logger getLogger() {
return LOGGER;
static Logger getLogger() {
return LOGGER;
}
private final StateMachine<ContainerStatus> stateMachine;
private final GlobalRegistryAccessor accessor;
final T logic;
private final ComponentInstanceId containerId;
private final NetworkHandler network;
final LifecycleController controller;
public StandardContainer(ComponentInstanceId id, T logicParam, NetworkHandler networkParam,
LifecycleController controllerParam, GlobalRegistryAccessor accessorParam) {
LifecycleController controllerParam, GlobalRegistryAccessor accessorParam) {
containerId = id;
logic = logicParam;
network = networkParam;
controller = controllerParam;
accessor = accessorParam;
stateMachine = addDestroyTransition(
addInitTransition(addBootstrapTransition(
addCreateTransition(new StateMachineBuilder<>(ContainerStatus.NEW).
addAllState(ContainerStatus.values())))
addInitTransition(addBootstrapTransition(
addCreateTransition(new StateMachineBuilder<>(ContainerStatus.NEW).
addAllState(ContainerStatus.values())))
)).build();
}
@Override public ComponentInstanceId getId() {
return containerId;
@Override
public ComponentInstanceId getId() {
return containerId;
}
@Override public ContainerStatus getState() {
return stateMachine.getState();
@Override
public ContainerStatus getState() {
return stateMachine.getState();
}
@Override public void create() {
stateMachine.transit(ContainerStatus.NEW, new Object[] { });
@Override
public void create() {
stateMachine.transit(ContainerStatus.NEW, new Object[]{});
}
@Override public void awaitCreation() {
stateMachine.waitForTransitionEnd(ContainerStatus.CREATED);
@Override
public void awaitCreation() {
stateMachine.waitForTransitionEnd(ContainerStatus.CREATED);
}
@Override public void bootstrap() {
stateMachine.transit(ContainerStatus.CREATED, new Object[] { });
@Override
public void bootstrap() {
stateMachine.transit(ContainerStatus.CREATED, new Object[]{});
}
@Override public void awaitBootstrap() {
@Override
public void awaitBootstrap() {
stateMachine.waitForTransitionEnd(ContainerStatus.BOOTSTRAPPED);
}
@Override public void init(LifecycleStore store) {
stateMachine.transit(ContainerStatus.BOOTSTRAPPED, new Object[] { store });
@Override
public void init(LifecycleStore store) {
stateMachine.transit(ContainerStatus.BOOTSTRAPPED, new Object[]{store});
}
@Override public void awaitInitialisation() {
@Override
public void awaitInitialisation() {
stateMachine.waitForTransitionEnd(ContainerStatus.READY);
}
@Override public void tearDown() {
@Override
public void tearDown() {
stateMachine.transit(ContainerStatus.READY);
}
@Override public void awaitDestruction() {
@Override
public void awaitDestruction() {
stateMachine.waitForTransitionEnd(ContainerStatus.DESTROYED);
}
void preCreateAction() throws ContainerException {
private void setNetworking() throws ContainerException {
String address = logic.getLocalAddress();
try {
network.initPorts(address);
} catch(RegistrationException re) {
} catch (RegistrationException re) {
throw new ContainerException("cannot access registry.", re);
}
}
void preCreateAction() throws ContainerException {
setNetworking();
}
void postCreateAction() throws ContainerException {
// add dummy values so that other components are aware of this instance,
// but can see that it is not ready for use yet.
network.publishLocalData(containerId);
}
void postBootstrapAction() throws ContainerException {
String address = logic.getLocalAddress();
if(address == null)
if (address == null)
throw new ContainerException("container has no IP address set after bootstrapping.");
network.updateAddress(PortRegistryTranslator.PORT_HIERARCHY_2, address);
network.iterateOverInPorts(logic.getPortMapper());
network.pollForNeededConnections();
}
void preInitAction() throws LifecycleException {
controller.blockingInit();
controller.blockingInit();
controller.blockingInstall();
controller.blockingConfigure();
controller.blockingStart();
}
void postInitAction() throws ContainerException {
// only now that we have started, can the ports be
// retrieved and then registered at the registry //
network.publishLocalData(containerId);
network.startPortUpdaters(controller);
}
void preDestroyAction() {
controller.blockingStop();
//FIXME: remove entries from the registries //
void preDestroyAction() throws ContainerException {
controller.blockingStop();
}
void registerStatus(ContainerStatus status) throws RegistrationException {
accessor.updateContainerState(containerId, status);
accessor.updateContainerState(containerId, status);
}
private StateMachineBuilder<ContainerStatus> addCreateTransition(StateMachineBuilder<ContainerStatus> b) {
return b.addAsynchronousTransition(ContainerStatus.NEW, ContainerStatus.CREATING, ContainerStatus.CREATED,
new TransitionAction() {
@Override public void transit(Object[] params) {
new TransitionAction() {
@Override
public void transit(Object[] params) {
try {
preCreateAction();
checkForCreationParameters(params);
logic.doCreate();
checkForCreationParameters(params);
logic.doCreate();
postCreateAction();
registerStatus(ContainerStatus.CREATED);
} catch(ContainerException | RegistrationException ce) {
} catch (ContainerException | RegistrationException ce) {
getLogger().error("could not create container; FIXME add error state", ce);
/* FIXME: change to error state */
/* FIXME: change to error state */
}
}
});
}
private StateMachineBuilder<ContainerStatus> addBootstrapTransition(StateMachineBuilder<ContainerStatus> b) {
return b.addAsynchronousTransition(ContainerStatus.CREATED, ContainerStatus.BOOTSTRAPPING, ContainerStatus.BOOTSTRAPPED,
new TransitionAction() {
@Override public void transit(Object[] params) {
try {
checkForBootstrapParameters(params);
new TransitionAction() {
@Override
public void transit(Object[] params) {
try {
checkForBootstrapParameters(params);
logic.doInit(null);
postBootstrapAction();
registerStatus(ContainerStatus.BOOTSTRAPPED);
} catch(ContainerException | RegistrationException ce) {
} catch (ContainerException | RegistrationException ce) {
getLogger().error("could not initialise container; FIXME add error state", ce);
/* FIXME: change to error state */
/* FIXME: change to error state */
}
}
});
});
}
private StateMachineBuilder<ContainerStatus> addInitTransition(StateMachineBuilder<ContainerStatus> b) {
return b.addAsynchronousTransition(ContainerStatus.BOOTSTRAPPED, ContainerStatus.INITIALISING, ContainerStatus.READY,
new TransitionAction() {
@Override public void transit(Object[] params) {
new TransitionAction() {
@Override
public void transit(Object[] params) {
//TODO: add code for starting from snapshot (skip init and install steps)
try {
preInitAction();
try {
preInitAction();
logic.completeInit();
postInitAction();
registerStatus(ContainerStatus.READY);
} catch(ContainerException | LifecycleException | RegistrationException ce ) {
} catch (ContainerException | LifecycleException | RegistrationException ce) {
getLogger().error("could not initialise container; FIXME add error state", ce);
/* FIXME: change to error state */
/* FIXME: change to error state */
}
}
});
});
}
private StateMachineBuilder<ContainerStatus> addDestroyTransition(StateMachineBuilder<ContainerStatus> b) {
return b.addAsynchronousTransition(ContainerStatus.READY, ContainerStatus.SHUTTING_DOWN, ContainerStatus.DESTROYED,
new TransitionAction() {
@Override public void transit(Object[] params) {
try {
boolean forceShutdown = false;
try {
preDestroyAction();
} catch(Exception ex) {
getLogger().error("could not shut down component; trying to force shut down of container", ex);
forceShutdown = true;
}
logic.doDestroy(forceShutdown);
return b.addAsynchronousTransition(ContainerStatus.READY, ContainerStatus.SHUTTING_DOWN, ContainerStatus.DESTROYED,
new TransitionAction() {
@Override
public void transit(Object[] params) {
network.stopPortUpdaters();
try {
boolean forceShutdown = false;
try {
preDestroyAction();
} catch (Exception ex) {
getLogger().error("could not shut down component; trying to force shut down of container", ex);
forceShutdown = true;
}
logic.doDestroy(forceShutdown);
registerStatus(ContainerStatus.DESTROYED);
} catch(ContainerException | RegistrationException ce) {
} catch (ContainerException | RegistrationException ce) {
getLogger().error("could not shut down container; FIXME add error state", ce);
/* FIXME: change to error state */
/* FIXME: change to error state */
} finally {
try {
setNetworking();
} catch (ContainerException e) {
getLogger().error("could not update networking", e);
}
try {
network.publishLocalData(containerId);
} catch (ContainerException e) {
getLogger().error("could not publish local data", e);
}
}
}
});
}
......
......@@ -60,10 +60,11 @@ public class PlainContainerLogic implements ContainerLogic, LifecycleActionInter
private final NetworkHandler networkHandler;
private final PlainShellFactory plainShellFactory;
private final HostContext hostContext;
private boolean stopped = false;
PlainContainerLogic(ComponentInstanceId id, DeployableComponent deployableComponent,
DeploymentContext deploymentContext, OperatingSystem os, NetworkHandler networkHandler,
PlainShellFactory plainShellFactory, HostContext hostContext) {
DeploymentContext deploymentContext, OperatingSystem os, NetworkHandler networkHandler,
PlainShellFactory plainShellFactory, HostContext hostContext) {
this.myId = id;
this.deployableComponent = deployableComponent;
......@@ -74,7 +75,8 @@ public class PlainContainerLogic implements ContainerLogic, LifecycleActionInter
this.hostContext = hostContext;
}
@Override public void doCreate() throws ContainerException {
@Override
public void doCreate() throws ContainerException {
LOGGER.info("Creating shell for operating system: " + this.os.toString());
PlainShell plainShell = new PlainShellImpl(this.os);
......@@ -91,28 +93,31 @@ public class PlainContainerLogic implements ContainerLogic, LifecycleActionInter
}
@Override public void doInit(LifecycleStore store) throws ContainerException {
@Override
public void doInit(LifecycleStore store) throws ContainerException {
//probably not needed for plain container
}
@Override public void completeInit() throws ContainerException {
@Override
public void completeInit() throws ContainerException {
this.plainShellFactory.closeShell();
}
@Override public void doDestroy(boolean forceShutdown) throws ContainerException {
if(forceShutdown) {
throw new ContainerException("cannot force shutdown in plain container. shutdown will fail.");
}
throw new UnsupportedOperationException("graceful shutdown not implemented.");
@Override
public void doDestroy(boolean forceShutdown) throws ContainerException {
//TODO: maybe remember pid of start, then kill this pid or gracefully kill pid.
LOGGER.warn("doDestroy not implemented!");
}
@Override public String getLocalAddress() throws ContainerException {
return hostContext.getInternalIp();
@Override
public String getLocalAddress() throws ContainerException {
if (!stopped) {
return hostContext.getInternalIp();
}
return null;
}
/**
......@@ -120,7 +125,8 @@ public class PlainContainerLogic implements ContainerLogic, LifecycleActionInter
*
* @return
*/
@Override public InportAccessor getPortMapper() {
@Override
public InportAccessor getPortMapper() {
return ((portName, clientState) -> {
Integer portNumber = (Integer) deploymentContext.getProperty(portName, InPort.class);
......@@ -131,10 +137,17 @@ public class PlainContainerLogic implements ContainerLogic, LifecycleActionInter
});
}
@Override public void prepare(HandlerType type) {
@Override
public void prepare(HandlerType type) {
//TODO: open shells here?
if (type == LifecycleHandlerType.INSTALL) {
preInstallAction();
}
if (type == LifecycleHandlerType.PRE_STOP) {
stopped = true;
}
}
......@@ -145,13 +158,13 @@ public class PlainContainerLogic implements ContainerLogic, LifecycleActionInter
if (this.os.getFamily().equals(OperatingSystemFamily.WINDOWS)) {
PowershellExportBasedVisitor visitor =
new PowershellExportBasedVisitor(plainShellWrapper.plainShell);
new PowershellExportBasedVisitor(plainShellWrapper.plainShell);
networkHandler.accept(visitor, null);
this.deployableComponent.accept(this.deploymentContext, visitor);
} else if (this.os.getFamily().equals(OperatingSystemFamily.LINUX)) {
BashExportBasedVisitor visitor =
new BashExportBasedVisitor(plainShellWrapper.plainShell);
new BashExportBasedVisitor(plainShellWrapper.plainShell);
networkHandler.accept(visitor, null);
this.deployableComponent.accept(this.deploymentContext, visitor);
......@@ -162,7 +175,8 @@ public class PlainContainerLogic implements ContainerLogic, LifecycleActionInter
}
@Override public void postprocess(HandlerType type) {
@Override
public void postprocess(HandlerType type) {
if (type == LifecycleHandlerType.PRE_INSTALL) {
postPreInstall();
} else if (type == LifecycleHandlerType.POST_INSTALL) {
......@@ -171,21 +185,22 @@ public class PlainContainerLogic implements ContainerLogic, LifecycleActionInter
}
private void postPreInstall() {
// TODO: empty method?
// TODO: empty method?
}
@Override public ComponentInstanceId getComponentId() {
@Override
public ComponentInstanceId getComponentId() {
return this.myId;
}
@Override
public void postprocessPortUpdate(PortDiff<DownstreamAddress> diff) {
plainShellFactory.closeShell();
}
@Override
public void postprocessPortUpdate(PortDiff<DownstreamAddress> diff) {
plainShellFactory.closeShell();
}
@Override
public void preprocessPortUpdate(PortDiff<DownstreamAddress> diff)
throws ContainerException {
@Override
public void preprocessPortUpdate(PortDiff<DownstreamAddress> diff)
throws ContainerException {
//TODO: again duplicated code, needs refactoring
......@@ -212,19 +227,17 @@ public class PlainContainerLogic implements ContainerLogic, LifecycleActionInter
}
}
}
@Override
public void postprocessDetector(DetectorType type) {
LOGGER.error("postprocessDetector is not implemented for plain container");
}
@Override
public void preprocessDetector(DetectorType type) throws ContainerException {
LOGGER.error("preprocessDetector is not implemented for plain container");
}
@Override
public void postprocessDetector(DetectorType type) {
LOGGER.error("postprocessDetector is not implemented for plain container");
}