mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Issue ===== Exception observed while creating CPVM in VMware Setup with DVS. Observed error "StartCommand failed due to Exception: com.vmware.vim25.AlreadyExists." This is due to concurrent attempts to create same dv portgroup on same dvSwitch by manager threads of CPVM and SSVM when both are started at same time. Fix === Synchronize api calls to create/update dvportgroup. Also maintaing local cache to avoid multiple fetch api calls to vCenter when multiple threads try to create same object. Signed-off-by: Sateesh Chodapuneedi <sateesh.chodapuneedi@accelerite.com>
173 lines
8.6 KiB
Java
173 lines
8.6 KiB
Java
// 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.vmware.mo;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import org.apache.log4j.Logger;
|
|
|
|
import com.vmware.vim25.DVPortgroupConfigSpec;
|
|
import com.vmware.vim25.DVSConfigInfo;
|
|
import com.vmware.vim25.ManagedObjectReference;
|
|
import com.vmware.vim25.TaskInfo;
|
|
import com.vmware.vim25.VMwareDVSConfigInfo;
|
|
import com.vmware.vim25.VMwareDVSConfigSpec;
|
|
import com.vmware.vim25.VMwareDVSPvlanMapEntry;
|
|
|
|
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
|
|
|
public class DistributedVirtualSwitchMO extends BaseMO {
|
|
@SuppressWarnings("unused")
|
|
private static final Logger s_logger = Logger.getLogger(DistributedVirtualSwitchMO.class);
|
|
private static ConcurrentHashMap<String, List<String>> s_dvPortGroupCacheMap = null;
|
|
|
|
public DistributedVirtualSwitchMO(VmwareContext context, ManagedObjectReference morDvs) {
|
|
super(context, morDvs);
|
|
s_dvPortGroupCacheMap = new ConcurrentHashMap<String, List<String>>();
|
|
}
|
|
|
|
public DistributedVirtualSwitchMO(VmwareContext context, String morType, String morValue) {
|
|
super(context, morType, morValue);
|
|
s_dvPortGroupCacheMap = new ConcurrentHashMap<String, List<String>>();
|
|
}
|
|
|
|
public void createDVPortGroup(DVPortgroupConfigSpec dvPortGroupSpec) throws Exception {
|
|
List<DVPortgroupConfigSpec> dvPortGroupSpecArray = new ArrayList<DVPortgroupConfigSpec>();
|
|
dvPortGroupSpecArray.add(dvPortGroupSpec);
|
|
boolean dvPortGroupExists = false;
|
|
String dvSwitchInstance = _mor.getValue();
|
|
String dvPortGroupName = dvPortGroupSpec.getName();
|
|
String uniquedvPortGroupPerDvs = dvSwitchInstance + dvPortGroupName;
|
|
List<String> dvPortGroupList = null;
|
|
synchronized (uniquedvPortGroupPerDvs.intern()) {
|
|
// Looking up local cache rather than firing another API call to see if dvPortGroup exists already.
|
|
if (s_dvPortGroupCacheMap.containsKey(dvSwitchInstance)) {
|
|
dvPortGroupList = s_dvPortGroupCacheMap.get(dvSwitchInstance);
|
|
if (dvPortGroupList != null && dvPortGroupList.contains(dvPortGroupName)) {
|
|
dvPortGroupExists = true;
|
|
}
|
|
}
|
|
if (!dvPortGroupExists) {
|
|
ManagedObjectReference task = _context.getService().addDVPortgroupTask(_mor, dvPortGroupSpecArray);
|
|
if (!_context.getVimClient().waitForTask(task)) {
|
|
throw new Exception("Failed to create dvPortGroup " + dvPortGroupSpec.getName());
|
|
} else {
|
|
if (s_dvPortGroupCacheMap.containsKey(dvSwitchInstance)) {
|
|
dvPortGroupList = s_dvPortGroupCacheMap.get(dvSwitchInstance);
|
|
if (dvPortGroupList == null) {
|
|
dvPortGroupList = new ArrayList<String>();
|
|
}
|
|
dvPortGroupList.add(dvPortGroupName); //does this update map?
|
|
} else {
|
|
dvPortGroupList = new ArrayList<String>();
|
|
dvPortGroupList.add(dvPortGroupName);
|
|
s_dvPortGroupCacheMap.put(dvSwitchInstance, dvPortGroupList);
|
|
}
|
|
}
|
|
if (s_logger.isTraceEnabled()) {
|
|
s_logger.trace("Created dvPortGroup. dvPortGroup cache is :" + s_dvPortGroupCacheMap);
|
|
}
|
|
} else if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Detected dvPortGroup [" + dvPortGroupName + "] already present. Not attempting to create again.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public void updateDvPortGroup(ManagedObjectReference dvPortGroupMor, DVPortgroupConfigSpec dvPortGroupSpec) throws Exception {
|
|
synchronized (dvPortGroupMor.getValue().intern()) {
|
|
ManagedObjectReference task = _context.getService().reconfigureDVPortgroupTask(dvPortGroupMor, dvPortGroupSpec);
|
|
if (!_context.getVimClient().waitForTask(task)) {
|
|
throw new Exception("Failed to update dvPortGroup " + dvPortGroupMor.getValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
public void updateVMWareDVSwitch(ManagedObjectReference dvSwitchMor, VMwareDVSConfigSpec dvsSpec) throws Exception {
|
|
_context.getService().reconfigureDvsTask(dvSwitchMor, dvsSpec);
|
|
}
|
|
|
|
public TaskInfo updateVMWareDVSwitchGetTask(ManagedObjectReference dvSwitchMor, VMwareDVSConfigSpec dvsSpec) throws Exception {
|
|
ManagedObjectReference task = _context.getService().reconfigureDvsTask(dvSwitchMor, dvsSpec);
|
|
TaskInfo info = (TaskInfo)(_context.getVimClient().getDynamicProperty(task, "info"));
|
|
_context.getVimClient().waitForTask(task);
|
|
return info;
|
|
}
|
|
|
|
public String getDVSConfigVersion(ManagedObjectReference dvSwitchMor) throws Exception {
|
|
assert (dvSwitchMor != null);
|
|
DVSConfigInfo dvsConfigInfo = (DVSConfigInfo)_context.getVimClient().getDynamicProperty(dvSwitchMor, "config");
|
|
return dvsConfigInfo.getConfigVersion();
|
|
}
|
|
|
|
public Map<Integer, HypervisorHostHelper.PvlanType> retrieveVlanPvlan(int vlanid, int secondaryvlanid, ManagedObjectReference dvSwitchMor) throws Exception {
|
|
assert (dvSwitchMor != null);
|
|
|
|
Map<Integer, HypervisorHostHelper.PvlanType> result = new HashMap<Integer, HypervisorHostHelper.PvlanType>();
|
|
|
|
VMwareDVSConfigInfo configinfo = (VMwareDVSConfigInfo)_context.getVimClient().getDynamicProperty(dvSwitchMor, "config");
|
|
List<VMwareDVSPvlanMapEntry> pvlanconfig = null;
|
|
pvlanconfig = configinfo.getPvlanConfig();
|
|
|
|
if (null == pvlanconfig || 0 == pvlanconfig.size()) {
|
|
return result;
|
|
}
|
|
// Iterate through the pvlanMapList and check if the specified vlan id and pvlan id exist. If they do, set the fields in result accordingly.
|
|
|
|
for (VMwareDVSPvlanMapEntry mapEntry : pvlanconfig) {
|
|
int entryVlanid = mapEntry.getPrimaryVlanId();
|
|
int entryPvlanid = mapEntry.getSecondaryVlanId();
|
|
if (entryVlanid == entryPvlanid) {
|
|
// promiscuous
|
|
if (vlanid == entryVlanid) {
|
|
// pvlan type will always be promiscuous in this case.
|
|
result.put(vlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType()));
|
|
} else if ((vlanid != secondaryvlanid) && secondaryvlanid == entryVlanid) {
|
|
result.put(secondaryvlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType()));
|
|
}
|
|
} else {
|
|
if (vlanid == entryVlanid) {
|
|
// vlan id in entry is promiscuous
|
|
result.put(vlanid, HypervisorHostHelper.PvlanType.promiscuous);
|
|
} else if (vlanid == entryPvlanid) {
|
|
result.put(vlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType()));
|
|
}
|
|
if ((vlanid != secondaryvlanid) && secondaryvlanid == entryVlanid) {
|
|
//promiscuous
|
|
result.put(secondaryvlanid, HypervisorHostHelper.PvlanType.promiscuous);
|
|
} else if (secondaryvlanid == entryPvlanid) {
|
|
result.put(secondaryvlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType()));
|
|
}
|
|
|
|
}
|
|
// If we already know that the vlanid is being used as a non primary vlan, it's futile to
|
|
// go over the entire list. Return.
|
|
if (result.containsKey(vlanid) && result.get(vlanid) != HypervisorHostHelper.PvlanType.promiscuous)
|
|
return result;
|
|
|
|
// If we've already found both vlanid and pvlanid, we have enough info to make a decision. Return.
|
|
if (result.containsKey(vlanid) && result.containsKey(secondaryvlanid))
|
|
return result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
}
|