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 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"); }
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 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 boolean isDisconnectedEachOther(List<String> blackList, List<String> whiteList) { VirtualDataCenter myVdc = getLocalVdc(); Collection<String> addresses = myVdc.queryHostIPAddressesMap().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 <T extends DataObject> boolean hasDataInCF(Class<T> clazz) { if (excludeClasses.contains(clazz)) { return false; // ignore the data in those CFs } // true: query only active object ids, for below reason: // add VDC should succeed just when remove the data in vdc2. List<URI> ids = dbClient.queryByType(clazz, true, null, 2); if (clazz.equals(TenantOrg.class) || clazz.equals(ObjectStore.class)) { if (ids.size() > 1) { // at least one non-root tenant exist return true; } return false; } if (!ids.isEmpty()) { log.info("The class {} has data e.g. id={}", clazz.getSimpleName(), ids.get(0)); return true; } return false; }
@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(); } }
@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); 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); 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); if (isRemoveOp(param)) { log.info("Disable grossip to avoid schema version disagreement errors"); dbClient.stopClusterGossiping(); } break; } return Response.ok().build(); }
/** * 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); resp2.setIsAllNodesNotReachable( !helper.areNodesReachable( getLocalVdc().getShortId(), targetVdc.getHostIPv4AddressesMap(), targetVdc.getHostIPv6AddressesMap(), 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; }