/* * Copyright (c) 2014 EMC Corporation * All Rights Reserved */ package com.emc.storageos.geo.service.impl.resource; import java.net.InetAddress; import java.net.URI; import java.util.*; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import com.emc.storageos.coordinator.client.model.SiteInfo; import com.emc.storageos.model.property.PropertyInfoRestRep; import com.emc.storageos.security.ipsec.IPsecConfig; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.emc.storageos.api.service.impl.resource.ArgValidator; import com.emc.storageos.coordinator.client.model.RepositoryInfo; import com.emc.storageos.coordinator.client.model.Site; import com.emc.storageos.coordinator.client.model.SoftwareVersion; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.coordinator.client.service.DrUtil; import com.emc.storageos.coordinator.common.Service; import com.emc.storageos.db.client.model.StringMap; import com.emc.storageos.db.client.model.VirtualDataCenter; import com.emc.storageos.db.common.VdcUtil; import com.emc.storageos.geo.service.impl.GeoBackgroundTasks; import com.emc.storageos.geo.service.impl.util.VdcConfigHelper; import com.emc.storageos.geo.vdccontroller.impl.InternalDbClient; import com.emc.storageos.geomodel.VdcCertListParam; import com.emc.storageos.geomodel.VdcConfig; import com.emc.storageos.geomodel.VdcConfigSyncParam; import com.emc.storageos.geomodel.VdcNatCheckParam; import com.emc.storageos.geomodel.VdcNatCheckResponse; import com.emc.storageos.geomodel.VdcNodeCheckParam; import com.emc.storageos.geomodel.VdcNodeCheckResponse; import com.emc.storageos.geomodel.VdcPostCheckParam; import com.emc.storageos.geomodel.VdcPreCheckParam; import com.emc.storageos.geomodel.VdcPreCheckParam2; import com.emc.storageos.geomodel.VdcPreCheckResponse; import com.emc.storageos.geomodel.VdcPreCheckResponse2; import com.emc.storageos.security.geo.GeoServiceClient; import com.emc.storageos.security.geo.exceptions.GeoException; import com.emc.storageos.services.util.Strings; import com.emc.storageos.services.util.SysUtils; import com.emc.storageos.svcs.errorhandling.resources.APIException; import com.emc.storageos.svcs.errorhandling.resources.InternalException; import com.google.common.net.InetAddresses; import static com.emc.storageos.coordinator.client.model.Constants.IPSEC_KEY; import static com.emc.storageos.coordinator.client.model.Constants.VDC_CONFIG_VERSION; @Path(GeoServiceClient.VDCCONFIG_URI) public class VdcConfigService { private static final Logger log = LoggerFactory.getLogger(VdcConfigService.class); public static final String DataServiceName = "blobsvc"; public static final String DataServiceVersion = "1"; @Autowired private GeoBackgroundTasks geoBackgroundTasks; @Autowired private InternalDbClient dbClient; @Autowired private CoordinatorClient coordinator; @Autowired private VdcConfigHelper helper; @Autowired private DrUtil drUtil; private Service service; private SysUtils sysUtils; private IPsecConfig ipsecConfig; public void setIpsecConfig(IPsecConfig ipsecConfig) { this.ipsecConfig = ipsecConfig; } public void setService(Service service) { this.service = service; } /** * Retrieve the vdc config info of the current site, return such info with precheck. * 1. For adding a new vdc, the current vdc should be in ISOLATED status and is a fresh installation. * 2. For updating an existing vdc, the current vdc should be in CONNECTED status. * * @param checkParam * * @return VirtualDataCenterResponse */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/precheck") public VdcPreCheckResponse precheckVdcConfig(VdcPreCheckParam checkParam) { log.info("Start vdc config precheck for {} ...", checkParam.getConfigChangeType()); if (service.getId().endsWith("standalone")) { throw GeoException.fatals.remoteVDCWrongStandaloneInstall(); } log.info("Loading local vdc config ..."); VirtualDataCenter vdc = VdcUtil.getLocalVdc(); Boolean isFresher = checkParam.getFresher(); if (isFresher != null && isFresher) { // check if VDC is a fresh installation, in ISOLATED status if (VirtualDataCenter.ConnectionStatus.ISOLATED != vdc.getConnectionStatus()) { throw GeoException.fatals.remoteFreshVDCWrongStatus(vdc.getId()); } } else { // check if VDC is in CONNECTED status // check if VDC is in CONNECTED status- remove, add; update will skip-CTRL3549 if (checkParam.getConfigChangeType().equals(VdcConfig.ConfigChangeType.CONNECT_VDC.toString()) || (checkParam.getConfigChangeType().equals(VdcConfig.ConfigChangeType.REMOVE_VDC.toString()))) { if (vdc.getConnectionStatus() != VirtualDataCenter.ConnectionStatus.CONNECTED) { throw GeoException.fatals.remoteVDCWrongOperationStatus(vdc.getId(), checkParam.getConfigChangeType()); } } } boolean hasData = false; if (isFresher) { hasData = dbClient.hasUsefulData(); } hasData |= hasDataService(); log.info("Checking software version ..."); SoftwareVersion remoteSoftVer = null; try { remoteSoftVer = new SoftwareVersion(checkParam.getSoftwareVersion()); log.info("Software version of remote vdc: {}", remoteSoftVer); } catch (Exception e) { log.info("Cannot get software version from checkParam, the version of remote vdc is lower than v2.3 with exception {}", e.getMessage()); } SoftwareVersion localSoftVer; try { localSoftVer = coordinator.getTargetInfo(RepositoryInfo.class).getCurrentVersion(); } catch (Exception ex) { throw GeoException.fatals.remoteVDCFailedToGetVersion(vdc.getId()); } return toVirtualDataCenterResponse(vdc, hasData, remoteSoftVer, localSoftVer); } /** * @return true if there are data services */ private boolean hasDataService() { try { List<Service> services = coordinator.locateAllServices(DataServiceName, DataServiceVersion, null, null); if (services.isEmpty()) { return false; } } catch (Exception e) { return false; } return true; } /** * Do more precheck * For disconnecting a vdc, check if there is a VDC that is under disconnecting * If yes, return the VDC under disconnecting, otherwise set the VDC (given by parameter) * status to DISCONNECTING * * @param checkParam * * @return VdcPreCheckResponse */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/precheck2") public VdcPreCheckResponse2 precheckVdcConfig(VdcPreCheckParam2 checkParam) { log.info("Start vdc config precheck2 for {} ...", checkParam.getConfigChangeType()); if (service.getId().endsWith("standalone")) { throw GeoException.fatals.remoteVDCWrongStandaloneInstall(); } VdcConfig.ConfigChangeType type = checkParam.getConfigChangeType(); VirtualDataCenter vdc = null; VdcPreCheckResponse2 resp2 = new VdcPreCheckResponse2(); resp2.setCompatible(true); // BZ // TODO Need to use a different method to update info on lock on a remote system. // Need to use a different field (not connection status of VDC object) as a locking mechanism) boolean precheckFailed = checkParam.isPrecheckFailed(); switch (type) { case DISCONNECT_VDC: log.info("Precheck2 for disconnect ops"); vdc = helper.getDisconnectingVdc(); if (checkParam.getIsAllNotReachable()) { URI targetVdcId = checkParam.getVdcIds().get(0); log.info("Precheck2 to check the disconnect vdc {} is reachable", targetVdcId); VirtualDataCenter targetVdc = dbClient.queryObject(VirtualDataCenter.class, targetVdcId); Site activeSite = drUtil.getActiveSite(targetVdc.getShortId()); resp2.setIsAllNodesNotReachable(!helper.areNodesReachable(getLocalVdc().getShortId(), activeSite.getHostIPv4AddressMap(), activeSite.getHostIPv6AddressMap(), checkParam.getIsAllNotReachable())); break; } if (precheckFailed) { log.info("Precheck2 to update reconnect precheck fail status"); String vdcState = checkParam.getDefaultVdcState(); if (StringUtils.isNotEmpty(vdcState)) { vdc.setConnectionStatus(VirtualDataCenter.ConnectionStatus.valueOf(vdcState)); dbClient.updateAndReindexObject(vdc); } break; } if (vdc == null) { // no DISCONNECTING_VDC log.info("Precheck2: there is no disconnecting vdc"); URI srcVdcId = checkParam.getVdcIds().get(1); VirtualDataCenter srcVdc = dbClient.queryObject(VirtualDataCenter.class, srcVdcId); if (srcVdc.getConnectionStatus() == VirtualDataCenter.ConnectionStatus.DISCONNECTED) { resp2.setCompatible(false); break; } // BZ // TODO need to use a different field to set locks on concurrent VDC operation URI id = checkParam.getVdcIds().get(0); vdc = dbClient.queryObject(VirtualDataCenter.class, id); vdc.setConnectionStatus(VirtualDataCenter.ConnectionStatus.DISCONNECTING); dbClient.updateAndReindexObject(vdc); } else { resp2 = toVirtualDataCenterResponse2(vdc, true, null); } break; case RECONNECT_VDC: log.info("Precheck2 for reconnect ops checkParam={}", checkParam); List<String> blackList = checkParam.getBlackList(); List<String> whiteList = checkParam.getWhiteList(); log.info("Precheck2 to check if two vdc disconnect each other"); resp2.setCompatible(true); if (isDisconnectedEachOther(blackList, whiteList)) { log.info("Precheck2: two vdc have disconnected each other"); resp2.setCompatible(false); break; } if (precheckFailed) { log.info("Precheck2 to update reconnect precheck fail status"); URI targetVdcId = checkParam.getVdcIds().get(0); log.info("Precheck2 to check the disconnect vdc {} is reachable", targetVdcId); VirtualDataCenter targetVdc = dbClient.queryObject(VirtualDataCenter.class, targetVdcId); String vdcState = checkParam.getDefaultVdcState(); if (StringUtils.isNotEmpty(vdcState)) { targetVdc.setConnectionStatus(VirtualDataCenter.ConnectionStatus.valueOf(vdcState)); dbClient.updateAndReindexObject(targetVdc); } break; } break; } log.info("Precheck2 done, resp is {}", resp2.toString()); return resp2; } private boolean isDisconnectedEachOther(List<String> blackList, List<String> whiteList) { VirtualDataCenter myVdc = getLocalVdc(); Collection<String> addresses = dbClient.queryHostIPAddressesMap(myVdc).values(); log.info("local vdc IP addresses:{}", addresses); boolean found = false; for (String addr : addresses) { if (blackList.contains(addr)) { log.info("The addr {} is in the blackList {}", addr, blackList); found = true; break; } } if (found == false) { return false; // not disconnected each other } Collection<List<String>> localBlackLists = dbClient.getBlacklist().values(); log.info("The localBackLists={}", localBlackLists); List<String> localBlackList = new ArrayList(); for (List<String> list : localBlackLists) { localBlackList = list; } return localBlackList.containsAll(whiteList); } private VirtualDataCenter getLocalVdc() { List<URI> ids = dbClient.queryByType(VirtualDataCenter.class, true); for (URI id : ids) { VirtualDataCenter vdc = dbClient.queryObject(VirtualDataCenter.class, id); if (vdc.getLocal() == true) { return vdc; } } throw new RuntimeException("Failed to find local vdc"); } @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response syncVdcConfig(VdcConfigSyncParam param) { log.info("Acquired gobal lock, vdc {}...", param.getVirtualDataCenters().size()); VdcConfig.ConfigChangeType type = VdcConfig.ConfigChangeType.valueOf(param.getConfigChangeType()); log.info("Current config change type is {}", type); switch (type) { case DISCONNECT_VDC: String disconntecedvdcId = param.getAssignedVdcId(); try { disconnectVdc(disconntecedvdcId); } catch (Exception e) { throw GeoException.fatals.disconnectRemoteSyncFailed(disconntecedvdcId, e.getMessage()); } break; case RECONNECT_VDC: String reconnectVdcId = param.getAssignedVdcId(); try { VirtualDataCenter localVdc = VdcUtil.getLocalVdc(); // If the local vdc is the one need to be reconnected back, trigger a node repair for geodb if (localVdc.getId().toString().equals(reconnectVdcId)) { log.info("Perform sync vdc config operation and node repair for the reconnected vdc {}", reconnectVdcId); VirtualDataCenter reconnVdc = dbClient.queryObject(VirtualDataCenter.class, new URI(reconnectVdcId)); // Update operated local db, make sure all the vdcs in operated vdc'd db have the same status with others. log.info("Reconnect ops update local db for operatedVdc"); updateVdcStatusInDB(param.getVirtualDataCenters()); log.info("Reconnect ops update local db done"); // Clean blacklist for reconnected vdc log.info("Reconnect ops to clean blacklist for reconnected vdc."); updateBlackListForReconnectedVdc(); log.info("Reconnect ops: new blacklist is {}", dbClient.getBlacklist()); helper.syncVdcConfig(param.getVirtualDataCenters(), null, param.getVdcConfigVersion(), param.getIpsecKey()); log.info("Current strategy options is {}", dbClient.getGeoStrategyOptions()); log.info("Current schema version for Geo is {}", dbClient.getGeoSchemaVersions()); geoBackgroundTasks.startGeodbNodeRepair(); } else { reconnectVdc(reconnectVdcId); } } catch (Exception e) { throw GeoException.fatals.reconnectRemoteSyncFailed(reconnectVdcId, e.getMessage()); } break; default: Iterator<URI> srcVdcIdIter = dbClient.queryByType(VirtualDataCenter.class, true).iterator(); String assignedVdcId = param.getAssignedVdcId(); String geoEncryptionKey = param.getGeoEncryptionKey(); // for add-vdc if (assignedVdcId != null && geoEncryptionKey != null) { log.info("This vdc will be added to a geo system."); if (!srcVdcIdIter.hasNext()) { throw GeoException.fatals.connectVDCLocalMultipleVDC(assignedVdcId); } URI srcVdcId = srcVdcIdIter.next(); // Delete the local vdc record VirtualDataCenter existingVdc = dbClient.queryObject(VirtualDataCenter.class, srcVdcId); dbClient.markForDeletion(existingVdc); helper.deleteVdcConfigFromZk(existingVdc); log.info("The existing vdc {} has been removed. The current vdc id will be {}.", srcVdcId, assignedVdcId); helper.setGeoEncryptionKey(geoEncryptionKey); log.info("geo encryption key has been updated"); helper.resetStaleLocalObjects(); dbClient.stopClusterGossiping(); } else if (assignedVdcId == null && geoEncryptionKey == null) { log.info("Sync'ing new vdc info to existing geo system."); } else { throw GeoException.fatals.remoteVDCGeoEncryptionMissing(); } helper.syncVdcConfig(param.getVirtualDataCenters(), assignedVdcId, param.getVdcConfigVersion(), param.getIpsecKey()); if (isRemoveOp(param)) { log.info("Disable grossip to avoid schema version disagreement errors"); dbClient.stopClusterGossiping(); } break; } return Response.ok().build(); } private void updateVdcStatusInDB(List<VdcConfig> vdcConfigs) { List<URI> vdcIdIter = new ArrayList<>(); List<URI> vdcIds = dbClient.queryByType(VirtualDataCenter.class, true); for (URI id : vdcIds) { vdcIdIter.add(id); } for (VdcConfig vdcConfig : vdcConfigs) { log.info("current config's id is {}", vdcConfig.getId()); if (vdcIdIter.contains(vdcConfig.getId())) { VirtualDataCenter vdc = dbClient.queryObject(VirtualDataCenter.class, vdcConfig.getId()); vdc.setConnectionStatus(VirtualDataCenter.ConnectionStatus.valueOf(vdcConfig.getConnectionStatus())); dbClient.updateAndReindexObject(vdc); } } } private void updateBlackListForReconnectedVdc() { List<URI> vdcIds = dbClient.queryByType(VirtualDataCenter.class, true); dbClient.clearBlackList(); log.info("After clear, get current black list {}", dbClient.getBlacklist()); for (URI vdcId : vdcIds) { VirtualDataCenter vdc = dbClient.queryObject(VirtualDataCenter.class, vdcId); if (vdc.getConnectionStatus() == VirtualDataCenter.ConnectionStatus.DISCONNECTED) { log.info("Add vdc {} with status {} to blacklist", vdc.getId(), vdc.getConnectionStatus()); dbClient.addVdcNodesToBlacklist(vdc); } } } private void disconnectVdc(String vdcId) throws Exception { URI id = new URI(vdcId); VirtualDataCenter vdc = dbClient.queryObject(VirtualDataCenter.class, id); vdc.setConnectionStatus(VirtualDataCenter.ConnectionStatus.DISCONNECTED); dbClient.updateAndReindexObject(vdc); dbClient.addVdcNodesToBlacklist(vdc); } private void reconnectVdc(String vdcId) throws Exception { URI id = new URI(vdcId); VirtualDataCenter vdc = dbClient.queryObject(VirtualDataCenter.class, id); vdc.setConnectionStatus(VirtualDataCenter.ConnectionStatus.CONNECTED); dbClient.updateAndReindexObject(vdc); dbClient.removeVdcNodesFromBlacklist(vdc); } private boolean isRemoveOp(VdcConfigSyncParam param) { return VdcConfig.ConfigChangeType.REMOVE_VDC.toString().equals(param.getConfigChangeType()); } private static InetAddress parseInetAddress(String addrStr) { if (addrStr == null || addrStr.isEmpty()) { return null; } try { return InetAddresses.forString(addrStr); } catch (IllegalArgumentException e) { log.error(String.format("Failed to parse Inet address string: %s", addrStr), e); return null; } } @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/natcheck") public VdcNatCheckResponse checkIfBehindNat(VdcNatCheckParam checkParam, @HeaderParam("X-Forwarded-For") String clientIp) { if (checkParam == null) { log.error("checkParam is null, X-Forwarded-For is {}", clientIp); throw GeoException.fatals.invalidNatCheckCall("(null)", clientIp); } String ipv4Str = checkParam.getIPv4Address(); String ipv6Str = checkParam.getIPv6Address(); log.info(String.format("Performing NAT check, client address connecting to VIP: %s. Client reports its IPv4 = %s, IPv6 = %s", clientIp, ipv4Str, ipv6Str)); boolean isBehindNat = false; try { isBehindNat = sysUtils.checkIfBehindNat(ipv4Str, ipv6Str, clientIp); } catch (Exception e) { log.error("Fail to check NAT {}", e); throw GeoException.fatals.invalidNatCheckCall(e.getMessage(), clientIp); } VdcNatCheckResponse resp = new VdcNatCheckResponse(); resp.setSeenIp(clientIp); resp.setBehindNAT(isBehindNat); return resp; } /** * Post check after sync vdc config. * Verify if connect vdc finished successfully, if so, update the connection status. * * @param checkParam List of parameters to be checked. * * @return if check pass */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/postcheck") public Response verifyVdcConfig(VdcPostCheckParam checkParam) { log.info("Post check enter: {}", checkParam.getVdcList()); helper.syncVdcConfigPostSteps(checkParam); return Response.ok().build(); } /** * check to see if the individual nodes of one vdc are visible from another * * @param checkParam * @return */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/nodecheck") public VdcNodeCheckResponse checkNodeConnections(VdcNodeCheckParam checkParam, @HeaderParam("X-Forwarded-For") String clientIp) { List<VdcConfig> vdcList = checkParam.getVirtualDataCenters(); log.info("checking nodes for vdcs {} ...", getVdcIds(vdcList)); if (service.getId().endsWith("standalone")) { throw GeoException.fatals.remoteVDCWrongStandaloneInstall(); } ArgValidator.checkFieldNotEmpty(vdcList, "vdc"); VirtualDataCenter localVdc = VdcUtil.getLocalVdc(); if (localVdc == null) { throw GeoException.fatals.failedToFindLocalVDC(); } return toVdcNodeCheckResponse(localVdc, helper.areNodesReachable(vdcList, false)); } /** * @param configs * @return */ private String getVdcIds(List<VdcConfig> configs) { List<String> vdcShortIds = new ArrayList<String>(); for (VdcConfig config : configs) { vdcShortIds.add(config.getShortId()); } return StringUtils.join(vdcShortIds, ","); } /** * @param from * @param areNodesReachable * @return */ private VdcNodeCheckResponse toVdcNodeCheckResponse(VirtualDataCenter from, boolean areNodesReachable) { VdcNodeCheckResponse to = new VdcNodeCheckResponse(); to.setId(from.getId()); to.setShortId(from.getShortId()); to.setNodesReachable(areNodesReachable); return to; } private VdcPreCheckResponse toVirtualDataCenterResponse(VirtualDataCenter from, boolean hasData, SoftwareVersion remoteSoftVer, SoftwareVersion localSoftVer) { if (from == null) { return null; } Site activeSite = drUtil.getActiveSite(from.getShortId()); VdcPreCheckResponse to = new VdcPreCheckResponse(); to.setId(from.getId()); to.setConnectionStatus(from.getConnectionStatus().name()); to.setVersion(from.getVersion()); to.setShortId(from.getShortId()); to.setHostCount(activeSite.getNodeCount()); StringMap ipv4Addr = new StringMap(); ipv4Addr.putAll(activeSite.getHostIPv4AddressMap()); to.setHostIPv4AddressesMap(ipv4Addr); StringMap ipv6Addr = new StringMap(); ipv6Addr.putAll(activeSite.getHostIPv6AddressMap()); to.setHostIPv6AddressesMap(ipv6Addr); to.setName(from.getLabel()); to.setDescription(from.getDescription()); to.setApiEndpoint(activeSite.getVipEndPoint()); to.setSecretKey(from.getSecretKey()); to.setHasData(hasData); to.setSoftwareVersion(localSoftVer.toString()); boolean compatible = false; if (remoteSoftVer != null) { compatible = helper.isCompatibleVersion(remoteSoftVer); } to.setCompatible(compatible); boolean clusterStable = isClusterStable(); to.setClusterStable(clusterStable); log.info("current cluster stable {}", clusterStable); to.setActiveSiteId(activeSite.getUuid()); return to; } private VdcPreCheckResponse2 toVirtualDataCenterResponse2(VirtualDataCenter from, boolean hasData, SoftwareVersion softVer) { if (from == null) { return null; } VdcPreCheckResponse2 to = new VdcPreCheckResponse2(); to.setId(from.getId()); to.setCompatible(helper.isCompatibleVersion(softVer)); boolean clusterStable = isClusterStable(); to.setClusterStable(clusterStable); log.info("current cluster stable {}", clusterStable); return to; } /** * Check to see if the local cluster is stable * * @return true if state is STABLE */ private boolean isClusterStable() { return helper.isClusterStable(); } /** * Sync all VDCs' certs into the local VDC. * * @param vdcCertListParam vdc certs list parameter * * @return */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/certs") public Response syncCert(VdcCertListParam vdcCertListParam) { log.info("Syncing vdc certs: {}", vdcCertListParam); helper.syncVdcCerts(vdcCertListParam); return Response.ok().build(); } /** * Check if the current VDC is stable or not * * @return "true" if the current VDC is stable, "false" otherwise */ @GET @Produces({ MediaType.TEXT_PLAIN }) @Path("/stablecheck") public String checkVdcStable() { return String.valueOf(isClusterStable()); } @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/ipsec-properties") public PropertyInfoRestRep getIpsecProperties() throws Exception { log.info("getting ipsec properties."); Map<String, String> ipsecProps = new HashMap(); ipsecProps.put(IPSEC_KEY, ipsecConfig.getPreSharedKey()); SiteInfo siteInfo = coordinator.getTargetInfo(SiteInfo.class); String vdcConfigVersion = String.valueOf(siteInfo.getVdcConfigVersion()); ipsecProps.put(VDC_CONFIG_VERSION, vdcConfigVersion); log.info("ipsec key: " + ipsecConfig.getPreSharedKey() + ", vdc config version: " + vdcConfigVersion); return new PropertyInfoRestRep(ipsecProps); } @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/resetblacklist") public Response resetBlackListForVdc(@QueryParam("vdc_short_id") String vdcShortId) { try { log.info("Reset blacklist for {}", vdcShortId); URI vdcId = VdcUtil.getVdcUrn(vdcShortId); VirtualDataCenter vdc = dbClient.queryObject(VirtualDataCenter.class, vdcId); dbClient.removeVdcNodesFromBlacklist(vdc); return Response.ok().build(); } catch (InternalException ex) { throw ex; } catch (Exception ex) { log.error("Reset blacklist vdc error", ex); throw GeoException.fatals.reconnectVdcIncompatible(); } } public void setSysUtils(SysUtils sysUtils) { this.sysUtils = sysUtils; } }