Commit 4fdb0d65 authored by Joerg Domaschka's avatar Joerg Domaschka

Merge pull request #18 from cloudiator/PS-119

Ps 119: run stop detectors on a regular basis
parents e507ba49 aa554cd9
......@@ -94,6 +94,7 @@ public enum LifecycleHandlerType implements State, HandlerType {
INSTALL_FAILED(VoidHandler.class, DefaultFactories.VOID_FACTORY),
STARTUP_FAILED(VoidHandler.class, DefaultFactories.VOID_FACTORY),
TERMINATION_FAILED(VoidHandler.class, DefaultFactories.VOID_FACTORY),
UNEXPECTED_EXECUTION_STOP(VoidHandler.class, DefaultFactories.VOID_FACTORY),
UNKNOWN(VoidHandler.class, DefaultFactories.VOID_FACTORY),
;
......
......@@ -24,6 +24,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.uniulm.omi.cloudiator.lance.lifecycle.detector.StartDetector;
import de.uniulm.omi.cloudiator.lance.lifecycle.detector.StopDetector;
public class LifecycleStore implements Serializable {
......@@ -32,8 +33,9 @@ public class LifecycleStore implements Serializable {
private static final long serialVersionUID = 1L;
private final LifecycleHandler[] handlers;
private final StartDetector startDetector;
private final StopDetector stopDetector;
LifecycleStore(LifecycleHandler[] handlersParam, StartDetector startDetectorParam) {
LifecycleStore(LifecycleHandler[] handlersParam, StartDetector startDetectorParam, StopDetector stopDetectorParam) {
handlers = handlersParam;
assert handlers.length == LifecycleHandlerType.values().length : "array too small";
for(LifecycleHandlerType t : LifecycleHandlerType.values()) {
......@@ -42,6 +44,7 @@ public class LifecycleStore implements Serializable {
throw new IllegalStateException("not the correct lifecycle handler");
}
startDetector = startDetectorParam;
stopDetector = stopDetectorParam;
}
public <T extends LifecycleHandler> T getHandler(LifecycleHandlerType t, Class<T> type) {
......@@ -69,4 +72,8 @@ public class LifecycleStore implements Serializable {
public StartDetector getStartDetector() {
return startDetector;
}
public StopDetector getStopDetector() {
return stopDetector;
}
}
/*
* Copyright (c) 2014-2015 University of Ulm
*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package de.uniulm.omi.cloudiator.lance.lifecycle;
import de.uniulm.omi.cloudiator.lance.lifecycle.detector.StartDetector;
public final class LifecycleStoreBuilder {
private final LifecycleHandler[] handlers = new LifecycleHandler[LifecycleHandlerType.values().length];
private volatile StartDetector startDetector;
public LifecycleStoreBuilder() {
// empty!
}
public synchronized LifecycleStoreBuilder setStartDetector(StartDetector start) {
if(startDetector == null || startDetector == start) {
startDetector = start;
} else {
throw new IllegalStateException("start detector has already been set.");
}
return this;
}
public LifecycleStoreBuilder setHandler(LifecycleHandler h, LifecycleHandlerType t) {
if(h == null)
throw new NullPointerException();
Class<?> superClass = t.getTypeClass();
Class<?> inheritCla = h.getClass();
if(! superClass.isAssignableFrom(inheritCla)) {
throw new IllegalArgumentException("handler types do not match: " + h.getClass() + " vs. " + t.getTypeClass());
}
if(t == LifecycleHandlerType.NEW) {
throw new IllegalArgumentException("cannot set a handler for 'NEW'. " + "This event is a system event");
}
handlers[t.ordinal()] = h;
return this;
}
public LifecycleStore build() {
for(LifecycleHandlerType t : LifecycleHandlerType.values()) {
if(handlers[t.ordinal()] == null) {
handlers[t.ordinal()] = t.getDefaultImplementation();
}
}
if(startDetector == null) {
throw new NullPointerException("start detector cannot be null");
}
return new LifecycleStore(handlers, startDetector);
}
}
/*
* Copyright (c) 2014-2015 University of Ulm
*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package de.uniulm.omi.cloudiator.lance.lifecycle;
import de.uniulm.omi.cloudiator.lance.lifecycle.detector.StartDetector;
import de.uniulm.omi.cloudiator.lance.lifecycle.detector.StopDetector;
public final class LifecycleStoreBuilder {
private final LifecycleHandler[] handlers = new LifecycleHandler[LifecycleHandlerType.values().length];
private volatile StartDetector startDetector;
private volatile StopDetector stopDetector;
public LifecycleStoreBuilder() {
// empty!
}
public synchronized LifecycleStoreBuilder setStartDetector(StartDetector start) {
if(startDetector == null || startDetector == start) {
startDetector = start;
} else {
throw new IllegalStateException("start detector has already been set.");
}
return this;
}
public LifecycleStoreBuilder setHandler(LifecycleHandler h, LifecycleHandlerType t) {
if(h == null)
throw new NullPointerException();
Class<?> superClass = t.getTypeClass();
Class<?> inheritCla = h.getClass();
if(! superClass.isAssignableFrom(inheritCla)) {
throw new IllegalArgumentException("handler types do not match: " + h.getClass() + " vs. " + t.getTypeClass());
}
if(t == LifecycleHandlerType.NEW) {
throw new IllegalArgumentException("cannot set a handler for 'NEW'. " + "This event is a system event");
}
handlers[t.ordinal()] = h;
return this;
}
public LifecycleStore build() {
for(LifecycleHandlerType t : LifecycleHandlerType.values()) {
if(handlers[t.ordinal()] == null) {
handlers[t.ordinal()] = t.getDefaultImplementation();
}
}
if(startDetector == null) {
throw new NullPointerException("start detector cannot be null");
}
return new LifecycleStore(handlers, startDetector, stopDetector);
}
}
......@@ -223,8 +223,6 @@ final class BashStartDetectorHandler implements StartDetector {
BashExecutionHelper.executeCommands(os, ec, commands);
ExecutionResult result = BashExecutionHelper.doExecuteCommand(false, "echo -n \"$STARTED\"", ec.getShell());
if(result.isSuccess()) {
// return values for docker is:
// \nfalse\n0\n
if("true".equals(result.getOutput().trim())) {
return DetectorState.DETECTED;
}
......
......@@ -30,7 +30,6 @@ import de.uniulm.omi.cloudiator.lance.lifecycle.LifecycleHandlerType;
public interface StartDetector extends Detector {
DetectorState execute(ExecutionContext ec);
// empty interface; methods not yet fixed //
}
......
......@@ -18,6 +18,8 @@
package de.uniulm.omi.cloudiator.lance.lifecycle.detector;
import de.uniulm.omi.cloudiator.lance.lifecycle.ExecutionContext;
/**
* may be used to notify USM that the service instance has stopped,
* be it intended or unintended
......@@ -25,5 +27,6 @@ package de.uniulm.omi.cloudiator.lance.lifecycle.detector;
* @author Joerg Domaschka
*/
public interface StopDetector extends Detector {
// empty interface; methods not yet fixed //
DetectorState execute(ExecutionContext ec);
}
......@@ -27,7 +27,7 @@ import de.uniulm.omi.cloudiator.lance.LcaConstants;
import de.uniulm.omi.cloudiator.lance.application.DeploymentContext;
import de.uniulm.omi.cloudiator.lance.application.component.DeployableComponent;
import de.uniulm.omi.cloudiator.lance.container.spec.os.OperatingSystem;
import de.uniulm.omi.cloudiator.lance.container.standard.StandardContainer;
import de.uniulm.omi.cloudiator.lance.container.standard.ErrorAwareContainer;
import de.uniulm.omi.cloudiator.lance.lca.GlobalRegistryAccessor;
import de.uniulm.omi.cloudiator.lance.lca.HostContext;
import de.uniulm.omi.cloudiator.lance.lca.container.ContainerController;
......@@ -93,7 +93,7 @@ public class DockerContainerManager implements ContainerManager {
DockerContainerLogic logic = new DockerContainerLogic(id, client, comp, ctx, os, networkHandler, shellFactory, dockerConfig);
// DockerLifecycleInterceptor interceptor = new DockerLifecycleInterceptor(accessor, id, networkHandler, comp, shellFactory);
ExecutionContext ec = new ExecutionContext(os, shellFactory);
LifecycleController controller = new LifecycleController(comp.getLifecycleStore(), logic, accessor, ec);
LifecycleController controller = new LifecycleController(comp.getLifecycleStore(), logic, accessor, ec, hostContext);
try {
accessor.init(id);
......@@ -101,7 +101,7 @@ public class DockerContainerManager implements ContainerManager {
throw new ContainerException("cannot start container, because registry not available", re);
}
ContainerController dc = new StandardContainer<>(id, logic, networkHandler, controller, accessor);
ContainerController dc = new ErrorAwareContainer<>(id, logic, networkHandler, controller, accessor);
registry.addContainer(dc);
dc.create();
return dc;
......
/*
* Copyright (c) 2014-2015 University of Ulm
*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package de.uniulm.omi.cloudiator.lance.lca.containers.plain;
import de.uniulm.omi.cloudiator.lance.application.DeploymentContext;
import de.uniulm.omi.cloudiator.lance.application.component.DeployableComponent;
import de.uniulm.omi.cloudiator.lance.container.spec.os.OperatingSystem;
import de.uniulm.omi.cloudiator.lance.container.standard.StandardContainer;
import de.uniulm.omi.cloudiator.lance.lca.GlobalRegistryAccessor;
import de.uniulm.omi.cloudiator.lance.lca.HostContext;
import de.uniulm.omi.cloudiator.lance.lca.container.*;
import de.uniulm.omi.cloudiator.lance.lca.container.port.NetworkHandler;
import de.uniulm.omi.cloudiator.lance.lca.container.registry.ContainerRegistry;
import de.uniulm.omi.cloudiator.lance.lca.registry.RegistrationException;
import de.uniulm.omi.cloudiator.lance.lifecycle.ExecutionContext;
import de.uniulm.omi.cloudiator.lance.lifecycle.LifecycleController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Created by Daniel Seybold on 10.08.2015.
*/
public class PlainContainerManager implements ContainerManager {
private static final Logger LOGGER = LoggerFactory.getLogger(ContainerManager.class);
private final ContainerRegistry registry = new ContainerRegistry();
private final HostContext hostContext;
public PlainContainerManager(HostContext vmId) {
this.hostContext = vmId;
}
@Override public ContainerType getContainerType() {
return ContainerType.PLAIN;
}
@Override public ContainerController getContainer(ComponentInstanceId id) {
return this.registry.getContainer(id);
}
@Override public ContainerController createNewContainer(DeploymentContext ctx,
DeployableComponent component, OperatingSystem os) throws ContainerException {
ComponentInstanceId componentInstanceId = new ComponentInstanceId();
PlainShellFactory plainShellFactory = new PlainShellFactory();
GlobalRegistryAccessor accessor =
new GlobalRegistryAccessor(ctx, component, componentInstanceId);
NetworkHandler networkHandler = new NetworkHandler(accessor, component, this.hostContext);
PlainContainerLogic plainContainerLogic =
new PlainContainerLogic(componentInstanceId, component, ctx, os, networkHandler,
plainShellFactory, this.hostContext);
ExecutionContext executionContext = new ExecutionContext(os, plainShellFactory);
LifecycleController lifecycleController =
new LifecycleController(component.getLifecycleStore(), plainContainerLogic, accessor,
executionContext);
try {
accessor.init(componentInstanceId);
} catch (RegistrationException re) {
throw new ContainerException("cannot start container, because registry not available",
re);
}
ContainerController containerController =
new StandardContainer<>(componentInstanceId, plainContainerLogic, networkHandler,
lifecycleController, accessor);
this.registry.addContainer(containerController);
containerController.create();
return containerController;
}
@Override public void terminate() {
try {
this.hostContext.close();
} catch (InterruptedException ie) {
LOGGER.warn("shutting down interrupted");
}
LOGGER.error(
"terminate has not been fully implemented, closing further parts need to be implemented!");
// FIXME: add other parts to shut down //
}
@Override public List<ComponentInstanceId> getAllContainers() {
return registry.listComponentInstances();
}
@Override public ContainerStatus getComponentContainerStatus(ComponentInstanceId cid) {
ContainerController dc = registry.getContainer(cid);
return dc.getState();
}
}
/*
* Copyright (c) 2014-2015 University of Ulm
*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package de.uniulm.omi.cloudiator.lance.lca.containers.plain;
import de.uniulm.omi.cloudiator.lance.application.DeploymentContext;
import de.uniulm.omi.cloudiator.lance.application.component.DeployableComponent;
import de.uniulm.omi.cloudiator.lance.container.spec.os.OperatingSystem;
import de.uniulm.omi.cloudiator.lance.container.standard.ErrorAwareContainer;
import de.uniulm.omi.cloudiator.lance.lca.GlobalRegistryAccessor;
import de.uniulm.omi.cloudiator.lance.lca.HostContext;
import de.uniulm.omi.cloudiator.lance.lca.container.*;
import de.uniulm.omi.cloudiator.lance.lca.container.port.NetworkHandler;
import de.uniulm.omi.cloudiator.lance.lca.container.registry.ContainerRegistry;
import de.uniulm.omi.cloudiator.lance.lca.registry.RegistrationException;
import de.uniulm.omi.cloudiator.lance.lifecycle.ExecutionContext;
import de.uniulm.omi.cloudiator.lance.lifecycle.LifecycleController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Created by Daniel Seybold on 10.08.2015.
*/
public class PlainContainerManager implements ContainerManager {
private static final Logger LOGGER = LoggerFactory.getLogger(ContainerManager.class);
private final ContainerRegistry registry = new ContainerRegistry();
private final HostContext hostContext;
public PlainContainerManager(HostContext vmId) {
this.hostContext = vmId;
}
@Override public ContainerType getContainerType() {
return ContainerType.PLAIN;
}
@Override public ContainerController getContainer(ComponentInstanceId id) {
return this.registry.getContainer(id);
}
@Override public ContainerController createNewContainer(DeploymentContext ctx,
DeployableComponent component, OperatingSystem os) throws ContainerException {
ComponentInstanceId componentInstanceId = new ComponentInstanceId();
PlainShellFactory plainShellFactory = new PlainShellFactory();
GlobalRegistryAccessor accessor =
new GlobalRegistryAccessor(ctx, component, componentInstanceId);
NetworkHandler networkHandler = new NetworkHandler(accessor, component, this.hostContext);
PlainContainerLogic plainContainerLogic =
new PlainContainerLogic(componentInstanceId, component, ctx, os, networkHandler,
plainShellFactory, this.hostContext);
ExecutionContext executionContext = new ExecutionContext(os, plainShellFactory);
LifecycleController lifecycleController =
new LifecycleController(component.getLifecycleStore(), plainContainerLogic, accessor,
executionContext, hostContext);
try {
accessor.init(componentInstanceId);
} catch (RegistrationException re) {
throw new ContainerException("cannot start container, because registry not available",
re);
}
ContainerController containerController =
new ErrorAwareContainer<>(componentInstanceId, plainContainerLogic, networkHandler,
lifecycleController, accessor);
this.registry.addContainer(containerController);
containerController.create();
return containerController;
}
@Override public void terminate() {
try {
this.hostContext.close();
} catch (InterruptedException ie) {
LOGGER.warn("shutting down interrupted");
}
LOGGER.error(
"terminate has not been fully implemented, closing further parts need to be implemented!");
// FIXME: add other parts to shut down //
}
@Override public List<ComponentInstanceId> getAllContainers() {
return registry.listComponentInstances();
}
@Override public ContainerStatus getComponentContainerStatus(ComponentInstanceId cid) {
ContainerController dc = registry.getContainer(cid);
return dc.getState();
}
}
......@@ -19,7 +19,9 @@
package de.uniulm.omi.cloudiator.lance.lifecycle;
import de.uniulm.omi.cloudiator.lance.application.component.OutPort;
import de.uniulm.omi.cloudiator.lance.lifecycle.detector.DetectorState;
import de.uniulm.omi.cloudiator.lance.lca.GlobalRegistryAccessor;
import de.uniulm.omi.cloudiator.lance.lca.HostContext;
import de.uniulm.omi.cloudiator.lance.lca.container.ContainerException;
import de.uniulm.omi.cloudiator.lance.lca.container.port.DownstreamAddress;
import de.uniulm.omi.cloudiator.lance.lca.container.port.PortDiff;
......@@ -44,15 +46,21 @@ public final class LifecycleController {
private final ErrorAwareStateMachine<LifecycleHandlerType> machine;
private final LifecycleActionInterceptor interceptor;
private final GlobalRegistryAccessor accessor;
private final StopDetectorHandler stopDetector;
private final StopDetectorCallback callback;
private final HostContext hostContext;
public LifecycleController(LifecycleStore storeParam,
LifecycleActionInterceptor interceptorParam, GlobalRegistryAccessor accessorParam,
ExecutionContext ecParam) {
ExecutionContext ecParam, HostContext hostContextParam) {
store = storeParam;
ec = ecParam;
interceptor = interceptorParam;
accessor = accessorParam;
machine = initStateMachine();
callback = new StopDetectorCallbackImpl();
hostContext = hostContextParam;
stopDetector = StopDetectorHandler.create(interceptorParam, store.getStopDetector(), ecParam, callback);
}
private ErrorAwareStateMachine<LifecycleHandlerType> initStateMachine() {
......@@ -68,8 +76,11 @@ public final class LifecycleController {
LifecycleTransitionHelper.createPreStartAction(builder.getTransitionBuilder(), store, ec);
StartTransitionAction.createStartAction(builder.getTransitionBuilder(), store, ec, interceptor);
LifecycleTransitionHelper.createPostStartAction(builder.getTransitionBuilder(), store, ec);
LifecycleTransitionHelper.createPreStopAction(builder.getTransitionBuilder(), store, ec);
LifecycleTransitionHelper.createStopAction(builder.getTransitionBuilder(), store, ec);
LifecycleTransitionHelper.createSkipStopAction(builder.getTransitionBuilder());
LifecycleTransitionHelper.createPostStopAction(builder.getTransitionBuilder(), store, ec);
return builder.build();
}
......@@ -82,7 +93,7 @@ public final class LifecycleController {
interceptor.postprocess(from);
}
void run(LifecycleHandlerType from, LifecycleHandlerType to) {
private void run(LifecycleHandlerType from, LifecycleHandlerType to) {
try {
preRun(from, to);
machine.transit(from, to);
......@@ -129,32 +140,43 @@ public final class LifecycleController {
// calls 'start handler' and verifies start-up via start detector
run(LifecycleHandlerType.PRE_START, LifecycleHandlerType.START);
// FIXME: establish periodic invocation of stop detector
getLogger().warn("TODO: periodically run stop detector");
stopDetector.scheduleDetection(hostContext);
// invokes POST_START handler and installs stop detector
run(LifecycleHandlerType.START, LifecycleHandlerType.POST_START);
}
public synchronized void blockingStop() {
run(LifecycleHandlerType.POST_START, LifecycleHandlerType.PRE_STOP);
run(LifecycleHandlerType.PRE_STOP, LifecycleHandlerType.STOP);
//FIXME: is a stop detector action required at this point?
getLogger().warn("Stopping instance, running PRE_STOP state!");
run(LifecycleHandlerType.STOP, LifecycleHandlerType.POST_STOP);
stopDetector.clearSchedule();
if(callback.getDetectedState() == DetectorState.NOT_DETECTED) {
run(LifecycleHandlerType.POST_START, LifecycleHandlerType.PRE_STOP);
run(LifecycleHandlerType.PRE_STOP, LifecycleHandlerType.STOP);
try {
stopDetector.waitForFinalShutdown();
} catch(LifecycleException lce) {
// FIXME: here, external resources should be cleared and
// and instance should be moved to error state
}
run(LifecycleHandlerType.STOP, LifecycleHandlerType.POST_STOP);
} else {
// this remains to be discussed //
}