Hi Team, Please find attached the ASF master git patch for Bug CS-15173 (http://bugs.cloudstack.org/browse/CS-15173 ). Also, pasting the contents of the patch below for quicker review.
Regards, Vijay >From 89753db2ef5411e81de6c28d57794d8acda87efd Mon Sep 17 00:00:00 2001 From: Vijayendra Bhamidipati <vijayendra.bhamidip...@citrix.com> Date: Mon, 18 Jun 2012 16:41:06 -0700 Subject: [PATCH] CS-15173: Additional Cluster is allowed to add with the same VSM IPaddress as the previous cluster Description: Restricting association of a Cisco Nexus VSM to a single cluster. --- api/src/com/cloud/api/commands/AddClusterCmd.java | 11 +++- api/src/com/cloud/resource/ResourceService.java | 3 +- .../com/cloud/resource/ResourceManagerImpl.java | 73 +++++++++++++------- .../hypervisor/vmware/mo/HypervisorHostHelper.java | 10 +++- 4 files changed, 68 insertions(+), 29 deletions(-) diff --git a/api/src/com/cloud/api/commands/AddClusterCmd.java b/api/src/com/cloud/api/commands/AddClusterCmd.java index 6688dee..39fa63d 100755 --- a/api/src/com/cloud/api/commands/AddClusterCmd.java +++ b/api/src/com/cloud/api/commands/AddClusterCmd.java @@ -31,8 +31,10 @@ import com.cloud.api.ServerApiException; import com.cloud.api.response.ClusterResponse; import com.cloud.api.response.ListResponse; import com.cloud.exception.DiscoveryException; +import com.cloud.exception.ResourceInUseException; import com.cloud.org.Cluster; import com.cloud.user.Account; +import com.cloud.utils.IdentityProxy; ^M @Implementation(description="Adds a new cluster", responseObject=ClusterResponse.class)^M public class AddClusterCmd extends BaseCmd {^M @@ -166,7 +168,14 @@ public class AddClusterCmd extends BaseCmd { this.setResponseObject(response);^M } catch (DiscoveryException ex) {^M s_logger.warn("Exception: ", ex);^M - throw new ServerApiException(BaseCmd.INTERNAL_ERROR, ex.getMessage());^M + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, ex.getMessage()); + } catch (ResourceInUseException ex) { + s_logger.warn("Exception: ", ex); + ServerApiException e = new ServerApiException(BaseCmd.INTERNAL_ERROR, ex.getMessage()); + for (IdentityProxy proxyObj : ex.getIdProxyList()) { + e.addProxyObject(proxyObj.getTableName(), proxyObj.getValue(), proxyObj.getidFieldName()); + } + throw e; }^M }^M } diff --git a/api/src/com/cloud/resource/ResourceService.java b/api/src/com/cloud/resource/ResourceService.java index d971a40..1065453 100755 --- a/api/src/com/cloud/resource/ResourceService.java +++ b/api/src/com/cloud/resource/ResourceService.java @@ -31,6 +31,7 @@ import com.cloud.api.commands.UpdateHostCmd; import com.cloud.api.commands.UpdateHostPasswordCmd; import com.cloud.exception.DiscoveryException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceInUseException; import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Cluster; @@ -61,7 +62,7 @@ public interface ResourceService { * @throws IllegalArgumentException * @throws DiscoveryException */ - List<? extends Cluster> discoverCluster(AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException; + List<? extends Cluster> discoverCluster(AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException, ResourceInUseException; boolean deleteCluster(DeleteClusterCmd cmd); diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 3380972..357dca3 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -79,6 +79,7 @@ import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.DiscoveryException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceInUseException; import com.cloud.ha.HighAvailabilityManager; import com.cloud.ha.HighAvailabilityManager.WorkType; import com.cloud.host.DetailVO; @@ -324,7 +325,7 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma @DB @Override - public List<? extends Cluster> discoverCluster(AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException { + public List<? extends Cluster> discoverCluster(AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException, ResourceInUseException { long dcId = cmd.getZoneId(); long podId = cmd.getPodId(); String clusterName = cmd.getClusterName(); @@ -433,6 +434,7 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma clusterId = cluster.getId(); result.add(cluster); + // Check if we're associating a Cisco Nexus VSM with a vmware cluster. if (hypervisorType == HypervisorType.VMware && Boolean.parseBoolean(_configDao.getValue(Config.VmwareUseNexusVSwitch.toString()))) { String vsmIp = cmd.getVSMIpaddress(); @@ -450,33 +452,52 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma _clusterDao.remove(clusterId); throw new CloudRuntimeException(msg); } - // persist credentials to database - CiscoNexusVSMDeviceVO vsm = new CiscoNexusVSMDeviceVO(vsmIp, vsmUser, vsmPassword); - Transaction txn = Transaction.currentTxn(); - try { - txn.start(); - vsm = _vsmDao.persist(vsm); - txn.commit(); - } catch (Exception e) { - txn.rollback(); - s_logger.error("Failed to persist Cisco Nexus 1000v VSM details to database. Exception: " + e.getMessage()); - // Removing the cluster record which was added already because the persistence of Nexus VSM credentials has failed. - _clusterDao.remove(clusterId); - throw new CloudRuntimeException(e.getMessage()); - } + Transaction txn; - ClusterVSMMapVO connectorObj = new ClusterVSMMapVO(clusterId, vsm.getId()); - txn = Transaction.currentTxn(); - try { - txn.start(); - _clusterVSMDao.persist(connectorObj); - txn.commit(); - } catch (Exception e) { - txn.rollback(); - s_logger.error("Failed to associate Cisco Nexus 1000v VSM with cluster: " + clusterName + ". Exception: " + e.getMessage()); - _clusterDao.remove(clusterId); - throw new CloudRuntimeException(e.getMessage()); + // If VSM already exists and is mapped to a cluster, fail this operation. + CiscoNexusVSMDeviceVO vsm = _vsmDao.getVSMbyIpaddress(vsmIp); + if(vsm != null) { + List<ClusterVSMMapVO> clusterList = _clusterVSMDao.listByVSMId(vsm.getId()); + if (clusterList != null && !clusterList.isEmpty()) { + s_logger.error("Failed to add cluster: specified Nexus VSM is already associated with another cluster"); + _clusterDao.remove(clusterId); + ResourceInUseException ex = new ResourceInUseException("Failed to add cluster: specified Nexus VSM is already associated with another cluster with specified Id"); + ex.addProxyObject("cluster", clusterList.get(0).getClusterId(), "clusterId"); + throw ex; + } + } + // persist credentials to database if the VSM entry is not already in the db. + if (_vsmDao.getVSMbyIpaddress(vsmIp) == null) { + vsm = new CiscoNexusVSMDeviceVO(vsmIp, vsmUser, vsmPassword); + txn = Transaction.currentTxn(); + try { + txn.start(); + vsm = _vsmDao.persist(vsm); + txn.commit(); + } catch (Exception e) { + txn.rollback(); + s_logger.error("Failed to persist Cisco Nexus 1000v VSM details to database. Exception: " + e.getMessage()); + // Removing the cluster record which was added already because the persistence of Nexus VSM credentials has failed. + _clusterDao.remove(clusterId); + throw new CloudRuntimeException(e.getMessage()); + } + } + // Create a mapping between the cluster and the vsm. + vsm = _vsmDao.getVSMbyIpaddress(vsmIp); + if (vsm != null) { + ClusterVSMMapVO connectorObj = new ClusterVSMMapVO(clusterId, vsm.getId()); + txn = Transaction.currentTxn(); + try { + txn.start(); + _clusterVSMDao.persist(connectorObj); + txn.commit(); + } catch (Exception e) { + txn.rollback(); + s_logger.error("Failed to associate Cisco Nexus 1000v VSM with cluster: " + clusterName + ". Exception: " + e.getMessage()); + _clusterDao.remove(clusterId); + throw new CloudRuntimeException(e.getMessage()); + } } } else { String msg; 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 4437519..cfbdc56 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -194,6 +194,7 @@ public class HypervisorHostHelper { netconfClient.disconnect(); s_logger.debug("Disconnected Nexus 1000v session."); } + throw new CloudRuntimeException(msg); } List<Pair<OperationType, String>> params = new ArrayList<Pair<OperationType, String>>(); @@ -212,6 +213,7 @@ public class HypervisorHostHelper { netconfClient.disconnect(); s_logger.debug("Disconnected Nexus 1000v session."); } + throw new CloudRuntimeException(msg); } } @@ -230,6 +232,7 @@ public class HypervisorHostHelper { netconfClient.disconnect(); s_logger.debug("Disconnected Nexus 1000v session."); } + throw new CloudRuntimeException(msg); } try { @@ -241,7 +244,8 @@ public class HypervisorHostHelper { catch(CloudRuntimeException e) { msg = "Failed to associate policy map " + policyName + " with port profile " + networkName + ". Exception: " + e.toString(); - s_logger.error(msg); + s_logger.error(msg); + throw new CloudRuntimeException(msg); } finally { if (netconfClient != null) { netconfClient.disconnect(); @@ -301,6 +305,7 @@ public class HypervisorHostHelper { netconfClient.disconnect(); s_logger.debug("Disconnected Nexus 1000v session."); } + throw new CloudRuntimeException(msg); } try { @@ -315,6 +320,7 @@ public class HypervisorHostHelper { netconfClient.disconnect(); s_logger.debug("Disconnected Nexus 1000v session."); } + throw new CloudRuntimeException(msg); } } } @@ -352,6 +358,7 @@ public class HypervisorHostHelper { netconfClient.disconnect(); s_logger.debug("Disconnected Nexus 1000v session."); } + throw new CloudRuntimeException(msg); } try { @@ -364,6 +371,7 @@ public class HypervisorHostHelper { netconfClient.disconnect(); s_logger.debug("Disconnected Nexus 1000v session."); } + throw new CloudRuntimeException(msg); } }