From 74faf73408f805af7ac64a081c711f1ceac0a144 Mon Sep 17 00:00:00 2001 From: wilderrodrigues Date: Thu, 26 Mar 2015 15:56:18 +0100 Subject: [PATCH] Refactoring CheckOnHostCommand, ModifySshKeysCommand, OvsSetTagAndFlowCommand and StartCommand to cope with new design - Unit tests added --- .../resource/CitrixResourceBase.java | 36 +-- .../xenserver/resource/XcpOssResource.java | 2 +- .../resource/XenServer620SP1Resource.java | 2 +- .../CitrixCheckOnHostCommandWrapper.java | 34 +++ .../CitrixModifySshKeysCommandWrapper.java | 33 +++ .../CitrixOvsSetTagAndFlowCommandWrapper.java | 72 ++++++ .../wrapper/CitrixRequestWrapper.java | 8 + .../wrapper/CitrixStartCommandWrapper.java | 210 ++++++++++++++++++ .../wrapper/CitrixRequestWrapperTest.java | 149 ++++++++++--- 9 files changed, 498 insertions(+), 48 deletions(-) create mode 100644 plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixCheckOnHostCommandWrapper.java create mode 100644 plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixModifySshKeysCommandWrapper.java create mode 100644 plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixOvsSetTagAndFlowCommandWrapper.java create mode 100644 plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixStartCommandWrapper.java diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index 50859afa66e..c9b05a4cf68 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -340,6 +340,14 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return _host; } + public boolean isOvs() { + return _isOvs; + } + + public void setIsOvs(final boolean isOvs) { + _isOvs = isOvs; + } + public boolean isSecurityGroupEnabled() { return _securityGroupEnabled; } @@ -453,12 +461,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe if (cmd instanceof NetworkElementCommand) { return _vrResource.executeRequest((NetworkElementCommand)cmd); - } else if (clazz == CheckOnHostCommand.class) { - return execute((CheckOnHostCommand)cmd); - } else if (clazz == ModifySshKeysCommand.class) { - return execute((ModifySshKeysCommand)cmd); - } else if (clazz == StartCommand.class) { - return execute((StartCommand)cmd); } else if (clazz == CheckSshCommand.class) { return execute((CheckSshCommand)cmd); } else if (clazz == SecurityGroupRulesCmd.class) { @@ -467,8 +469,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return execute((OvsFetchInterfaceCommand)cmd); } else if (clazz == OvsCreateGreTunnelCommand.class) { return execute((OvsCreateGreTunnelCommand)cmd); - } else if (clazz == OvsSetTagAndFlowCommand.class) { - return execute((OvsSetTagAndFlowCommand)cmd); } else if (clazz == OvsDeleteFlowCommand.class) { return execute((OvsDeleteFlowCommand)cmd); } else if (clazz == OvsVpcPhysicalTopologyConfigCommand.class) { @@ -863,7 +863,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe throw new CloudRuntimeException("Unsupported network type: " + type); } - private synchronized Network setupvSwitchNetwork(final Connection conn) { + public synchronized Network setupvSwitchNetwork(final Connection conn) { try { if (_host.getVswitchNetwork() == null) { Network vswitchNw = null; @@ -1052,7 +1052,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } - protected VIF createVif(final Connection conn, final String vmName, final VM vm, final VirtualMachineTO vmSpec, final NicTO nic) throws XmlRpcException, XenAPIException { + public VIF createVif(final Connection conn, final String vmName, final VM vm, final VirtualMachineTO vmSpec, final NicTO nic) throws XmlRpcException, XenAPIException { assert nic.getUuid() != null : "Nic should have a uuid value"; if (s_logger.isDebugEnabled()) { @@ -1198,7 +1198,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } - protected VBD createVbd(final Connection conn, final DiskTO volume, final String vmName, final VM vm, final BootloaderType bootLoaderType, VDI vdi) throws XmlRpcException, XenAPIException { + public VBD createVbd(final Connection conn, final DiskTO volume, final String vmName, final VM vm, final BootloaderType bootLoaderType, VDI vdi) throws XmlRpcException, XenAPIException { final Volume.Type type = volume.getType(); if (vdi == null) { @@ -1287,10 +1287,10 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return null; } - protected void createVGPU(final Connection conn, final StartCommand cmd, final VM vm, final GPUDeviceTO gpuDevice) throws XenAPIException, XmlRpcException { + public void createVGPU(final Connection conn, final StartCommand cmd, final VM vm, final GPUDeviceTO gpuDevice) throws XenAPIException, XmlRpcException { } - protected VM createVmFromTemplate(final Connection conn, final VirtualMachineTO vmSpec, final Host host) throws XenAPIException, XmlRpcException { + public VM createVmFromTemplate(final Connection conn, final VirtualMachineTO vmSpec, final Host host) throws XenAPIException, XmlRpcException { final String guestOsTypeName = getGuestOsType(vmSpec.getOs(), vmSpec.getPlatformEmulator(), vmSpec.getBootloader() == BootloaderType.CD); final Set templates = VM.getByNameLabel(conn, guestOsTypeName); if ( templates == null || templates.isEmpty()) { @@ -1454,7 +1454,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } - protected String handleVmStartFailure(final Connection conn, final String vmName, final VM vm, final String message, final Throwable th) { + public String handleVmStartFailure(final Connection conn, final String vmName, final VM vm, final String message, final Throwable th) { final String msg = "Unable to start " + vmName + " due to " + message; s_logger.warn(msg, th); @@ -1519,7 +1519,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return msg; } - protected VBD createPatchVbd(final Connection conn, final String vmName, final VM vm) throws XmlRpcException, XenAPIException { + public VBD createPatchVbd(final Connection conn, final String vmName, final VM vm) throws XmlRpcException, XenAPIException { if (_host.getSystemvmisouuid() == null) { final Set srs = SR.getByNameLabel(conn, "XenServer Tools"); @@ -1607,7 +1607,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return new CheckSshAnswer(cmd); } - private HashMap parseDefaultOvsRuleComamnd(final String str) { + public HashMap parseDefaultOvsRuleComamnd(final String str) { final HashMap cmd = new HashMap(); final String[] sarr = str.split("/"); for (int i = 0; i < sarr.length; i++) { @@ -1864,7 +1864,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe // the idea here is to see if the DiskTO in question is from managed storage and // does not yet have an SR // if no SR, create it and create a VDI in it - private VDI prepareManagedDisk(final Connection conn, final DiskTO disk, final String vmName) throws Exception { + public VDI prepareManagedDisk(final Connection conn, final DiskTO disk, final String vmName) throws Exception { final Map details = disk.getDetails(); if (details == null) { @@ -3297,7 +3297,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } - void startVM(final Connection conn, final Host host, final VM vm, final String vmName) throws Exception { + public void startVM(final Connection conn, final Host host, final VM vm, final String vmName) throws Exception { Task task = null; try { task = vm.startOnAsync(conn, host, false, true); diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java index 312b34cc295..540044e5d04 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java @@ -123,7 +123,7 @@ public class XcpOssResource extends CitrixResourceBase { } @Override - protected synchronized VBD createPatchVbd(final Connection conn, final String vmName, final VM vm) throws XmlRpcException, XenAPIException { + public synchronized VBD createPatchVbd(final Connection conn, final String vmName, final VM vm) throws XmlRpcException, XenAPIException { if (_host.getLocalSRuuid() != null) { //create an iso vdi on it final String result = callHostPlugin(conn, "vmops", "createISOVHD", "uuid", _host.getLocalSRuuid()); diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer620SP1Resource.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer620SP1Resource.java index e6c66a41c14..0704e8e4b62 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer620SP1Resource.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer620SP1Resource.java @@ -136,7 +136,7 @@ public class XenServer620SP1Resource extends XenServer620Resource { } @Override - protected void createVGPU(final Connection conn, final StartCommand cmd, final VM vm, final GPUDeviceTO gpuDevice) throws XenAPIException, XmlRpcException { + public void createVGPU(final Connection conn, final StartCommand cmd, final VM vm, final GPUDeviceTO gpuDevice) throws XenAPIException, XmlRpcException { if (s_logger.isDebugEnabled()) { s_logger.debug("Creating VGPU of VGPU type [ " + gpuDevice.getVgpuType() + " ] in gpu group" + gpuDevice.getGpuGroup() + " for VM " + cmd.getVirtualMachine().getName()); diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixCheckOnHostCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixCheckOnHostCommandWrapper.java new file mode 100644 index 00000000000..aaee57b498e --- /dev/null +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixCheckOnHostCommandWrapper.java @@ -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.hypervisor.xenserver.resource.wrapper; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CheckOnHostAnswer; +import com.cloud.agent.api.CheckOnHostCommand; +import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase; +import com.cloud.resource.CommandWrapper; + +public final class CitrixCheckOnHostCommandWrapper extends CommandWrapper { + + @Override + public Answer execute(final CheckOnHostCommand command, final CitrixResourceBase citrixResourceBase) { + return new CheckOnHostAnswer(command, "Not Implmeneted"); + } +} \ No newline at end of file diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixModifySshKeysCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixModifySshKeysCommandWrapper.java new file mode 100644 index 00000000000..8ea852d9127 --- /dev/null +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixModifySshKeysCommandWrapper.java @@ -0,0 +1,33 @@ +// +// 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.ModifySshKeysCommand; +import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase; +import com.cloud.resource.CommandWrapper; + +public final class CitrixModifySshKeysCommandWrapper extends CommandWrapper { + + @Override + public Answer execute(final ModifySshKeysCommand command, final CitrixResourceBase citrixResourceBase) { + return new Answer(command); + } +} \ No newline at end of file diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixOvsSetTagAndFlowCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixOvsSetTagAndFlowCommandWrapper.java new file mode 100644 index 00000000000..2048f4d16d2 --- /dev/null +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixOvsSetTagAndFlowCommandWrapper.java @@ -0,0 +1,72 @@ +// +// 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 org.apache.log4j.Logger; +import org.apache.xmlrpc.XmlRpcException; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.OvsSetTagAndFlowAnswer; +import com.cloud.agent.api.OvsSetTagAndFlowCommand; +import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase; +import com.cloud.resource.CommandWrapper; +import com.xensource.xenapi.Connection; +import com.xensource.xenapi.Network; +import com.xensource.xenapi.Types.BadServerResponse; +import com.xensource.xenapi.Types.XenAPIException; + +public final class CitrixOvsSetTagAndFlowCommandWrapper extends CommandWrapper { + + private static final Logger s_logger = Logger.getLogger(CitrixOvsSetTagAndFlowCommandWrapper.class); + + @Override + public Answer execute(final OvsSetTagAndFlowCommand command, final CitrixResourceBase citrixResourceBase) { + citrixResourceBase.setIsOvs(true); + + final Connection conn = citrixResourceBase.getConnection(); + try { + final Network nw = citrixResourceBase.setupvSwitchNetwork(conn); + final String bridge = nw.getBridge(conn); + + /* + * If VM is domainRouter, this will try to set flow and tag on its + * none guest network nic. don't worry, it will fail silently at + * host plugin side + */ + final String result = citrixResourceBase.callHostPlugin(conn, "ovsgre", "ovs_set_tag_and_flow", "bridge", bridge, "vmName", command.getVmName(), "tag", + command.getTag(), "vlans", command.getVlans(), "seqno", command.getSeqNo()); + s_logger.debug("set flow for " + command.getVmName() + " " + result); + + if (result != null && result.equalsIgnoreCase("SUCCESS")) { + return new OvsSetTagAndFlowAnswer(command, true, result); + } else { + return new OvsSetTagAndFlowAnswer(command, false, result); + } + } catch (final BadServerResponse e) { + s_logger.error("Failed to set tag and flow", e); + } catch (final XenAPIException e) { + s_logger.error("Failed to set tag and flow", e); + } catch (final XmlRpcException e) { + s_logger.error("Failed to set tag and flow", e); + } + + return new OvsSetTagAndFlowAnswer(command, false, "EXCEPTION"); + } +} \ No newline at end of file diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java index badc892b2ee..fbb3f27c42d 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java @@ -25,6 +25,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; import com.cloud.agent.api.AttachVolumeCommand; import com.cloud.agent.api.CheckHealthCommand; +import com.cloud.agent.api.CheckOnHostCommand; import com.cloud.agent.api.CheckVirtualMachineCommand; import com.cloud.agent.api.Command; import com.cloud.agent.api.CreateStoragePoolCommand; @@ -36,13 +37,16 @@ import com.cloud.agent.api.GetVmStatsCommand; import com.cloud.agent.api.GetVncPortCommand; import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.MigrateCommand; +import com.cloud.agent.api.ModifySshKeysCommand; import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.OvsSetTagAndFlowCommand; import com.cloud.agent.api.PingTestCommand; import com.cloud.agent.api.PrepareForMigrationCommand; import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.RebootCommand; import com.cloud.agent.api.RebootRouterCommand; import com.cloud.agent.api.SetupCommand; +import com.cloud.agent.api.StartCommand; import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.UpgradeSnapshotCommand; import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; @@ -101,6 +105,10 @@ public class CitrixRequestWrapper extends RequestWrapper { map.put(SetupCommand.class, new CitrixSetupCommandWrapper()); map.put(MaintainCommand.class, new CitrixMaintainCommandWrapper()); map.put(PingTestCommand.class, new CitrixPingTestCommandWrapper()); + map.put(CheckOnHostCommand.class, new CitrixCheckOnHostCommandWrapper()); + map.put(ModifySshKeysCommand.class, new CitrixModifySshKeysCommandWrapper()); + map.put(StartCommand.class, new CitrixStartCommandWrapper()); + map.put(OvsSetTagAndFlowCommand.class, new CitrixOvsSetTagAndFlowCommandWrapper()); } public static CitrixRequestWrapper getInstance() { diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixStartCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixStartCommandWrapper.java new file mode 100644 index 00000000000..ceaaf3498d6 --- /dev/null +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixStartCommandWrapper.java @@ -0,0 +1,210 @@ +// +// 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.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.OvsSetTagAndFlowAnswer; +import com.cloud.agent.api.OvsSetTagAndFlowCommand; +import com.cloud.agent.api.StartAnswer; +import com.cloud.agent.api.StartCommand; +import com.cloud.agent.api.to.DiskTO; +import com.cloud.agent.api.to.GPUDeviceTO; +import com.cloud.agent.api.to.NicTO; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase; +import com.cloud.network.Networks; +import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.Networks.IsolationType; +import com.cloud.resource.CommandWrapper; +import com.cloud.vm.VirtualMachine; +import com.xensource.xenapi.Connection; +import com.xensource.xenapi.Host; +import com.xensource.xenapi.Types.VmPowerState; +import com.xensource.xenapi.VDI; +import com.xensource.xenapi.VM; + +public final class CitrixStartCommandWrapper extends CommandWrapper { + + private static final Logger s_logger = Logger.getLogger(CitrixStartCommandWrapper.class); + + @Override + public Answer execute(final StartCommand command, final CitrixResourceBase citrixResourceBase) { + final Connection conn = citrixResourceBase.getConnection(); + final VirtualMachineTO vmSpec = command.getVirtualMachine(); + final String vmName = vmSpec.getName(); + VmPowerState state = VmPowerState.HALTED; + VM vm = null; + // if a VDI is created, record its UUID to send back to the CS MS + final Map iqnToPath = new HashMap(); + try { + final Set vms = VM.getByNameLabel(conn, vmName); + if (vms != null) { + for (final VM v : vms) { + final VM.Record vRec = v.getRecord(conn); + if (vRec.powerState == VmPowerState.HALTED) { + v.destroy(conn); + } else if (vRec.powerState == VmPowerState.RUNNING) { + final String host = vRec.residentOn.getUuid(conn); + final String msg = "VM " + vmName + " is runing on host " + host; + s_logger.debug(msg); + return new StartAnswer(command, msg, host); + } else { + final String msg = "There is already a VM having the same name " + vmName + " vm record " + vRec.toString(); + s_logger.warn(msg); + return new StartAnswer(command, msg); + } + } + } + s_logger.debug("1. The VM " + vmName + " is in Starting state."); + + final Host host = Host.getByUuid(conn, citrixResourceBase.getHost().getUuid()); + vm = citrixResourceBase.createVmFromTemplate(conn, vmSpec, host); + + final GPUDeviceTO gpuDevice = vmSpec.getGpuDevice(); + if (gpuDevice != null) { + s_logger.debug("Creating VGPU for of VGPU type: " + gpuDevice.getVgpuType() + " in GPU group " + gpuDevice.getGpuGroup() + " for VM " + vmName); + citrixResourceBase.createVGPU(conn, command, vm, gpuDevice); + } + + for (final DiskTO disk : vmSpec.getDisks()) { + final VDI newVdi = citrixResourceBase.prepareManagedDisk(conn, disk, vmName); + + if (newVdi != null) { + final String path = newVdi.getUuid(conn); + + iqnToPath.put(disk.getDetails().get(DiskTO.IQN), path); + } + + citrixResourceBase.createVbd(conn, disk, vmName, vm, vmSpec.getBootloader(), newVdi); + } + + if (vmSpec.getType() != VirtualMachine.Type.User) { + citrixResourceBase.createPatchVbd(conn, vmName, vm); + } + + for (final NicTO nic : vmSpec.getNics()) { + citrixResourceBase.createVif(conn, vmName, vm, vmSpec, nic); + } + + citrixResourceBase.startVM(conn, host, vm, vmName); + + if (citrixResourceBase.isOvs()) { + // TODO(Salvatore-orlando): This code should go + for (final NicTO nic : vmSpec.getNics()) { + if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vswitch) { + final HashMap args = citrixResourceBase.parseDefaultOvsRuleComamnd(BroadcastDomainType.getValue(nic.getBroadcastUri())); + final OvsSetTagAndFlowCommand flowCmd = new OvsSetTagAndFlowCommand(args.get("vmName"), args.get("tag"), args.get("vlans"), args.get("seqno"), + Long.parseLong(args.get("vmId"))); + + final CitrixRequestWrapper citrixRequestWrapper = CitrixRequestWrapper.getInstance(); + + final OvsSetTagAndFlowAnswer r = (OvsSetTagAndFlowAnswer) citrixRequestWrapper.execute(flowCmd, citrixResourceBase); + + if (!r.getResult()) { + s_logger.warn("Failed to set flow for VM " + r.getVmId()); + } else { + s_logger.info("Success to set flow for VM " + r.getVmId()); + } + } + } + } + + if (citrixResourceBase.canBridgeFirewall()) { + String result = null; + if (vmSpec.getType() != VirtualMachine.Type.User) { + final NicTO[] nics = vmSpec.getNics(); + boolean secGrpEnabled = false; + for (final NicTO nic : nics) { + if (nic.isSecurityGroupEnabled() || nic.getIsolationUri() != null && nic.getIsolationUri().getScheme().equalsIgnoreCase(IsolationType.Ec2.toString())) { + secGrpEnabled = true; + break; + } + } + if (secGrpEnabled) { + result = citrixResourceBase.callHostPlugin(conn, "vmops", "default_network_rules_systemvm", "vmName", vmName); + if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { + s_logger.warn("Failed to program default network rules for " + vmName); + } else { + s_logger.info("Programmed default network rules for " + vmName); + } + } + + } else { + // For user vm, program the rules for each nic if the + // isolation uri scheme is ec2 + final NicTO[] nics = vmSpec.getNics(); + for (final NicTO nic : nics) { + if (nic.isSecurityGroupEnabled() || nic.getIsolationUri() != null && nic.getIsolationUri().getScheme().equalsIgnoreCase(IsolationType.Ec2.toString())) { + final List nicSecIps = nic.getNicSecIps(); + String secIpsStr; + final StringBuilder sb = new StringBuilder(); + if (nicSecIps != null) { + for (final String ip : nicSecIps) { + sb.append(ip).append(":"); + } + secIpsStr = sb.toString(); + } else { + secIpsStr = "0:"; + } + result = citrixResourceBase.callHostPlugin(conn, "vmops", "default_network_rules", "vmName", vmName, "vmIP", nic.getIp(), "vmMAC", nic.getMac(), + "vmID", Long.toString(vmSpec.getId()), "secIps", secIpsStr); + + if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { + s_logger.warn("Failed to program default network rules for " + vmName + " on nic with ip:" + nic.getIp() + " mac:" + nic.getMac()); + } else { + s_logger.info("Programmed default network rules for " + vmName + " on nic with ip:" + nic.getIp() + " mac:" + nic.getMac()); + } + } + } + } + } + + state = VmPowerState.RUNNING; + + final StartAnswer startAnswer = new StartAnswer(command); + + startAnswer.setIqnToPath(iqnToPath); + + return startAnswer; + } catch (final Exception e) { + s_logger.warn("Catch Exception: " + e.getClass().toString() + " due to " + e.toString(), e); + final String msg = citrixResourceBase.handleVmStartFailure(conn, vmName, vm, "", e); + + final StartAnswer startAnswer = new StartAnswer(command, msg); + + startAnswer.setIqnToPath(iqnToPath); + + return startAnswer; + } finally { + if (state != VmPowerState.HALTED) { + s_logger.debug("2. The VM " + vmName + " is in " + state + " state."); + } else { + s_logger.debug("The VM is in stopped state, detected problem during startup : " + vmName); + } + } + } +} \ No newline at end of file diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapperTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapperTest.java index 0ba9d1a1f3b..0ffa7f4f92e 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapperTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapperTest.java @@ -3,6 +3,7 @@ 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.junit.Assert.fail; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -13,6 +14,7 @@ import java.util.Hashtable; import java.util.Map; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.xmlrpc.XmlRpcException; import org.apache.xmlrpc.client.XmlRpcClient; import org.junit.Test; import org.junit.runner.RunWith; @@ -26,6 +28,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; import com.cloud.agent.api.AttachVolumeCommand; import com.cloud.agent.api.CheckHealthCommand; +import com.cloud.agent.api.CheckOnHostCommand; import com.cloud.agent.api.CheckVirtualMachineCommand; import com.cloud.agent.api.Command; import com.cloud.agent.api.CreateStoragePoolCommand; @@ -37,7 +40,9 @@ import com.cloud.agent.api.GetVmStatsCommand; import com.cloud.agent.api.GetVncPortCommand; import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.MigrateCommand; +import com.cloud.agent.api.ModifySshKeysCommand; import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.OvsSetTagAndFlowCommand; import com.cloud.agent.api.PingTestCommand; import com.cloud.agent.api.PrepareForMigrationCommand; import com.cloud.agent.api.ReadyCommand; @@ -45,6 +50,7 @@ import com.cloud.agent.api.RebootAnswer; import com.cloud.agent.api.RebootCommand; import com.cloud.agent.api.RebootRouterCommand; import com.cloud.agent.api.SetupCommand; +import com.cloud.agent.api.StartCommand; import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.UpgradeSnapshotCommand; import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; @@ -67,6 +73,9 @@ import com.cloud.vm.DiskProfile; import com.xensource.xenapi.Connection; import com.xensource.xenapi.Host; import com.xensource.xenapi.Marshalling; +import com.xensource.xenapi.Network; +import com.xensource.xenapi.Types.BadServerResponse; +import com.xensource.xenapi.Types.XenAPIException; @RunWith(PowerMockRunner.class) @PrepareForTest({Connection.class, Host.Record.class}) @@ -189,36 +198,36 @@ public class CitrixRequestWrapperTest { @Test public void testGetVmDiskStatsCommand() { - final GetVmDiskStatsCommand statsCommand = new GetVmDiskStatsCommand(new ArrayList(), null, null); + final GetVmDiskStatsCommand diskStatsCommand = new GetVmDiskStatsCommand(new ArrayList(), null, null); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); - final Answer answer = wrapper.execute(statsCommand, citrixResourceBase); + final Answer answer = wrapper.execute(diskStatsCommand, citrixResourceBase); assertTrue(answer.getResult()); } @Test public void testCheckHealthCommand() { - final CheckHealthCommand statsCommand = new CheckHealthCommand(); + final CheckHealthCommand checkHealthCommand = new CheckHealthCommand(); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); - final Answer answer = wrapper.execute(statsCommand, citrixResourceBase); + final Answer answer = wrapper.execute(checkHealthCommand, citrixResourceBase); assertFalse(answer.getResult()); } @Test public void testStopCommandCommand() { - final StopCommand statsCommand = new StopCommand("Test", false, false); + final StopCommand stopCommand = new StopCommand("Test", false, false); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); - final Answer answer = wrapper.execute(statsCommand, citrixResourceBase); + final Answer answer = wrapper.execute(stopCommand, citrixResourceBase); assertFalse(answer.getResult()); } @@ -300,14 +309,14 @@ public class CitrixRequestWrapperTest { final StoragePoolVO poolVO = Mockito.mock(StoragePoolVO.class); final XsHost xsHost = Mockito.mock(XsHost.class); - final CreateStoragePoolCommand destroyCommand = new CreateStoragePoolCommand(false, poolVO); + final CreateStoragePoolCommand createStorageCommand = new CreateStoragePoolCommand(false, poolVO); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); when(citrixResourceBase.getHost()).thenReturn(xsHost); - final Answer answer = wrapper.execute(destroyCommand, citrixResourceBase); + final Answer answer = wrapper.execute(createStorageCommand, citrixResourceBase); verify(citrixResourceBase, times(1)).getConnection(); assertFalse(answer.getResult()); @@ -318,14 +327,14 @@ public class CitrixRequestWrapperTest { final StoragePoolVO poolVO = Mockito.mock(StoragePoolVO.class); final XsHost xsHost = Mockito.mock(XsHost.class); - final ModifyStoragePoolCommand destroyCommand = new ModifyStoragePoolCommand(false, poolVO); + final ModifyStoragePoolCommand modifyStorageCommand = new ModifyStoragePoolCommand(false, poolVO); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); when(citrixResourceBase.getHost()).thenReturn(xsHost); - final Answer answer = wrapper.execute(destroyCommand, citrixResourceBase); + final Answer answer = wrapper.execute(modifyStorageCommand, citrixResourceBase); verify(citrixResourceBase, times(1)).getConnection(); assertFalse(answer.getResult()); @@ -336,14 +345,14 @@ public class CitrixRequestWrapperTest { final StoragePoolVO poolVO = Mockito.mock(StoragePoolVO.class); final XsHost xsHost = Mockito.mock(XsHost.class); - final DeleteStoragePoolCommand destroyCommand = new DeleteStoragePoolCommand(poolVO); + final DeleteStoragePoolCommand deleteStorageCommand = new DeleteStoragePoolCommand(poolVO); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); when(citrixResourceBase.getHost()).thenReturn(xsHost); - final Answer answer = wrapper.execute(destroyCommand, citrixResourceBase); + final Answer answer = wrapper.execute(deleteStorageCommand, citrixResourceBase); verify(citrixResourceBase, times(1)).getConnection(); assertTrue(answer.getResult()); @@ -366,12 +375,12 @@ public class CitrixRequestWrapperTest { @Test public void testAttachVolumeCommand() { - final AttachVolumeCommand destroyCommand = new AttachVolumeCommand(false, true, "Test", StoragePoolType.LVM, "/", "DATA", 100l, 1l, "123"); + final AttachVolumeCommand attachCommand = new AttachVolumeCommand(false, true, "Test", StoragePoolType.LVM, "/", "DATA", 100l, 1l, "123"); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); - final Answer answer = wrapper.execute(destroyCommand, citrixResourceBase); + final Answer answer = wrapper.execute(attachCommand, citrixResourceBase); verify(citrixResourceBase, times(1)).getConnection(); assertFalse(answer.getResult()); @@ -379,12 +388,12 @@ public class CitrixRequestWrapperTest { @Test public void testAttachIsoCommand() { - final AttachIsoCommand destroyCommand = new AttachIsoCommand("Test", "/", true); + final AttachIsoCommand attachCommand = new AttachIsoCommand("Test", "/", true); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); - final Answer answer = wrapper.execute(destroyCommand, citrixResourceBase); + final Answer answer = wrapper.execute(attachCommand, citrixResourceBase); verify(citrixResourceBase, times(1)).getConnection(); assertFalse(answer.getResult()); @@ -394,12 +403,12 @@ public class CitrixRequestWrapperTest { public void testUpgradeSnapshotCommand() { final StoragePoolVO poolVO = Mockito.mock(StoragePoolVO.class); - final UpgradeSnapshotCommand destroyCommand = new UpgradeSnapshotCommand(poolVO, "http", 1l, 1l, 1l, 1l, 1l, "/", "58c5778b-7dd1-47cc-a7b5-f768541bf278", "Test", "2.1"); + final UpgradeSnapshotCommand upgradeSnapshotCommand = new UpgradeSnapshotCommand(poolVO, "http", 1l, 1l, 1l, 1l, 1l, "/", "58c5778b-7dd1-47cc-a7b5-f768541bf278", "Test", "2.1"); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); - final Answer answer = wrapper.execute(destroyCommand, citrixResourceBase); + final Answer answer = wrapper.execute(upgradeSnapshotCommand, citrixResourceBase); verify(citrixResourceBase, times(1)).getConnection(); assertTrue(answer.getResult()); @@ -409,12 +418,12 @@ public class CitrixRequestWrapperTest { public void testUpgradeSnapshotCommandNo21() { final StoragePoolVO poolVO = Mockito.mock(StoragePoolVO.class); - final UpgradeSnapshotCommand destroyCommand = new UpgradeSnapshotCommand(poolVO, "http", 1l, 1l, 1l, 1l, 1l, "/", "58c5778b-7dd1-47cc-a7b5-f768541bf278", "Test", "3.1"); + final UpgradeSnapshotCommand upgradeSnapshotCommand = new UpgradeSnapshotCommand(poolVO, "http", 1l, 1l, 1l, 1l, 1l, "/", "58c5778b-7dd1-47cc-a7b5-f768541bf278", "Test", "3.1"); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); - final Answer answer = wrapper.execute(destroyCommand, citrixResourceBase); + final Answer answer = wrapper.execute(upgradeSnapshotCommand, citrixResourceBase); verify(citrixResourceBase, times(0)).getConnection(); assertTrue(answer.getResult()); @@ -458,12 +467,12 @@ public class CitrixRequestWrapperTest { @Test public void testGetVncPortCommand() { - final GetVncPortCommand storageDownloadCommand = new GetVncPortCommand(1l, "Test"); + final GetVncPortCommand vncPortCommand = new GetVncPortCommand(1l, "Test"); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); - final Answer answer = wrapper.execute(storageDownloadCommand, citrixResourceBase); + final Answer answer = wrapper.execute(vncPortCommand, citrixResourceBase); verify(citrixResourceBase, times(1)).getConnection(); assertFalse(answer.getResult()); @@ -474,14 +483,14 @@ public class CitrixRequestWrapperTest { final XsHost xsHost = Mockito.mock(XsHost.class); final HostEnvironment env = Mockito.mock(HostEnvironment.class); - final SetupCommand storageDownloadCommand = new SetupCommand(env); + final SetupCommand setupCommand = new SetupCommand(env); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); when(citrixResourceBase.getHost()).thenReturn(xsHost); - final Answer answer = wrapper.execute(storageDownloadCommand, citrixResourceBase); + final Answer answer = wrapper.execute(setupCommand, citrixResourceBase); verify(citrixResourceBase, times(1)).getConnection(); assertFalse(answer.getResult()); @@ -500,7 +509,7 @@ public class CitrixRequestWrapperTest { // final Host.Record hr = PowerMockito.mock(Host.Record.class); // final Host host = PowerMockito.mock(Host.class); - final MaintainCommand storageDownloadCommand = new MaintainCommand(); + final MaintainCommand maintainCommand = new MaintainCommand(); final Map map = new Hashtable(); map.put("Value", "Xen"); @@ -551,23 +560,107 @@ public class CitrixRequestWrapperTest { // fail(e.getMessage()); // } - final Answer answer = wrapper.execute(storageDownloadCommand, citrixResourceBase); + final Answer answer = wrapper.execute(maintainCommand, citrixResourceBase); assertFalse(answer.getResult()); } @Test public void testPingTestCommandHostIp() { - final PingTestCommand storageDownloadCommand = new PingTestCommand("127.0.0.1"); + final PingTestCommand pingTestCommand = new PingTestCommand("127.0.0.1"); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); - final Answer answer = wrapper.execute(storageDownloadCommand, citrixResourceBase); + final Answer answer = wrapper.execute(pingTestCommand, citrixResourceBase); verify(citrixResourceBase, times(1)).getConnection(); assertFalse(answer.getResult()); } + + @Test + public void testPingTestCommandRouterPvtIps() { + final PingTestCommand pingTestCommand = new PingTestCommand("127.0.0.1", "192.168.0.1"); + + final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); + assertNotNull(wrapper); + + final Answer answer = wrapper.execute(pingTestCommand, citrixResourceBase); + verify(citrixResourceBase, times(1)).getConnection(); + + assertFalse(answer.getResult()); + } + + @Test + public void testCheckOnHostCommand() { + final com.cloud.host.Host host = Mockito.mock(com.cloud.host.Host.class); + final CheckOnHostCommand onHostCommand = new CheckOnHostCommand(host); + + final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); + assertNotNull(wrapper); + + final Answer answer = wrapper.execute(onHostCommand, citrixResourceBase); + + assertFalse(answer.getResult()); + } + + @Test + public void testModifySshKeysCommand() { + final ModifySshKeysCommand sshKeysCommand = new ModifySshKeysCommand("", ""); + + final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); + assertNotNull(wrapper); + + final Answer answer = wrapper.execute(sshKeysCommand, citrixResourceBase); + + assertTrue(answer.getResult()); + } + + @Test + public void testStartCommand() { + final VirtualMachineTO vm = Mockito.mock(VirtualMachineTO.class); + final com.cloud.host.Host host = Mockito.mock(com.cloud.host.Host.class); + + final StartCommand startCommand = new StartCommand(vm, host, false); + + final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); + assertNotNull(wrapper); + + final Answer answer = wrapper.execute(startCommand, citrixResourceBase); + verify(citrixResourceBase, times(1)).getConnection(); + + assertFalse(answer.getResult()); + } + + @Test + public void testOvsSetTagAndFlowCommand() { + final Network network = Mockito.mock(Network.class); + final Connection conn = Mockito.mock(Connection.class); + + final OvsSetTagAndFlowCommand tagAndFlowCommand = new OvsSetTagAndFlowCommand("Test", "tag", "vlan://1", "123", 1l); + + final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); + assertNotNull(wrapper); + + when(citrixResourceBase.getConnection()).thenReturn(conn); + when(citrixResourceBase.setupvSwitchNetwork(conn)).thenReturn(network); + try { + when(network.getBridge(conn)).thenReturn("br0"); + } catch (final BadServerResponse e) { + fail(e.getMessage()); + } catch (final XenAPIException e) { + fail(e.getMessage()); + } catch (final XmlRpcException e) { + fail(e.getMessage()); + } + + final Answer answer = wrapper.execute(tagAndFlowCommand, citrixResourceBase); + + verify(citrixResourceBase, times(1)).getConnection(); + verify(citrixResourceBase, times(1)).setupvSwitchNetwork(conn); + + assertFalse(answer.getResult()); + } } class NotAValidCommand extends Command {