Refactoring XenServer56 and 56FP1 Resources in order to cope with new FenceCommandWrapper

- Unit tests added

Also removed an unit test that was doing nothing.
This commit is contained in:
wilderrodrigues 2015-03-31 07:44:39 +02:00
parent 4600eef87c
commit f3842c81f8
8 changed files with 251 additions and 134 deletions

View File

@ -18,32 +18,22 @@ package com.cloud.hypervisor.xenserver.resource;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;
import com.cloud.agent.api.FenceAnswer;
import com.cloud.agent.api.FenceCommand;
import com.cloud.resource.ServerResource;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Host;
import com.xensource.xenapi.Types.XenAPIException;
import com.xensource.xenapi.VBD;
import com.xensource.xenapi.VDI;
import com.xensource.xenapi.VM;
@Local(value = ServerResource.class)
public class XenServer56FP1Resource extends XenServer56Resource {
private static final long mem_128m = 134217728L;
private static final Logger s_logger = Logger.getLogger(XenServer56FP1Resource.class);
public XenServer56FP1Resource() {
super();
@ -62,52 +52,6 @@ public class XenServer56FP1Resource extends XenServer56Resource {
return files;
}
@Override
protected FenceAnswer execute(final FenceCommand cmd) {
final Connection conn = getConnection();
try {
final Boolean alive = checkHeartbeat(cmd.getHostGuid());
if ( alive == null ) {
s_logger.debug("Failed to check heartbeat, so unable to fence");
return new FenceAnswer(cmd, false, "Failed to check heartbeat, so unable to fence");
}
if ( alive ) {
s_logger.debug("Heart beat is still going so unable to fence");
return new FenceAnswer(cmd, false, "Heartbeat is still going on unable to fence");
}
final Set<VM> vms = VM.getByNameLabel(conn, cmd.getVmName());
for (final VM vm : vms) {
final Set<VDI> vdis = new HashSet<VDI>();
final Set<VBD> vbds = vm.getVBDs(conn);
for (final VBD vbd : vbds) {
final VDI vdi = vbd.getVDI(conn);
if (!isRefNull(vdi)) {
vdis.add(vdi);
}
}
s_logger.info("Fence command for VM " + cmd.getVmName());
vm.powerStateReset(conn);
vm.destroy(conn);
for (final VDI vdi : vdis) {
final Map<String, String> smConfig = vdi.getSmConfig(conn);
for (final String key : smConfig.keySet()) {
if (key.startsWith("host_")) {
vdi.removeFromSmConfig(conn, key);
break;
}
}
}
}
return new FenceAnswer(cmd);
} catch (final XmlRpcException e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(cmd, false, e.getMessage());
} catch (final XenAPIException e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(cmd, false, e.getMessage());
}
}
/**
* When Dynamic Memory Control (DMC) is enabled -
* xenserver allows scaling the guest memory while the guest is running

View File

@ -19,7 +19,6 @@ package com.cloud.hypervisor.xenserver.resource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.ejb.Local;
@ -28,8 +27,6 @@ import org.apache.xmlrpc.XmlRpcException;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.FenceAnswer;
import com.cloud.agent.api.FenceCommand;
import com.cloud.agent.api.NetworkUsageAnswer;
import com.cloud.agent.api.NetworkUsageCommand;
import com.cloud.agent.api.StartupCommand;
@ -46,7 +43,6 @@ import com.xensource.xenapi.PIF;
import com.xensource.xenapi.Types.IpConfigurationMode;
import com.xensource.xenapi.Types.XenAPIException;
import com.xensource.xenapi.VLAN;
import com.xensource.xenapi.VM;
@Local(value = ServerResource.class)
public class XenServer56Resource extends CitrixResourceBase {
@ -63,9 +59,7 @@ public class XenServer56Resource extends CitrixResourceBase {
// Ignore this for now. Still working on converting the other commands.
}
if (cmd instanceof FenceCommand) {
return execute((FenceCommand) cmd);
} else if (cmd instanceof NetworkUsageCommand) {
if (cmd instanceof NetworkUsageCommand) {
return execute((NetworkUsageCommand) cmd);
} else {
return super.executeRequest(cmd);
@ -238,34 +232,6 @@ public class XenServer56Resource extends CitrixResourceBase {
}
}
protected FenceAnswer execute(final FenceCommand cmd) {
final Connection conn = getConnection();
try {
final Boolean alive = checkHeartbeat(cmd.getHostGuid());
if (alive == null) {
s_logger.debug("Failed to check heartbeat, so unable to fence");
return new FenceAnswer(cmd, false, "Failed to check heartbeat, so unable to fence");
}
if (alive) {
s_logger.debug("Heart beat is still going so unable to fence");
return new FenceAnswer(cmd, false, "Heartbeat is still going on unable to fence");
}
final Set<VM> vms = VM.getByNameLabel(conn, cmd.getVmName());
for (final VM vm : vms) {
s_logger.info("Fence command for VM " + cmd.getVmName());
vm.powerStateReset(conn);
vm.destroy(conn);
}
return new FenceAnswer(cmd);
} catch (final XmlRpcException e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(cmd, false, e.getMessage());
} catch (final XenAPIException e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(cmd, false, e.getMessage());
}
}
@Override
public boolean transferManagementNetwork(final Connection conn, final Host host, final PIF src, final PIF.Record spr, final PIF dest) throws XmlRpcException, XenAPIException {
dest.reconfigureIp(conn, spr.ipConfigurationMode, spr.IP, spr.netmask, spr.gateway, spr.DNS);

View File

@ -35,6 +35,7 @@ import com.cloud.agent.api.CreateStoragePoolCommand;
import com.cloud.agent.api.CreateVMSnapshotCommand;
import com.cloud.agent.api.DeleteStoragePoolCommand;
import com.cloud.agent.api.DeleteVMSnapshotCommand;
import com.cloud.agent.api.FenceCommand;
import com.cloud.agent.api.GetHostStatsCommand;
import com.cloud.agent.api.GetStorageStatsCommand;
import com.cloud.agent.api.GetVmDiskStatsCommand;
@ -82,6 +83,7 @@ import com.cloud.agent.api.storage.DestroyCommand;
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
import com.cloud.agent.api.storage.ResizeVolumeCommand;
import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase;
import com.cloud.hypervisor.xenserver.resource.XenServer56FP1Resource;
import com.cloud.hypervisor.xenserver.resource.XenServer56Resource;
import com.cloud.resource.CommandWrapper;
import com.cloud.resource.RequestWrapper;
@ -173,8 +175,14 @@ public class CitrixRequestWrapper extends RequestWrapper {
// XenServer56Resource commands
final Hashtable<Class<? extends Command>, CommandWrapper> xenServer56Commands = new Hashtable<Class<? extends Command>, CommandWrapper>();
xenServer56Commands.put(CheckOnHostCommand.class, new XenServer56CheckOnHostCommandWrapper());
xenServer56Commands.put(FenceCommand.class, new XenServer56FenceCommandWrapper());
resources.put(XenServer56Resource.class, xenServer56Commands);
// XenServer56FP1Resource commands
final Hashtable<Class<? extends Command>, CommandWrapper> xenServer56P1Commands = new Hashtable<Class<? extends Command>, CommandWrapper>();
xenServer56P1Commands.put(FenceCommand.class, new XenServer56FP1FenceCommandWrapper());
resources.put(XenServer56FP1Resource.class, xenServer56P1Commands);
initialised = true;
}

View File

@ -0,0 +1,92 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 com.cloud.hypervisor.xenserver.resource.wrapper;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.FenceAnswer;
import com.cloud.agent.api.FenceCommand;
import com.cloud.hypervisor.xenserver.resource.XenServer56Resource;
import com.cloud.resource.CommandWrapper;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Types.XenAPIException;
import com.xensource.xenapi.VBD;
import com.xensource.xenapi.VDI;
import com.xensource.xenapi.VM;
public final class XenServer56FP1FenceCommandWrapper extends CommandWrapper<FenceCommand, Answer, XenServer56Resource> {
private static final Logger s_logger = Logger.getLogger(XenServer56FP1FenceCommandWrapper.class);
@Override
public Answer execute(final FenceCommand command, final XenServer56Resource xenServer56) {
final Connection conn = xenServer56.getConnection();
try {
final Boolean alive = xenServer56.checkHeartbeat(command.getHostGuid());
if ( alive == null ) {
s_logger.debug("Failed to check heartbeat, so unable to fence");
return new FenceAnswer(command, false, "Failed to check heartbeat, so unable to fence");
}
if ( alive ) {
s_logger.debug("Heart beat is still going so unable to fence");
return new FenceAnswer(command, false, "Heartbeat is still going on unable to fence");
}
final Set<VM> vms = VM.getByNameLabel(conn, command.getVmName());
for (final VM vm : vms) {
final Set<VDI> vdis = new HashSet<VDI>();
final Set<VBD> vbds = vm.getVBDs(conn);
for (final VBD vbd : vbds) {
final VDI vdi = vbd.getVDI(conn);
if (!xenServer56.isRefNull(vdi)) {
vdis.add(vdi);
}
}
s_logger.info("Fence command for VM " + command.getVmName());
vm.powerStateReset(conn);
vm.destroy(conn);
for (final VDI vdi : vdis) {
final Map<String, String> smConfig = vdi.getSmConfig(conn);
for (final String key : smConfig.keySet()) {
if (key.startsWith("host_")) {
vdi.removeFromSmConfig(conn, key);
break;
}
}
}
}
return new FenceAnswer(command);
} catch (final XmlRpcException e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(command, false, e.getMessage());
} catch (final XenAPIException e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(command, false, e.getMessage());
} catch (final Exception e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(command, false, e.getMessage());
}
}
}

View File

@ -0,0 +1,71 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 com.cloud.hypervisor.xenserver.resource.wrapper;
import java.util.Set;
import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.FenceAnswer;
import com.cloud.agent.api.FenceCommand;
import com.cloud.hypervisor.xenserver.resource.XenServer56Resource;
import com.cloud.resource.CommandWrapper;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Types.XenAPIException;
import com.xensource.xenapi.VM;
public final class XenServer56FenceCommandWrapper extends CommandWrapper<FenceCommand, Answer, XenServer56Resource> {
private static final Logger s_logger = Logger.getLogger(XenServer56FenceCommandWrapper.class);
@Override
public Answer execute(final FenceCommand command, final XenServer56Resource xenServer56) {
final Connection conn = xenServer56.getConnection();
try {
final Boolean alive = xenServer56.checkHeartbeat(command.getHostGuid());
if (alive == null) {
s_logger.debug("Failed to check heartbeat, so unable to fence");
return new FenceAnswer(command, false, "Failed to check heartbeat, so unable to fence");
}
if (alive) {
s_logger.debug("Heart beat is still going so unable to fence");
return new FenceAnswer(command, false, "Heartbeat is still going on unable to fence");
}
final Set<VM> vms = VM.getByNameLabel(conn, command.getVmName());
for (final VM vm : vms) {
s_logger.info("Fence command for VM " + command.getVmName());
vm.powerStateReset(conn);
vm.destroy(conn);
}
return new FenceAnswer(command);
} catch (final XmlRpcException e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(command, false, e.getMessage());
} catch (final XenAPIException e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(command, false, e.getMessage());
} catch (final Exception e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(command, false, e.getMessage());
}
}
}

View File

@ -1,39 +0,0 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 com.cloud.ha;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class XenServerFencerTest {
@Test
public void testSetAndGetName() throws Exception {
XenServerFencer xenServerFencer = new XenServerFencer();
String name = "name";
xenServerFencer.setName(name);
String actual = xenServerFencer.getName();
assertEquals(name, actual);
}
}

View File

@ -0,0 +1,49 @@
package com.cloud.hypervisor.xenserver.resource.wrapper;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.modules.junit4.PowerMockRunner;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.FenceCommand;
import com.cloud.host.Host;
import com.cloud.hypervisor.xenserver.resource.XenServer56FP1Resource;
import com.cloud.vm.VMInstanceVO;
import com.xensource.xenapi.Connection;
@RunWith(PowerMockRunner.class)
public class XenServer56FP1WrapperTest {
@Mock
private XenServer56FP1Resource xenServer56Resource;
@Test
public void testFenceCommand() {
final VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
final Host host = Mockito.mock(Host.class);
final Connection conn = Mockito.mock(Connection.class);
final FenceCommand fenceCommand = new FenceCommand(vm, host);
final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
assertNotNull(wrapper);
when(xenServer56Resource.getConnection()).thenReturn(conn);
final Answer answer = wrapper.execute(fenceCommand, xenServer56Resource);
verify(xenServer56Resource, times(1)).getConnection();
verify(xenServer56Resource, times(1)).checkHeartbeat(fenceCommand.getHostGuid());
assertFalse(answer.getResult());
}
}

View File

@ -1,23 +1,27 @@
package com.cloud.hypervisor.xenserver.resource.wrapper;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.CheckOnHostCommand;
import com.cloud.agent.api.FenceCommand;
import com.cloud.host.Host;
import com.cloud.hypervisor.xenserver.resource.XenServer56Resource;
import com.cloud.vm.VMInstanceVO;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Host;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Connection.class, Host.Record.class })
public class XenServer56WrapperTest {
@Mock
@ -35,4 +39,26 @@ public class XenServer56WrapperTest {
assertTrue(answer.getResult());
}
}
@Test
public void testFenceCommand() {
final VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
final Host host = Mockito.mock(Host.class);
final Connection conn = Mockito.mock(Connection.class);
final FenceCommand fenceCommand = new FenceCommand(vm, host);
final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
assertNotNull(wrapper);
when(xenServer56Resource.getConnection()).thenReturn(conn);
final Answer answer = wrapper.execute(fenceCommand, xenServer56Resource);
verify(xenServer56Resource, times(1)).getConnection();
verify(xenServer56Resource, times(1)).checkHeartbeat(fenceCommand.getHostGuid());
assertFalse(answer.getResult());
}
}