From 392bbcc737ec8622d4101df783bc947266ff3dfe Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Wed, 3 Jul 2013 14:58:44 +0200 Subject: [PATCH] CLOUDSTACK-728 Rewrite support for lswitch connected nics on both standard and distributed switches. Fix the name of the interface id in extra config, so the nic is found up using the nic uuid instead of the vm id. getVlanInfo should return null when the nic is plugged on a Lswitch network. On a distributed portgroup all vms should be connected to a single portgroup and set a specific vlan on the port. On a standard switch each nic should have its own portgroup with a dedicated vlan (not related to CS vlans) --- .../vmware/manager/VmwareManagerImpl.java | 2 +- .../vmware/resource/VmwareResource.java | 157 +++++++++++++++++- .../vmware/mo/HypervisorHostHelper.java | 69 ++++++-- .../vmware/mo/VirtualMachineMO.java | 76 +++++---- 4 files changed, 251 insertions(+), 53 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index c872e93e1af..9eb6d34590d 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -352,7 +352,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw } s_logger.info("Preparing network on host " + hostMo.getContext().toString() + " for " + privateTrafficLabel); //The management network is probably always going to be a physical network with vlans, so assume BroadcastDomainType VLAN - HypervisorHostHelper.prepareNetwork(vSwitchName, "cloud.private", hostMo, vlanId, null, null, 180000, false, BroadcastDomainType.Vlan); + HypervisorHostHelper.prepareNetwork(vSwitchName, "cloud.private", hostMo, vlanId, null, null, 180000, false, BroadcastDomainType.Vlan, null); } @Override diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 1f54f9cdbbc..57f312186e9 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -265,6 +265,7 @@ import com.cloud.hypervisor.vmware.mo.CustomFieldsManagerMO; import com.cloud.hypervisor.vmware.mo.DatacenterMO; import com.cloud.hypervisor.vmware.mo.DatastoreMO; import com.cloud.hypervisor.vmware.mo.DiskControllerType; +import com.cloud.hypervisor.vmware.mo.DistributedVirtualSwitchMO; import com.cloud.hypervisor.vmware.mo.FeatureKeyConstants; import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO; import com.cloud.hypervisor.vmware.mo.HostFirewallSystemMO; @@ -319,6 +320,70 @@ import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachineName; import com.cloud.vm.VmDetailConstants; +import com.google.gson.Gson; +import com.vmware.vim25.AboutInfo; +import com.vmware.vim25.BoolPolicy; +import com.vmware.vim25.ClusterDasConfigInfo; +import com.vmware.vim25.ComputeResourceSummary; +import com.vmware.vim25.DVPortConfigInfo; +import com.vmware.vim25.DVPortConfigSpec; +import com.vmware.vim25.DVPortSetting; +import com.vmware.vim25.DatastoreSummary; +import com.vmware.vim25.DistributedVirtualPort; +import com.vmware.vim25.DistributedVirtualSwitchPortConnection; +import com.vmware.vim25.DistributedVirtualSwitchPortCriteria; +import com.vmware.vim25.DynamicProperty; +import com.vmware.vim25.GuestInfo; +import com.vmware.vim25.GuestOsDescriptor; +import com.vmware.vim25.HostCapability; +import com.vmware.vim25.HostFirewallInfo; +import com.vmware.vim25.HostFirewallRuleset; +import com.vmware.vim25.HostHostBusAdapter; +import com.vmware.vim25.HostInternetScsiTargetTransport; +import com.vmware.vim25.HostScsiTopology; +import com.vmware.vim25.HostInternetScsiHba; +import com.vmware.vim25.HostInternetScsiHbaAuthenticationProperties; +import com.vmware.vim25.HostInternetScsiHbaStaticTarget; +import com.vmware.vim25.HostScsiDisk; +import com.vmware.vim25.HostScsiTopologyInterface; +import com.vmware.vim25.HostScsiTopologyLun; +import com.vmware.vim25.HostScsiTopologyTarget; +import com.vmware.vim25.ManagedObjectReference; +import com.vmware.vim25.ObjectContent; +import com.vmware.vim25.OptionValue; +import com.vmware.vim25.PerfCounterInfo; +import com.vmware.vim25.PerfEntityMetric; +import com.vmware.vim25.PerfEntityMetricBase; +import com.vmware.vim25.PerfMetricId; +import com.vmware.vim25.PerfMetricIntSeries; +import com.vmware.vim25.PerfMetricSeries; +import com.vmware.vim25.PerfQuerySpec; +import com.vmware.vim25.PerfSampleInfo; +import com.vmware.vim25.RuntimeFaultFaultMsg; +import com.vmware.vim25.ToolsUnavailableFaultMsg; +import com.vmware.vim25.VMwareDVSPortSetting; +import com.vmware.vim25.VimPortType; +import com.vmware.vim25.VirtualDevice; +import com.vmware.vim25.VirtualDeviceBackingInfo; +import com.vmware.vim25.VirtualDeviceConfigSpec; +import com.vmware.vim25.VirtualDeviceConfigSpecOperation; +import com.vmware.vim25.VirtualDisk; +import com.vmware.vim25.VirtualEthernetCard; +import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo; +import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo; +import com.vmware.vim25.VirtualLsiLogicController; +import com.vmware.vim25.VirtualMachineConfigOption; +import com.vmware.vim25.VirtualMachineConfigSpec; +import com.vmware.vim25.VirtualMachineFileInfo; +import com.vmware.vim25.VirtualMachineGuestOsIdentifier; +import com.vmware.vim25.VirtualMachinePowerState; +import com.vmware.vim25.VirtualMachineRelocateSpec; +import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator; +import com.vmware.vim25.VirtualMachineRuntimeInfo; +import com.vmware.vim25.VirtualSCSISharing; +import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; + + public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService { private static final Logger s_logger = Logger.getLogger(VmwareResource.class); @@ -1803,7 +1868,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa */ if (VirtualSwitchType.StandardVirtualSwitch == vSwitchType) { networkInfo = HypervisorHostHelper.prepareNetwork(_publicTrafficInfo.getVirtualSwitchName(), "cloud.public", - vmMo.getRunningHost(), vlanId, null, null, _ops_timeout, true, BroadcastDomainType.Vlan); + vmMo.getRunningHost(), vlanId, null, null, _ops_timeout, true, BroadcastDomainType.Vlan, null); } else { networkInfo = HypervisorHostHelper.prepareNetwork(_publicTrafficInfo.getVirtualSwitchName(), "cloud.public", vmMo.getRunningHost(), vlanId, null, null, null, _ops_timeout, vSwitchType, _portsPerDvPortGroup, null, false, BroadcastDomainType.Vlan); @@ -2807,13 +2872,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa extraOptions.add(newVal); /** - * Extra Config : nvp.iface-id = uuid + * Extra Config : nvp.iface-id. = uuid * - Required for Nicira NVP integration */ int nicNum = 0; for (NicTO nicTo : sortNicsByDeviceId(nics)) { newVal = new OptionValue(); - newVal.setKey("nvp.iface-id" + nicNum); + newVal.setKey("nvp.iface-id." + nicNum); newVal.setValue(nicTo.getUuid()); extraOptions.add(newVal); nicNum++; @@ -2837,9 +2902,86 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK, String.valueOf(nicMask)); + int nicIndex = 0; + for (NicTO nicTo : sortNicsByDeviceId(nics)) { + s_logger.debug("Checking for port configuration on NIC device : " + nicTo.toString()); + if (nicTo.getBroadcastType() == BroadcastDomainType.Lswitch) { + // We need to create a port with a unique vlan and pass the key to the nic device + s_logger.debug("Nic " + nicTo.toString() + " needs to be configured for NVP"); + VirtualDevice nicVirtualDevice = vmMo.getNicDeviceByIndex(nicIndex); + if (nicVirtualDevice == null) { + throw new Exception("Failed to find a VirtualDevice for nic " + nicIndex); //FIXME Generic exceptions are bad + } + VirtualDeviceBackingInfo backing = nicVirtualDevice.getBacking(); + if (backing instanceof VirtualEthernetCardDistributedVirtualPortBackingInfo) { + VirtualEthernetCardDistributedVirtualPortBackingInfo portInfo = (VirtualEthernetCardDistributedVirtualPortBackingInfo) backing; + DistributedVirtualSwitchPortConnection port = portInfo.getPort(); + String portKey = port.getPortKey(); + String portGroupKey = port.getPortgroupKey(); + String dvSwitchUuid = port.getSwitchUuid(); + + s_logger.debug("NIC " + nicTo.toString() + " is connected to dvSwitch " + dvSwitchUuid + " pg " + portGroupKey + " port " + portKey); + + ManagedObjectReference dvSwitchManager = vmMo.getContext().getVimClient().getServiceContent().getDvSwitchManager(); + ManagedObjectReference dvSwitch = vmMo.getContext().getVimClient().getService().queryDvsByUuid(dvSwitchManager, dvSwitchUuid); + + DistributedVirtualSwitchPortCriteria criteria = new DistributedVirtualSwitchPortCriteria(); + criteria.setInside(true); + criteria.getPortgroupKey().add(portGroupKey); + criteria.getPortKey().add(portKey); + List dvPorts = vmMo.getContext().getVimClient().getService().fetchDVPorts(dvSwitch, criteria); + + if (dvPorts.isEmpty()) { + throw new Exception("Empty port list from dvSwitch for nic " + nicTo.toString()); + } else if (dvPorts.size() > 1) { + throw new Exception("Expected only one port in the list from dvSwitch for nic " + nicTo.toString()); + } + + DistributedVirtualPort dvPort = dvPorts.get(0); + DVPortConfigInfo dvPortConfigInfo = dvPort.getConfig(); + VMwareDVSPortSetting settings = (VMwareDVSPortSetting) dvPortConfigInfo.getSetting(); + + VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec) settings.getVlan(); + BoolPolicy blocked = settings.getBlocked(); + if (blocked.isValue() == Boolean.TRUE) { + s_logger.debug("Port is blocked, we need to set a vlanid and unblock"); + DVPortConfigSpec dvPortConfigSpec = new DVPortConfigSpec(); + VMwareDVSPortSetting edittedSettings = new VMwareDVSPortSetting(); + // Unblock + blocked.setValue(Boolean.FALSE); + blocked.setInherited(Boolean.FALSE); + edittedSettings.setBlocked(blocked); + // Set vlan + vlanId.setVlanId(100); //FIXME should be a determined based on usage + vlanId.setInherited(false); + edittedSettings.setVlan(vlanId); + + dvPortConfigSpec.setSetting(edittedSettings); + dvPortConfigSpec.setOperation("edit"); + dvPortConfigSpec.setKey(portKey); + List dvPortConfigSpecs = new ArrayList(); + dvPortConfigSpecs.add(dvPortConfigSpec); + ManagedObjectReference task = vmMo.getContext().getVimClient().getService().reconfigureDVPortTask(dvSwitch, dvPortConfigSpecs); + if (!vmMo.getContext().getVimClient().waitForTask(task)) { + s_logger.error("Failed to configure the dvSwitch port for nic " + nicTo.toString()); + } + } else { + s_logger.trace("Port already configured and set to vlan " + vlanId.getVlanId()); + } + } + else { + s_logger.error("nic device backing is of type " + backing.getClass().getName()); + throw new Exception("Incompatible backing for a VirtualDevice for nic " + nicIndex); //FIXME Generic exceptions are bad + } + } + nicIndex++; + } + if (!vmMo.powerOn()) { throw new Exception("Failed to start VM. vmName: " + vmName); } + + state = State.Running; return new StartAnswer(cmd); @@ -2971,7 +3113,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (nicTo.getBroadcastType() == BroadcastDomainType.Native) { return defaultVlan; } - if (nicTo.getBroadcastType() == BroadcastDomainType.Vlan || nicTo.getBroadcastType() == BroadcastDomainType.Pvlan) { + else if (nicTo.getBroadcastType() == BroadcastDomainType.Vlan || nicTo.getBroadcastType() == BroadcastDomainType.Pvlan) { if (nicTo.getBroadcastUri() != null) { if (nicTo.getBroadcastType() == BroadcastDomainType.Vlan) // For vlan, the broadcast uri is of the form vlan:// @@ -2983,6 +3125,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa s_logger.warn("BroadcastType is not claimed as VLAN or PVLAN, but without vlan info in broadcast URI. Use vlan info from labeling: " + defaultVlan); return defaultVlan; } + } else if (nicTo.getBroadcastType() == BroadcastDomainType.Lswitch) { + // We don't need to set any VLAN id for an NVP logical switch + return null; } s_logger.warn("Unrecognized broadcast type in VmwareResource, type: " + nicTo.getBroadcastType().toString() + ". Use vlan info from labeling: " + defaultVlan); @@ -3015,7 +3160,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (VirtualSwitchType.StandardVirtualSwitch == switchType) { networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, hostMo, getVlanInfo(nicTo, switchName.second()), nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, - !namePrefix.startsWith("cloud.private"), nicTo.getBroadcastType()); + !namePrefix.startsWith("cloud.private"), nicTo.getBroadcastType(), nicTo.getUuid()); } else { String vlanId = getVlanInfo(nicTo, switchName.second()); @@ -3029,7 +3174,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa svlanId = getPvlanInfo(nicTo); } networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, hostMo, vlanId, svlanId, - nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, switchType, + nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, switchType, _portsPerDvPortGroup, nicTo.getGateway(), configureVServiceInNexus, nicTo.getBroadcastType()); } diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index 9df7bc3af60..dc1486a2ee5 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -52,6 +52,7 @@ import com.vmware.vim25.DVSTrafficShapingPolicy; import com.vmware.vim25.DynamicProperty; import com.vmware.vim25.HostNetworkSecurityPolicy; import com.vmware.vim25.HostNetworkTrafficShapingPolicy; +import com.vmware.vim25.HostPortGroup; import com.vmware.vim25.HostPortGroupSpec; import com.vmware.vim25.HostVirtualSwitch; import com.vmware.vim25.HttpNfcLeaseDeviceUrl; @@ -467,8 +468,12 @@ public class HypervisorHostHelper { throw new InvalidParameterException("Nexus Distributed Virtualswitch is not supported with BroadcastDomainType " + broadcastDomainType); } - // Fixed name for the port-group on the vApp vswitch - networkName = "br-int"; + /** + * Nicira NVP requires all vms to be connected to a single port-group. + * A unique vlan needs to be set per port. This vlan is specific to + * this implementation and has no reference to other vlans in CS + */ + networkName = "br-int"; // FIXME Should be set via a configuration item in CS // No doubt about this, depending on vid=null to avoid lots of code below vid = null; } else { @@ -508,8 +513,7 @@ public class HypervisorHostHelper { if (broadcastDomainType == BroadcastDomainType.Lswitch) { if (!dataCenterMo.hasDvPortGroup(networkName)) { - // It'a bad thing if the integration bridge port-group does not exist - throw new InvalidParameterException("Unable to find port-group " + networkName + " on dvSwitch " + dvSwitchName); + throw new InvalidParameterException("NVP integration port-group " + networkName + " does not exist on the DVS " + dvSwitchName); } bWaitPortGroupReady = false; } else { @@ -856,7 +860,7 @@ public class HypervisorHostHelper { public static Pair prepareNetwork(String vSwitchName, String namePrefix, HostMO hostMo, String vlanId, Integer networkRateMbps, Integer networkRateMulticastMbps, - long timeOutMs, boolean syncPeerHosts, BroadcastDomainType broadcastDomainType) throws Exception { + long timeOutMs, boolean syncPeerHosts, BroadcastDomainType broadcastDomainType, String nicUuid) throws Exception { HostVirtualSwitch vSwitch; if (vSwitchName == null) { @@ -893,8 +897,11 @@ public class HypervisorHostHelper { } if (broadcastDomainType == BroadcastDomainType.Lswitch) { - // Fixed name for the port-group on the vApp vswitch - networkName = "br-int"; + /** + * Nicira NVP requires each vm to have its own port-group with a dedicated + * vlan. We'll set the name of the pg to the uuid of the nic. + */ + networkName = nicUuid; // No doubt about this, depending on vid=null to avoid lots of code below vid = null; } else { @@ -933,10 +940,12 @@ public class HypervisorHostHelper { boolean bWaitPortGroupReady = false; if (broadcastDomainType == BroadcastDomainType.Lswitch) { if (!hostMo.hasPortGroup(vSwitch, networkName)) { - // It'a bad thing if the integration bridge port-group does not exist - throw new InvalidParameterException("Unable to find port-group " + networkName + " on dvSwitch " + vSwitchName); + createNvpPortGroup(hostMo, vSwitch, networkName, shapingPolicy); + + bWaitPortGroupReady = true; + } else { + bWaitPortGroupReady = false; } - bWaitPortGroupReady = false; } else { if (!hostMo.hasPortGroup(vSwitch, networkName)) { hostMo.createPortGroup(vSwitch, networkName, vid, secPolicy, shapingPolicy); @@ -982,7 +991,7 @@ public class HypervisorHostHelper { try { if(s_logger.isDebugEnabled()) s_logger.debug("Prepare network on other host, vlan: " + vlanId + ", host: " + otherHostMo.getHostName()); - prepareNetwork(vSwitchName, namePrefix, otherHostMo, vlanId, networkRateMbps, networkRateMulticastMbps, timeOutMs, false, broadcastDomainType); + prepareNetwork(vSwitchName, namePrefix, otherHostMo, vlanId, networkRateMbps, networkRateMulticastMbps, timeOutMs, false, broadcastDomainType, nicUuid); } catch(Exception e) { s_logger.warn("Unable to prepare network on other host, vlan: " + vlanId + ", host: " + otherHostMo.getHostName()); } @@ -1041,6 +1050,44 @@ public class HypervisorHostHelper { return true; } + + private static void createNvpPortGroup(HostMO hostMo, HostVirtualSwitch vSwitch, String networkName, HostNetworkTrafficShapingPolicy shapingPolicy) throws Exception { + /** + * No portgroup created yet for this nic + * We need to find an unused vlan and create the pg + * The vlan is limited to this vSwitch and the NVP vAPP, + * so no relation to the other vlans in use in CloudStack. + */ + String vSwitchName = vSwitch.getName(); + + // Find all vlanids that we have in use + List usedVlans = new ArrayList(); + for (HostPortGroup pg : hostMo.getHostNetworkInfo().getPortgroup()) { + HostPortGroupSpec hpgs = pg.getSpec(); + if (vSwitchName.equals(hpgs.getVswitchName())) + usedVlans.add(hpgs.getVlanId()); + } + + // Find the first free vlanid + int nvpVlanId = 0; + for (nvpVlanId = 1; nvpVlanId < 4095; nvpVlanId++) { + if (! usedVlans.contains(nvpVlanId)) { + break; + } + } + if (nvpVlanId == 4095) { + throw new InvalidParameterException("No free vlan numbers on " + vSwitchName + " to create a portgroup for nic " + networkName); + } + + // Strict security policy + HostNetworkSecurityPolicy secPolicy = new HostNetworkSecurityPolicy(); + secPolicy.setAllowPromiscuous(Boolean.FALSE); + secPolicy.setForgedTransmits(Boolean.FALSE); + secPolicy.setMacChanges(Boolean.FALSE); + + // Create a portgroup with the uuid of the nic and the vlanid found above + hostMo.createPortGroup(vSwitch, networkName, nvpVlanId, secPolicy, shapingPolicy); + } public static ManagedObjectReference waitForNetworkReady(HostMO hostMo, String networkName, long timeOutMs) throws Exception { diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index 5214f3da0df..e2dd789d23c 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -2048,47 +2048,53 @@ public class VirtualMachineMO extends BaseMO { return ++deviceNumber; } - public VirtualDevice[] getNicDevices() throws Exception { - List devices = (List)_context.getVimClient(). - getDynamicProperty(_mor, "config.hardware.device"); + private List getNicDevices(boolean sorted) throws Exception { + List devices = (List)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); - List nics = new ArrayList(); - if(devices != null) { - for(VirtualDevice device : devices) { - if(device instanceof VirtualEthernetCard) { - nics.add(device); + List nics = new ArrayList(); + if(devices != null) { + for(VirtualDevice device : devices) { + if(device instanceof VirtualEthernetCard) { + nics.add(device); + } } - } - } + } + + if (sorted) { + Collections.sort(nics, new Comparator() { + @Override + public int compare(VirtualDevice arg0, VirtualDevice arg1) { + int unitNumber0 = arg0.getUnitNumber() != null ? arg0.getUnitNumber().intValue() : -1; + int unitNumber1 = arg1.getUnitNumber() != null ? arg1.getUnitNumber().intValue() : -1; + if(unitNumber0 < unitNumber1) + return -1; + else if(unitNumber0 > unitNumber1) + return 1; + return 0; + } + }); + } + + return nics; + } - return nics.toArray(new VirtualDevice[0]); + public VirtualDevice[] getNicDevices() throws Exception { + return getNicDevices(false).toArray(new VirtualDevice[0]); + } + + public VirtualDevice getNicDeviceByIndex(int index) throws Exception { + List nics = getNicDevices(true); + try { + return nics.get(index); + } catch (IndexOutOfBoundsException e) { + // Not found + return null; + } } public Pair getNicDeviceIndex(String networkNamePrefix) throws Exception { - List devices = (List)_context.getVimClient(). - getDynamicProperty(_mor, "config.hardware.device"); - - List nics = new ArrayList(); - if(devices != null) { - for(VirtualDevice device : devices) { - if(device instanceof VirtualEthernetCard) { - nics.add(device); - } - } - } - - Collections.sort(nics, new Comparator() { - @Override - public int compare(VirtualDevice arg0, VirtualDevice arg1) { - int unitNumber0 = arg0.getUnitNumber() != null ? arg0.getUnitNumber().intValue() : -1; - int unitNumber1 = arg1.getUnitNumber() != null ? arg1.getUnitNumber().intValue() : -1; - if(unitNumber0 < unitNumber1) - return -1; - else if(unitNumber0 > unitNumber1) - return 1; - return 0; - } - }); + List nics = getNicDevices(true); int index = 0; String attachedNetworkSummary;