@Override public boolean removeVmwareDatacenter(RemoveVmwareDcCmd cmd) throws ResourceInUseException { Long zoneId = cmd.getZoneId(); // Validate zone validateZone(zoneId); // Zone validation to check if the zone already has resources. // Association of VMware DC to zone is not allowed if zone already has resources added. validateZoneWithResources(zoneId, "remove VMware datacenter to zone"); // Get DC associated with this zone VmwareDatacenterZoneMapVO vmwareDcZoneMap; VmwareDatacenterVO vmwareDatacenter; String vmwareDcName; long vmwareDcId; String vCenterHost; String userName; String password; DatacenterMO dcMo = null; Transaction txn; vmwareDcZoneMap = _vmwareDcZoneMapDao.findByZoneId(zoneId); // Check if zone is associated with VMware DC if (vmwareDcZoneMap == null) { throw new CloudRuntimeException( "Zone " + zoneId + " is not associated with any VMware datacenter."); } vmwareDcId = vmwareDcZoneMap.getVmwareDcId(); vmwareDatacenter = _vmwareDcDao.findById(vmwareDcId); vmwareDcName = vmwareDatacenter.getVmwareDatacenterName(); vCenterHost = vmwareDatacenter.getVcenterHost(); userName = vmwareDatacenter.getUser(); password = vmwareDatacenter.getPassword(); txn = Transaction.currentTxn(); try { txn.start(); // Remove the VMware datacenter entry in table vmware_data_center _vmwareDcDao.remove(vmwareDcId); // Remove the map entry in table vmware_data_center_zone_map _vmwareDcZoneMapDao.remove(vmwareDcZoneMap.getId()); txn.commit(); } catch (Exception e) { s_logger.info( "Caught exception when trying to delete VMware datacenter record." + e.getMessage()); throw new CloudRuntimeException("Failed to delete VMware datacenter."); } // Construct context VmwareContext context = null; try { context = VmwareContextFactory.create(vCenterHost, userName, password); // Check if DC exists on vCenter try { dcMo = new DatacenterMO(context, vmwareDcName); } catch (Throwable t) { String msg = "Unable to find DC " + vmwareDcName + " in vCenter " + vCenterHost; s_logger.error(msg); throw new DiscoveryException(msg); } assert (dcMo != null); // Reset custom field property cloud.zone over this DC dcMo.setCustomFieldValue(CustomFieldConstants.CLOUD_ZONE, "false"); s_logger.info("Sucessfully reset custom field property cloud.zone over DC " + vmwareDcName); } catch (Exception e) { String msg = "Unable to reset custom field property cloud.zone over DC " + vmwareDcName + " due to : " + VmwareHelper.getExceptionMessage(e); s_logger.error(msg); throw new CloudRuntimeException(msg); } finally { if (context != null) { context.close(); } context = null; } return true; }
@Override public Map<? extends ServerResource, Map<String, String>> find( long dcId, Long podId, Long clusterId, URI url, String username, String password, List<String> hostTags) throws DiscoveryException { if (s_logger.isInfoEnabled()) s_logger.info( "Discover host. dc: " + dcId + ", pod: " + podId + ", cluster: " + clusterId + ", uri host: " + url.getHost()); if (podId == null) { if (s_logger.isInfoEnabled()) s_logger.info( "No pod is assigned, assuming that it is not for vmware and skip it to next discoverer"); return null; } ClusterVO cluster = _clusterDao.findById(clusterId); if (cluster == null || cluster.getHypervisorType() != HypervisorType.VMware) { if (s_logger.isInfoEnabled()) s_logger.info("invalid cluster id or cluster is not for VMware hypervisors"); return null; } List<HostVO> hosts = _resourceMgr.listAllHostsInCluster(clusterId); if (hosts != null && hosts.size() > 0) { int maxHostsPerCluster = _hvCapabilitiesDao.getMaxHostsPerCluster( hosts.get(0).getHypervisorType(), hosts.get(0).getHypervisorVersion()); if (hosts.size() > maxHostsPerCluster) { String msg = "VMware cluster " + cluster.getName() + " is too big to add new host now. (current configured cluster size: " + maxHostsPerCluster + ")"; s_logger.error(msg); throw new DiscoveredWithErrorException(msg); } } String privateTrafficLabel = null; String publicTrafficLabel = null; String guestTrafficLabel = null; Map<String, String> vsmCredentials = null; VirtualSwitchType defaultVirtualSwitchType = VirtualSwitchType.StandardVirtualSwitch; String paramGuestVswitchType = null; String paramGuestVswitchName = null; String paramPublicVswitchType = null; String paramPublicVswitchName = null; VmwareTrafficLabel guestTrafficLabelObj = new VmwareTrafficLabel(TrafficType.Guest); VmwareTrafficLabel publicTrafficLabelObj = new VmwareTrafficLabel(TrafficType.Public); Map<String, String> clusterDetails = _clusterDetailsDao.findDetails(clusterId); DataCenterVO zone = _dcDao.findById(dcId); NetworkType zoneType = zone.getNetworkType(); _readGlobalConfigParameters(); // Set default physical network end points for public and guest traffic // Private traffic will be only on standard vSwitch for now. if (useDVS) { // Parse url parameters for type of vswitch and name of vswitch specified at cluster level paramGuestVswitchType = _urlParams.get(ApiConstants.VSWITCH_TYPE_GUEST_TRAFFIC); paramGuestVswitchName = _urlParams.get(ApiConstants.VSWITCH_NAME_GUEST_TRAFFIC); paramPublicVswitchType = _urlParams.get(ApiConstants.VSWITCH_TYPE_PUBLIC_TRAFFIC); paramPublicVswitchName = _urlParams.get(ApiConstants.VSWITCH_NAME_PUBLIC_TRAFFIC); defaultVirtualSwitchType = getDefaultVirtualSwitchType(); } // Zone level vSwitch Type depends on zone level traffic labels // // User can override Zone wide vswitch type (for public and guest) by providing following // optional parameters in addClusterCmd // param "guestvswitchtype" with valid values vmwaredvs, vmwaresvs, nexusdvs // param "publicvswitchtype" with valid values vmwaredvs, vmwaresvs, nexusdvs // // Format of label is <VSWITCH>,<VLANID>,<VSWITCHTYPE> // If a field <VLANID> OR <VSWITCHTYPE> is not present leave it empty. // Ex: 1) vswitch0 // 2) dvswitch0,200,vmwaredvs // 3) nexusepp0,300,nexusdvs // 4) vswitch1,400,vmwaresvs // 5) vswitch0 // default vswitchtype is 'vmwaresvs'. // <VSWITCHTYPE> 'vmwaresvs' is for vmware standard vswitch // <VSWITCHTYPE> 'vmwaredvs' is for vmware distributed virtual switch // <VSWITCHTYPE> 'nexusdvs' is for cisco nexus distributed virtual switch // Get zone wide traffic labels for Guest traffic and Public traffic guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, HypervisorType.VMware); // Process traffic label information provided at zone level and cluster level guestTrafficLabelObj = getTrafficInfo( TrafficType.Guest, guestTrafficLabel, defaultVirtualSwitchType, paramGuestVswitchType, paramGuestVswitchName, clusterId); if (zoneType == NetworkType.Advanced) { // Get zone wide traffic label for Public traffic publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, HypervisorType.VMware); // Process traffic label information provided at zone level and cluster level publicTrafficLabelObj = getTrafficInfo( TrafficType.Public, publicTrafficLabel, defaultVirtualSwitchType, paramPublicVswitchType, paramPublicVswitchName, clusterId); // Configuration Check: A physical network cannot be shared by different types of virtual // switches. // // Check if different vswitch types are chosen for same physical network // 1. Get physical network for guest traffic - multiple networks // 2. Get physical network for public traffic - single network // See if 2 is in 1 // if no - pass // if yes - compare publicTrafficLabelObj.getVirtualSwitchType() == // guestTrafficLabelObj.getVirtualSwitchType() // true - pass // false - throw exception - fail cluster add operation List<? extends PhysicalNetwork> pNetworkListGuestTraffic = _netmgr.getPhysicalNtwksSupportingTrafficType(dcId, TrafficType.Guest); List<? extends PhysicalNetwork> pNetworkListPublicTraffic = _netmgr.getPhysicalNtwksSupportingTrafficType(dcId, TrafficType.Public); // Public network would be on single physical network hence getting first object of the list // would suffice. PhysicalNetwork pNetworkPublic = pNetworkListPublicTraffic.get(0); if (pNetworkListGuestTraffic.contains(pNetworkPublic)) { if (publicTrafficLabelObj.getVirtualSwitchType() != guestTrafficLabelObj.getVirtualSwitchType()) { String msg = "Both public traffic and guest traffic is over same physical network " + pNetworkPublic + ". And virtual switch type chosen for each traffic is different" + ". A physical network cannot be shared by different types of virtual switches."; s_logger.error(msg); throw new InvalidParameterValueException(msg); } } } else { // Distributed virtual switch is not supported in Basic zone for now. // Private / Management network traffic is not yet supported over distributed virtual switch. if (guestTrafficLabelObj.getVirtualSwitchType() != VirtualSwitchType.StandardVirtualSwitch) { String msg = "Detected that Guest traffic is over Distributed virtual switch in Basic zone. Only Standard vSwitch is supported in Basic zone."; s_logger.error(msg); throw new DiscoveredWithErrorException(msg); } } privateTrafficLabel = _netmgr.getDefaultManagementTrafficLabel(dcId, HypervisorType.VMware); if (privateTrafficLabel != null) { s_logger.info("Detected private network label : " + privateTrafficLabel); } if (nexusDVS) { if (zoneType != NetworkType.Basic) { publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, HypervisorType.VMware); if (publicTrafficLabel != null) { s_logger.info("Detected public network label : " + publicTrafficLabel); } } // Get physical network label guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, HypervisorType.VMware); if (guestTrafficLabel != null) { s_logger.info("Detected guest network label : " + guestTrafficLabel); } vsmCredentials = _vmwareMgr.getNexusVSMCredentialsByClusterId(clusterId); } VmwareContext context = null; try { context = VmwareContextFactory.create(url.getHost(), username, password); if (privateTrafficLabel != null) context.registerStockObject("privateTrafficLabel", privateTrafficLabel); if (nexusDVS) { if (vsmCredentials != null) { s_logger.info("Stocking credentials of Nexus VSM"); context.registerStockObject("vsmcredentials", vsmCredentials); } } List<ManagedObjectReference> morHosts = _vmwareMgr.addHostToPodCluster( context, dcId, podId, clusterId, URLDecoder.decode(url.getPath())); if (morHosts == null) s_logger.info("Found 0 hosts."); if (privateTrafficLabel != null) context.uregisterStockObject("privateTrafficLabel"); if (morHosts == null) { s_logger.error( "Unable to find host or cluster based on url: " + URLDecoder.decode(url.getPath())); return null; } ManagedObjectReference morCluster = null; clusterDetails = _clusterDetailsDao.findDetails(clusterId); if (clusterDetails.get("url") != null) { URI uriFromCluster = new URI(UriUtils.encodeURIComponent(clusterDetails.get("url"))); morCluster = context.getHostMorByPath(URLDecoder.decode(uriFromCluster.getPath())); if (morCluster == null || !morCluster.getType().equalsIgnoreCase("ClusterComputeResource")) { s_logger.warn( "Cluster url does not point to a valid vSphere cluster, url: " + clusterDetails.get("url")); return null; } else { ClusterMO clusterMo = new ClusterMO(context, morCluster); ClusterDasConfigInfo dasConfig = clusterMo.getDasConfig(); if (dasConfig != null && dasConfig.isEnabled() != null && dasConfig.isEnabled().booleanValue()) { clusterDetails.put("NativeHA", "true"); _clusterDetailsDao.persist(clusterId, clusterDetails); } } } if (!validateDiscoveredHosts(context, morCluster, morHosts)) { if (morCluster == null) s_logger.warn( "The discovered host is not standalone host, can not be added to a standalone cluster"); else s_logger.warn("The discovered host does not belong to the cluster"); return null; } Map<VmwareResource, Map<String, String>> resources = new HashMap<VmwareResource, Map<String, String>>(); for (ManagedObjectReference morHost : morHosts) { Map<String, String> details = new HashMap<String, String>(); Map<String, Object> params = new HashMap<String, Object>(); HostMO hostMo = new HostMO(context, morHost); details.put("url", hostMo.getHostName()); details.put("username", username); details.put("password", password); String guid = morHost.getType() + ":" + morHost.getValue() + "@" + url.getHost(); details.put("guid", guid); params.put("url", hostMo.getHostName()); params.put("username", username); params.put("password", password); params.put("zone", Long.toString(dcId)); params.put("pod", Long.toString(podId)); params.put("cluster", Long.toString(clusterId)); params.put("guid", guid); if (privateTrafficLabel != null) { params.put("private.network.vswitch.name", privateTrafficLabel); } params.put("guestTrafficInfo", guestTrafficLabelObj); params.put("publicTrafficInfo", publicTrafficLabelObj); VmwareResource resource = new VmwareResource(); try { resource.configure("VMware", params); } catch (ConfigurationException e) { _alertMgr.sendAlert( AlertManager.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + url.getHost(), "Error is " + e.getMessage()); s_logger.warn("Unable to instantiate " + url.getHost(), e); } resource.start(); resources.put(resource, details); } // place a place holder guid derived from cluster ID cluster.setGuid(UUID.nameUUIDFromBytes(String.valueOf(clusterId).getBytes()).toString()); _clusterDao.update(clusterId, cluster); return resources; } catch (DiscoveredWithErrorException e) { throw e; } catch (Exception e) { s_logger.warn( "Unable to connect to Vmware vSphere server. service address: " + url.getHost()); return null; } finally { if (context != null) context.close(); } }
@Override @DB public VmwareDatacenterVO addVmwareDatacenter(AddVmwareDcCmd cmd) throws ResourceInUseException { VmwareDatacenterVO vmwareDc = null; Long zoneId = cmd.getZoneId(); String userName = cmd.getUsername(); String password = cmd.getPassword(); String vCenterHost = cmd.getVcenter(); String vmwareDcName = cmd.getName(); // Validate username, password, VMware DC name and vCenter if (userName == null) { throw new InvalidParameterValueException("Missing or invalid parameter username."); } if (password == null) { throw new InvalidParameterValueException("Missing or invalid parameter username."); } if (vmwareDcName == null) { throw new InvalidParameterValueException( "Missing or invalid parameter name. Please provide valid VMware datacenter name."); } if (vCenterHost == null) { throw new InvalidParameterValueException( "Missing or invalid parameter name. " + "Please provide valid VMware vCenter server's IP address or fully qualified domain name."); } if (zoneId == null) { throw new InvalidParameterValueException( "Missing or invalid parameter name. " + "Please provide valid zone id."); } // Zone validation validateZone(zoneId); VmwareDatacenterZoneMapVO vmwareDcZoneMap = _vmwareDcZoneMapDao.findByZoneId(zoneId); // Check if zone is associated with VMware DC if (vmwareDcZoneMap != null) { // Check if the associated VMware DC matches the one specified in API params // This check would yield success as the association exists between same entities (zone and // VMware DC) // This scenario would result in if the API addVmwareDc is called more than once with same // parameters. Long associatedVmwareDcId = vmwareDcZoneMap.getVmwareDcId(); VmwareDatacenterVO associatedVmwareDc = _vmwareDcDao.findById(associatedVmwareDcId); if (associatedVmwareDc.getVcenterHost().equalsIgnoreCase(vCenterHost) && associatedVmwareDc.getVmwareDatacenterName().equalsIgnoreCase(vmwareDcName)) { s_logger.info( "Ignoring API call addVmwareDc, because VMware DC " + vCenterHost + "/" + vmwareDcName + " is already associated with specified zone with id " + zoneId); return associatedVmwareDc; } else { throw new CloudRuntimeException( "Zone " + zoneId + " is already associated with a VMware datacenter. " + "Only 1 VMware DC can be associated with a zone."); } } // Zone validation to check if the zone already has resources. // Association of VMware DC to zone is not allowed if zone already has resources added. validateZoneWithResources(zoneId, "add VMware datacenter to zone"); // Check if DC is already part of zone // In that case vmware_data_center table should have the DC vmwareDc = _vmwareDcDao.getVmwareDatacenterByGuid(vmwareDcName + "@" + vCenterHost); if (vmwareDc != null) { throw new ResourceInUseException( "This DC is already part of other CloudStack zone(s). Cannot add this DC to more zones."); } VmwareContext context = null; DatacenterMO dcMo = null; String dcCustomFieldValue; boolean addDcCustomFieldDef = false; boolean dcInUse = false; String guid; ManagedObjectReference dcMor; try { context = VmwareContextFactory.create(vCenterHost, userName, password); // Check if DC exists on vCenter dcMo = new DatacenterMO(context, vmwareDcName); dcMor = dcMo.getMor(); if (dcMor == null) { String msg = "Unable to find VMware DC " + vmwareDcName + " in vCenter " + vCenterHost + ". "; s_logger.error(msg); throw new InvalidParameterValueException(msg); } // Check if DC is already associated with another cloudstack deployment // Get custom field property cloud.zone over this DC guid = vmwareDcName + "@" + vCenterHost; dcCustomFieldValue = dcMo.getCustomFieldValue(CustomFieldConstants.CLOUD_ZONE); if (dcCustomFieldValue == null) { addDcCustomFieldDef = true; } dcInUse = Boolean.parseBoolean(dcCustomFieldValue); if (dcInUse) { throw new ResourceInUseException( "This DC is being managed by other CloudStack deployment. Cannot add this DC to zone."); } // Add DC to database into vmware_data_center table vmwareDc = new VmwareDatacenterVO(guid, vmwareDcName, vCenterHost, userName, password); Transaction txn = Transaction.currentTxn(); try { txn.start(); vmwareDc = _vmwareDcDao.persist(vmwareDc); txn.commit(); } catch (Exception e) { txn.rollback(); s_logger.error( "Failed to persist VMware datacenter details to database. Exception: " + e.getMessage()); throw new CloudRuntimeException(e.getMessage()); } // Map zone with vmware datacenter vmwareDcZoneMap = new VmwareDatacenterZoneMapVO(zoneId, vmwareDc.getId()); txn = Transaction.currentTxn(); try { txn.start(); vmwareDcZoneMap = _vmwareDcZoneMapDao.persist(vmwareDcZoneMap); txn.commit(); } catch (Exception e) { txn.rollback(); s_logger.error( "Failed to associate VMware datacenter with zone " + zoneId + ". Exception: " + e.getMessage()); // Removing VMware datacenter from vmware_data_center table because association with zone // failed. _vmwareDcDao.remove(vmwareDcZoneMap.getId()); throw new CloudRuntimeException(e.getMessage()); } // Set custom field for this DC if (addDcCustomFieldDef) { dcMo.ensureCustomFieldDef(CustomFieldConstants.CLOUD_ZONE); } dcMo.setCustomFieldValue(CustomFieldConstants.CLOUD_ZONE, "true"); } catch (Throwable e) { String msg = "Failed to add VMware DC to zone "; if (e instanceof RemoteException) { msg = "Encountered remote exception at vCenter. " + VmwareHelper.getExceptionMessage(e); } else { msg += "due to : " + e.getMessage(); } throw new CloudRuntimeException(msg); } finally { if (context != null) { context.close(); } context = null; } return vmwareDc; }