Martin Peřina has uploaded a new change for review. Change subject: core: Introduce HostFenceActionExecutor ......................................................................
core: Introduce HostFenceActionExecutor Introduces HostFenceActionExecutor which is responsible to execute fence action on specified host. Change-Id: I15bbc7e4a7a297173d3486394ac53587306078b1 Bug-Url: https://bugzilla.redhat.com/1182510 Signed-off-by: Martin Perina <[email protected]> --- A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/pm/HostFenceActionExecutor.java A backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/pm/HostFenceActionExecutorTest.java 2 files changed, 320 insertions(+), 0 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/65/38965/1 diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/pm/HostFenceActionExecutor.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/pm/HostFenceActionExecutor.java new file mode 100644 index 0000000..681795e --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/pm/HostFenceActionExecutor.java @@ -0,0 +1,109 @@ +package org.ovirt.engine.core.bll.pm; + +import java.util.ArrayList; +import java.util.List; + +import org.ovirt.engine.core.common.businessentities.FenceAgent; +import org.ovirt.engine.core.common.businessentities.FencingPolicy; +import org.ovirt.engine.core.common.businessentities.VDS; +import org.ovirt.engine.core.common.businessentities.pm.FenceActionType; +import org.ovirt.engine.core.common.businessentities.pm.FenceOperationResult; +import org.ovirt.engine.core.common.businessentities.pm.FenceOperationResult.Status; +import org.ovirt.engine.core.common.businessentities.pm.HostPowerStatus; + +/** + * Manages fence execution for the host + */ +public class HostFenceActionExecutor { + /** + * Host which the action is executed for + */ + private final VDS fencedHost; + + /** + * Fencing policy applied during action execution + */ + private final FencingPolicy fencingPolicy; + + public HostFenceActionExecutor(VDS fencedHost) { + this(fencedHost, null); + } + + public HostFenceActionExecutor(VDS fencedHost, FencingPolicy fencingPolicy) { + this.fencedHost = fencedHost; + this.fencingPolicy = fencingPolicy; + } + + /** + * Executes specified power management action on the fencedHost using specified fence agent + * + * @param fenceAction + * specified power management action + * @return result of the action + */ + public FenceOperationResult fence(FenceActionType fenceAction, FenceAgent fenceAgent) { + if (fenceAgent == null) { + return new FenceOperationResult( + Status.ERROR, + HostPowerStatus.UNKNOWN, + "Invalid fence agent specified."); + } + + List<FenceAgent> fenceAgents = new ArrayList<>(); + fenceAgents.add(fenceAgent); + return fence(fenceAction, fenceAgents); + } + + /** + * Executes specified power management action on the fencedHost using fence agents defined for the host + * + * @param fenceAction + * specified power management action + * @return result of the action + */ + public FenceOperationResult fence(FenceActionType fenceAction) { + if (fencedHost.getFenceAgents() == null || fencedHost.getFenceAgents().isEmpty()) { + return new FenceOperationResult( + Status.ERROR, + HostPowerStatus.UNKNOWN, + String.format( + "Invalid fence agents defined for host '%s'.", + fencedHost.getHostName())); + } + return fence(fenceAction, fencedHost.getFenceAgents()); + } + + /** + * Executes specified power management action using specified fence agents + */ + protected FenceOperationResult fence(FenceActionType fenceAction, List<FenceAgent> fenceAgents) { + PowerManagementHelper.AgentsIterator iterator = createFenceAgentsIterator(fenceAgents); + FenceOperationResult result = null; + while (iterator.hasNext()) { + result = createFenceActionExecutor(iterator.next()).fence(fenceAction); + if (result.getStatus() == Status.SUCCESS) { + break; + } + } + return result; + + } + + /** + * Creates fence agents iterator + */ + protected PowerManagementHelper.AgentsIterator createFenceAgentsIterator(List<FenceAgent> fenceAgents) { + return PowerManagementHelper.getAgentsIterator(fenceAgents); + } + + /** + * Creates instance of {@code FenceActionExecutor} according to specified fence agents + */ + FenceActionExecutor createFenceActionExecutor(List<FenceAgent> fenceAgents) { + if (fenceAgents.size() == 1) { + return new SingleAgentFenceActionExecutor(fencedHost, fenceAgents.get(0), fencingPolicy); + } else { + return new ConcurrentAgentsFenceActionExecutor(fencedHost, fenceAgents, fencingPolicy); + } + } +} diff --git a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/pm/HostFenceActionExecutorTest.java b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/pm/HostFenceActionExecutorTest.java new file mode 100644 index 0000000..f09919f --- /dev/null +++ b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/pm/HostFenceActionExecutorTest.java @@ -0,0 +1,211 @@ +package org.ovirt.engine.core.bll.pm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.ovirt.engine.core.common.businessentities.FenceAgent; +import org.ovirt.engine.core.common.businessentities.FencingPolicy; +import org.ovirt.engine.core.common.businessentities.VDS; +import org.ovirt.engine.core.common.businessentities.pm.FenceActionType; +import org.ovirt.engine.core.common.businessentities.pm.FenceOperationResult; +import org.ovirt.engine.core.common.businessentities.pm.FenceOperationResult.Status; +import org.ovirt.engine.core.common.businessentities.pm.HostPowerStatus; +import org.ovirt.engine.core.compat.Guid; + +@RunWith(MockitoJUnitRunner.class) +public class HostFenceActionExecutorTest { + @Mock + VDS fencedHost; + + @Mock + SingleAgentFenceActionExecutor agentExecutor1; + + @Mock + SingleAgentFenceActionExecutor agentExecutor2; + + HostFenceActionExecutor executor; + + List<FenceAgent> fenceAgents; + + @Before + public void setup() { + doReturn("host1").when(fencedHost).getHostName(); + + executor = spy(new HostFenceActionExecutor(fencedHost, new FencingPolicy())); + doReturn(agentExecutor1) + .doReturn(agentExecutor2) + .when(executor).createFenceActionExecutor(any(List.class)); + } + + /** + * Test successful fence action when the 1st of 2 sequential fence agents returns success + */ + @Test + public void successfulFenceWith1stSuccess() { + mockFenceAgents(); + + // result of fence action invoked on 1st sequential agent + mockFenceResult( + agentExecutor1, + new FenceOperationResult(Status.SUCCESS, HostPowerStatus.ON)); + + // result of fence action invoked on 2nd sequential agent - set it to error, so we verify that it's not used + mockFenceResult( + agentExecutor2, + new FenceOperationResult(Status.ERROR, HostPowerStatus.UNKNOWN)); + + FenceOperationResult result = executor.fence(FenceActionType.STATUS); + + assertEquals(Status.SUCCESS, result.getStatus()); + assertEquals(HostPowerStatus.ON, result.getPowerStatus()); + } + + /** + * Test successful fence action when the 1st of 2 sequential fence agents returns error and 2nd one return success + */ + @Test + public void successfulFenceWith1stError2ndSuccess() { + mockFenceAgents(); + + // result of fence action invoked on 1st sequential agent + mockFenceResult( + agentExecutor1, + new FenceOperationResult(Status.ERROR, HostPowerStatus.UNKNOWN)); + + // result of fence action invoked on 2nd sequential agent + mockFenceResult( + agentExecutor2, + new FenceOperationResult(Status.SUCCESS, HostPowerStatus.ON)); + + FenceOperationResult result = executor.fence(FenceActionType.STATUS); + + assertEquals(Status.SUCCESS, result.getStatus()); + assertEquals(HostPowerStatus.ON, result.getPowerStatus()); + } + + /** + * Test failed fence action when both of 2 sequential fence agents return error + */ + @Test + public void failedFenceWithAllError() { + mockFenceAgents(); + + // result of fence action invoked on 1st sequential agent + mockFenceResult( + agentExecutor1, + new FenceOperationResult(Status.ERROR, HostPowerStatus.UNKNOWN)); + + // result of fence action invoked on 2nd sequential agent + mockFenceResult( + agentExecutor2, + new FenceOperationResult(Status.ERROR, HostPowerStatus.UNKNOWN)); + + FenceOperationResult result = executor.fence(FenceActionType.STATUS); + + assertEquals(Status.ERROR, result.getStatus()); + assertEquals(HostPowerStatus.UNKNOWN, result.getPowerStatus()); + } + + /** + * Test successful fence action using specified fence agent + */ + @Test + public void successfulFenceWithSpecifiedFenceAgent() { + // result of fence action invoked on specified agent + mockFenceResult( + agentExecutor1, + new FenceOperationResult(Status.SUCCESS, HostPowerStatus.ON)); + + FenceOperationResult result = executor.fence(FenceActionType.STATUS, createFenceAgent(1)); + + assertEquals(Status.SUCCESS, result.getStatus()); + assertEquals(HostPowerStatus.ON, result.getPowerStatus()); + } + + /** + * Test failed fence action using specified fence agent + */ + @Test + public void failedFenceWithSpecifiedFenceAgent() { + // result of fence action invoked on specified agent + mockFenceResult( + agentExecutor1, + new FenceOperationResult(Status.ERROR, HostPowerStatus.UNKNOWN)); + + FenceOperationResult result = executor.fence(FenceActionType.STATUS, createFenceAgent(1)); + + assertEquals(Status.ERROR, result.getStatus()); + assertEquals(HostPowerStatus.UNKNOWN, result.getPowerStatus()); + } + + /** + * Tests {@code SingleAgentFenceActionExecutor} creation for single fence agent + */ + @Test + public void testSingleAgentFenceActionExecutorUsage() { + HostFenceActionExecutor executor = new HostFenceActionExecutor(fencedHost, new FencingPolicy()); + + assertTrue( + executor.createFenceActionExecutor(createSingleAgentList(1)) + instanceof SingleAgentFenceActionExecutor); + } + + /** + * Tests {@code ConcurrentAgentsFenceActionExecutor} creation for concurrent fence agents + */ + @Test + public void testConcurrentAgentsFenceActionExecutorUsage() { + HostFenceActionExecutor executor = new HostFenceActionExecutor(fencedHost, new FencingPolicy()); + + assertTrue( + executor.createFenceActionExecutor(createConcurrentAgentsList(2, 1)) + instanceof ConcurrentAgentsFenceActionExecutor); + } + + protected FenceAgent createFenceAgent(int order) { + FenceAgent agent = new FenceAgent(); + agent.setId(Guid.newGuid()); + agent.setOrder(order); + return agent; + } + + protected List<FenceAgent> createSingleAgentList(int order) { + List<FenceAgent> fenceAgents = new ArrayList<>(); + fenceAgents.add(createFenceAgent(order)); + return fenceAgents; + } + + protected List<FenceAgent> createConcurrentAgentsList(int count, int order) { + List<FenceAgent> fenceAgents = new ArrayList<>(); + for (int i = 0; i < count; i++) { + fenceAgents.add(createFenceAgent(order)); + } + return fenceAgents; + } + + protected List<FenceAgent> create2SequentialFenceAgents() { + List<FenceAgent> fenceAgents = createSingleAgentList(1); + fenceAgents.addAll(createSingleAgentList(2)); + return fenceAgents; + } + + protected void mockFenceResult(FenceActionExecutor executor, FenceOperationResult result) { + doReturn(result).when(executor).fence(any(FenceActionType.class)); + } + + protected void mockFenceAgents() { + fenceAgents = create2SequentialFenceAgents(); + doReturn(fenceAgents).when(fencedHost).getFenceAgents(); + } +} -- To view, visit https://gerrit.ovirt.org/38965 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I15bbc7e4a7a297173d3486394ac53587306078b1 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Martin Peřina <[email protected]> _______________________________________________ Engine-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/engine-patches
