First piece of the refactor of the CitrisResourceBase

- The same pattern will be used by the other subclasses of the ServerResource interface.
This commit is contained in:
wilderrodrigues 2015-03-19 15:37:08 +01:00
parent ed979b159f
commit a1e8778211
7 changed files with 304 additions and 74 deletions

View File

@ -0,0 +1,34 @@
//
// 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.resource;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
public abstract class CommandWrapper<T extends Command, A extends Answer, R extends ServerResource> {
/**
* @param T is the command to be used.
* @param R is the resource base to be used.
* @return A and the Answer from the command.
*/
public abstract A execute(T command, R serverResource);
}

View File

@ -0,0 +1,32 @@
//
// 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.resource;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
public abstract class RequestWrapper {
/**
* @param command to be executed.
* @return an Answer for the executed command.
*/
public abstract Answer execute(Command command, ServerResource serverResource);
}

View File

@ -2047,7 +2047,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
}
}
protected String networkUsage(final Connection conn, final String privateIpAddress, final String option, final String vif) {
public String networkUsage(final Connection conn, final String privateIpAddress, final String option, final String vif) {
if (option.equals("get")) {
return "0:0";
}
@ -3096,7 +3096,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
}
}
protected Answer execute(final RebootRouterCommand cmd) {
public Answer execute(final RebootRouterCommand cmd) {
final Connection conn = getConnection();
final RebootAnswer answer = execute((RebootCommand)cmd);
if (answer.getResult()) {
@ -3630,7 +3630,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
return msg;
}
protected String connect(final Connection conn, final String vmname, final String ipAddress) {
public String connect(final Connection conn, final String vmname, final String ipAddress) {
return connect(conn, vmname, ipAddress, 3922);
}

View File

@ -26,15 +26,6 @@ import javax.ejb.Local;
import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Host;
import com.xensource.xenapi.Network;
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;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.CheckOnHostAnswer;
import com.cloud.agent.api.CheckOnHostCommand;
@ -49,13 +40,21 @@ import com.cloud.utils.ExecutionResult;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
import com.cloud.utils.ssh.SSHCmdHelper;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Host;
import com.xensource.xenapi.Network;
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 {
private final static Logger s_logger = Logger.getLogger(XenServer56Resource.class);
@Override
public Answer executeRequest(Command cmd) {
public Answer executeRequest(final Command cmd) {
if (cmd instanceof FenceCommand) {
return execute((FenceCommand)cmd);
} else if (cmd instanceof NetworkUsageCommand) {
@ -68,63 +67,63 @@ public class XenServer56Resource extends CitrixResourceBase {
@Override
protected List<File> getPatchFiles() {
List<File> files = new ArrayList<File>();
String patch = "scripts/vm/hypervisor/xenserver/xenserver56/patch";
String patchfilePath = Script.findScript("", patch);
final List<File> files = new ArrayList<File>();
final String patch = "scripts/vm/hypervisor/xenserver/xenserver56/patch";
final String patchfilePath = Script.findScript("", patch);
if (patchfilePath == null) {
throw new CloudRuntimeException("Unable to find patch file " + patch);
}
File file = new File(patchfilePath);
final File file = new File(patchfilePath);
files.add(file);
return files;
}
@Override
protected void disableVlanNetwork(Connection conn, Network network) {
protected void disableVlanNetwork(final Connection conn, final Network network) {
try {
Network.Record networkr = network.getRecord(conn);
final Network.Record networkr = network.getRecord(conn);
if (!networkr.nameLabel.startsWith("VLAN")) {
return;
}
String bridge = networkr.bridge.trim();
for (PIF pif : networkr.PIFs) {
PIF.Record pifr = pif.getRecord(conn);
final String bridge = networkr.bridge.trim();
for (final PIF pif : networkr.PIFs) {
final PIF.Record pifr = pif.getRecord(conn);
if (!pifr.host.getUuid(conn).equalsIgnoreCase(_host.uuid)) {
continue;
}
VLAN vlan = pifr.VLANMasterOf;
final VLAN vlan = pifr.VLANMasterOf;
if (vlan != null) {
String vlannum = pifr.VLAN.toString();
String device = pifr.device.trim();
final String vlannum = pifr.VLAN.toString();
final String device = pifr.device.trim();
if (vlannum.equals("-1")) {
return;
}
try {
vlan.destroy(conn);
Host host = Host.getByUuid(conn, _host.uuid);
final Host host = Host.getByUuid(conn, _host.uuid);
host.forgetDataSourceArchives(conn, "pif_" + bridge + "_tx");
host.forgetDataSourceArchives(conn, "pif_" + bridge + "_rx");
host.forgetDataSourceArchives(conn, "pif_" + device + "." + vlannum + "_tx");
host.forgetDataSourceArchives(conn, "pif_" + device + "." + vlannum + "_rx");
} catch (XenAPIException e) {
} catch (final XenAPIException e) {
s_logger.trace("Catch " + e.getClass().getName() + ": failed to destory VLAN " + device + " on host " + _host.uuid + " due to " + e.toString());
}
}
return;
}
} catch (XenAPIException e) {
String msg = "Unable to disable VLAN network due to " + e.toString();
} catch (final XenAPIException e) {
final String msg = "Unable to disable VLAN network due to " + e.toString();
s_logger.warn(msg, e);
} catch (Exception e) {
String msg = "Unable to disable VLAN network due to " + e.getMessage();
} catch (final Exception e) {
final String msg = "Unable to disable VLAN network due to " + e.getMessage();
s_logger.warn(msg, e);
}
}
@Override
protected String networkUsage(Connection conn, final String privateIpAddress, final String option, final String vif) {
public String networkUsage(final Connection conn, final String privateIpAddress, final String option, final String vif) {
String args = "";
if (option.equals("get")) {
args += "-g";
@ -143,18 +142,18 @@ public class XenServer56Resource extends CitrixResourceBase {
return executeInVR(privateIpAddress, "netusage.sh", args).getDetails();
}
protected NetworkUsageAnswer VPCNetworkUsage(NetworkUsageCommand cmd) {
protected NetworkUsageAnswer VPCNetworkUsage(final NetworkUsageCommand cmd) {
try {
Connection conn = getConnection();
String option = cmd.getOption();
String publicIp = cmd.getGatewayIP();
final Connection conn = getConnection();
final String option = cmd.getOption();
final String publicIp = cmd.getGatewayIP();
String args = " -l " + publicIp + " ";
if (option.equals("get")) {
args += "-g";
} else if (option.equals("create")) {
args += "-c";
String vpcCIDR = cmd.getVpcCIDR();
final String vpcCIDR = cmd.getVpcCIDR();
args += " -v " + vpcCIDR;
} else if (option.equals("reset")) {
args += "-r";
@ -166,67 +165,67 @@ public class XenServer56Resource extends CitrixResourceBase {
return new NetworkUsageAnswer(cmd, "success", 0L, 0L);
}
ExecutionResult result = executeInVR(cmd.getPrivateIP(), "vpc_netusage.sh", args);
String detail = result.getDetails();
final ExecutionResult result = executeInVR(cmd.getPrivateIP(), "vpc_netusage.sh", args);
final String detail = result.getDetails();
if (!result.isSuccess()) {
throw new Exception(" vpc network usage plugin call failed ");
}
if (option.equals("get") || option.equals("vpn")) {
long[] stats = new long[2];
final long[] stats = new long[2];
if (detail != null) {
String[] splitResult = detail.split(":");
final String[] splitResult = detail.split(":");
int i = 0;
while (i < splitResult.length - 1) {
stats[0] += (new Long(splitResult[i++])).longValue();
stats[1] += (new Long(splitResult[i++])).longValue();
stats[0] += new Long(splitResult[i++]).longValue();
stats[1] += new Long(splitResult[i++]).longValue();
}
return new NetworkUsageAnswer(cmd, "success", stats[0], stats[1]);
}
}
return new NetworkUsageAnswer(cmd, "success", 0L, 0L);
} catch (Exception ex) {
} catch (final Exception ex) {
s_logger.warn("Failed to get network usage stats due to ", ex);
return new NetworkUsageAnswer(cmd, ex);
}
}
protected NetworkUsageAnswer execute(NetworkUsageCommand cmd) {
protected NetworkUsageAnswer execute(final NetworkUsageCommand cmd) {
if (cmd.isForVpc()) {
return VPCNetworkUsage(cmd);
}
try {
Connection conn = getConnection();
final Connection conn = getConnection();
if (cmd.getOption() != null && cmd.getOption().equals("create")) {
String result = networkUsage(conn, cmd.getPrivateIP(), "create", null);
NetworkUsageAnswer answer = new NetworkUsageAnswer(cmd, result, 0L, 0L);
final String result = networkUsage(conn, cmd.getPrivateIP(), "create", null);
final NetworkUsageAnswer answer = new NetworkUsageAnswer(cmd, result, 0L, 0L);
return answer;
}
long[] stats = getNetworkStats(conn, cmd.getPrivateIP());
NetworkUsageAnswer answer = new NetworkUsageAnswer(cmd, "", stats[0], stats[1]);
final long[] stats = getNetworkStats(conn, cmd.getPrivateIP());
final NetworkUsageAnswer answer = new NetworkUsageAnswer(cmd, "", stats[0], stats[1]);
return answer;
} catch (Exception ex) {
} catch (final Exception ex) {
s_logger.warn("Failed to get network usage stats due to ", ex);
return new NetworkUsageAnswer(cmd, ex);
}
}
protected Boolean check_heartbeat(String hostuuid) {
com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_host.ip, 22);
protected Boolean check_heartbeat(final String hostuuid) {
final com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_host.ip, 22);
try {
sshConnection.connect(null, 60000, 60000);
if (!sshConnection.authenticateWithPassword(_username, _password.peek())) {
throw new CloudRuntimeException("Unable to authenticate");
}
String shcmd = "/opt/cloud/bin/check_heartbeat.sh " + hostuuid + " "
+ Integer.toString(_heartbeatInterval * 2);
final String shcmd = "/opt/cloud/bin/check_heartbeat.sh " + hostuuid + " "
+ Integer.toString(_heartbeatInterval * 2);
if (!SSHCmdHelper.sshExecuteCmd(sshConnection, shcmd)) {
s_logger.debug("Heart beat is gone so dead.");
return false;
}
s_logger.debug("Heart beat is still going");
return true;
} catch (Exception e) {
} catch (final Exception e) {
s_logger.debug("health check failed due to catch exception " + e.toString());
return null;
} finally {
@ -234,10 +233,10 @@ public class XenServer56Resource extends CitrixResourceBase {
}
}
protected FenceAnswer execute(FenceCommand cmd) {
Connection conn = getConnection();
protected FenceAnswer execute(final FenceCommand cmd) {
final Connection conn = getConnection();
try {
Boolean alive = check_heartbeat(cmd.getHostGuid());
final Boolean alive = check_heartbeat(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");
@ -246,17 +245,17 @@ public class XenServer56Resource extends CitrixResourceBase {
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");
}
Set<VM> vms = VM.getByNameLabel(conn, cmd.getVmName());
for (VM vm : vms) {
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 (XmlRpcException e) {
} catch (final XmlRpcException e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(cmd, false, e.getMessage());
} catch (XenAPIException e) {
} catch (final XenAPIException e) {
s_logger.warn("Unable to fence", e);
return new FenceAnswer(cmd, false, e.getMessage());
}
@ -264,11 +263,11 @@ public class XenServer56Resource extends CitrixResourceBase {
@Override
protected boolean transferManagementNetwork(Connection conn, Host host, PIF src, PIF.Record spr, PIF dest) throws XmlRpcException, XenAPIException {
protected 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);
Host.managementReconfigure(conn, dest);
String hostUuid = null;
int count = 0;
final int count = 0;
while (count < 10) {
try {
Thread.sleep(10000);
@ -276,11 +275,11 @@ public class XenServer56Resource extends CitrixResourceBase {
if (hostUuid != null) {
break;
}
} catch (XmlRpcException e) {
} catch (final XmlRpcException e) {
s_logger.debug("Waiting for host to come back: " + e.getMessage());
} catch (XenAPIException e) {
} catch (final XenAPIException e) {
s_logger.debug("Waiting for host to come back: " + e.getMessage());
} catch (InterruptedException e) {
} catch (final InterruptedException e) {
s_logger.debug("Gotta run");
return false;
}
@ -297,21 +296,21 @@ public class XenServer56Resource extends CitrixResourceBase {
@Override
public StartupCommand[] initialize() {
pingXAPI();
StartupCommand[] cmds = super.initialize();
final StartupCommand[] cmds = super.initialize();
return cmds;
}
@Override
protected CheckOnHostAnswer execute(CheckOnHostCommand cmd) {
Boolean alive = check_heartbeat(cmd.getHost().getGuid());
protected CheckOnHostAnswer execute(final CheckOnHostCommand cmd) {
final Boolean alive = check_heartbeat(cmd.getHost().getGuid());
String msg = "";
if (alive == null) {
msg = " cannot determine ";
msg = " cannot determine ";
} else if ( alive == true) {
msg = "Heart beat is still going";
msg = "Heart beat is still going";
} else {
msg = "Heart beat is gone so dead.";
msg = "Heart beat is gone so dead.";
}
s_logger.debug(msg);
return new CheckOnHostAnswer(cmd, alive, msg);

View File

@ -0,0 +1,50 @@
//
// 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 com.cloud.agent.api.Answer;
import com.cloud.agent.api.RebootAnswer;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.RebootRouterCommand;
import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase;
import com.cloud.resource.CommandWrapper;
import com.xensource.xenapi.Connection;
public final class CitrixRebootRouterCommandWrapper extends CommandWrapper<RebootRouterCommand, Answer, CitrixResourceBase> {
@Override
public Answer execute(final RebootRouterCommand command, final CitrixResourceBase citrixResourceBase) {
final Connection conn = citrixResourceBase.getConnection();
final RebootAnswer answer = citrixResourceBase.execute((RebootCommand)command);
if (answer.getResult()) {
final String cnct = citrixResourceBase.connect(conn, command.getVmName(), command.getPrivateIpAddress());
citrixResourceBase.networkUsage(conn, command.getPrivateIpAddress(), "create", null);
if (cnct == null) {
return answer;
} else {
return new Answer(command, false, cnct);
}
}
return answer;
}
}

View File

@ -0,0 +1,63 @@
//
// 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.Hashtable;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.RebootRouterCommand;
import com.cloud.resource.CommandWrapper;
import com.cloud.resource.RequestWrapper;
import com.cloud.resource.ServerResource;
public class CitrixRequestWrapper extends RequestWrapper {
private static CitrixRequestWrapper instance;
static {
instance = new CitrixRequestWrapper();
}
@SuppressWarnings("rawtypes")
private final Hashtable<Class<? extends Command>, CommandWrapper> map;
@SuppressWarnings("rawtypes")
private CitrixRequestWrapper() {
map = new Hashtable<Class<? extends Command>, CommandWrapper>();
init();
}
private void init() {
map.put(RebootRouterCommand.class, new CitrixRebootRouterCommandWrapper());
}
public static CitrixRequestWrapper getInstance() {
return instance;
}
@Override
public Answer execute(final Command command, final ServerResource serverResource) {
@SuppressWarnings("unchecked")
final CommandWrapper<Command, Answer, ServerResource> commandWrapper = map.get(command.getClass());
return commandWrapper.execute(command, serverResource);
}
}

View File

@ -0,0 +1,52 @@
package com.cloud.hypervisor.xenserver.resource.wrapper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.RebootAnswer;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.RebootRouterCommand;
import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase;
@RunWith(MockitoJUnitRunner.class)
public class CitrixRequestWrapperTest {
@Mock
protected CitrixResourceBase citrixResourceBase;
@Mock
protected RebootAnswer rebootAnswer;
@Test
public void testWrapperInstance() {
final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
assertNotNull(wrapper);
}
@Test
public void testExecuteRebootRouterCommand() {
final RebootRouterCommand rebootCommand = new RebootRouterCommand("", "");
final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
assertNotNull(wrapper);
doReturn(rebootAnswer).when(citrixResourceBase).execute((RebootCommand)rebootCommand);
doReturn(false).when(rebootAnswer).getResult();
final Answer answer = wrapper.execute(rebootCommand, citrixResourceBase);
verify(citrixResourceBase, times(1)).execute((RebootCommand)rebootCommand);
assertFalse(rebootAnswer.getResult());
assertEquals(answer, rebootAnswer);
}
}