From d6fe4d7eaef2de4dbf37f52219486751e125b3f8 Mon Sep 17 00:00:00 2001 From: Vijayendra Bhamidipati Date: Thu, 31 May 2012 13:39:42 -0700 Subject: [PATCH] CS-15173: Additional Cluster is allowed to add with the same VSM IPaddress as the previous cluster reviewed-by: Vijay Description: Restricting association of a Cisco Nexus VSM to a single cluster. --- .../com/cloud/api/commands/AddClusterCmd.java | 9 +++ .../com/cloud/resource/ResourceService.java | 3 +- .../cloud/resource/ResourceManagerImpl.java | 70 ++++++++++++------- 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/api/src/com/cloud/api/commands/AddClusterCmd.java b/api/src/com/cloud/api/commands/AddClusterCmd.java index 181da8661ce..5337b891ed4 100755 --- a/api/src/com/cloud/api/commands/AddClusterCmd.java +++ b/api/src/com/cloud/api/commands/AddClusterCmd.java @@ -26,8 +26,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; @Implementation(description="Adds a new cluster", responseObject=ClusterResponse.class) public class AddClusterCmd extends BaseCmd { @@ -161,6 +163,13 @@ public class AddClusterCmd extends BaseCmd { } catch (DiscoveryException ex) { s_logger.warn("Exception: ", ex); 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; } } } diff --git a/api/src/com/cloud/resource/ResourceService.java b/api/src/com/cloud/resource/ResourceService.java index 2821d050420..40d18cda59f 100755 --- a/api/src/com/cloud/resource/ResourceService.java +++ b/api/src/com/cloud/resource/ResourceService.java @@ -27,6 +27,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; @@ -57,7 +58,7 @@ public interface ResourceService { * @throws IllegalArgumentException * @throws DiscoveryException */ - List discoverCluster(AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException; + List 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 dfe609f0dbc..bb219999a5d 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 discoverCluster(AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException { + public List discoverCluster(AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException, ResourceInUseException { long dcId = cmd.getZoneId(); long podId = cmd.getPodId(); String clusterName = cmd.getClusterName(); @@ -417,6 +418,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(); @@ -434,33 +436,49 @@ 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; + + // If VSM already exists and is mapped to a cluster, fail this operation. + CiscoNexusVSMDeviceVO vsm = _vsmDao.getVSMbyIpaddress(vsmIp); + List clusterList = _clusterVSMDao.listByVSMId(vsm.getId()); + if(vsm != null && clusterList != null && !clusterList.isEmpty()) { + s_logger.error("Failed to add cluster: specified Nexus VSM is already associated with another cluster"); + 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; } - - 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()); + // 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;