/** * Update vdc properties and reboot the node if * * @param svcId node service id * @throws Exception */ private void updateVdcProperties(String svcId) throws Exception { // If the change is being done to create a multi VDC configuration or to reduce to a // multi VDC configuration a reboot is needed. If only operating on a single VDC // do not reboot the nodes. if (targetVdcPropInfo.getProperty(VdcConfigUtil.VDC_IDS).contains(",") || localVdcPropInfo.getProperty(VdcConfigUtil.VDC_IDS).contains(",")) { log.info("Step4: Acquiring property lock for vdc properties change."); if (!getPropertyLock(svcId)) { retrySleep(); } else if (!isQuorumMaintained()) { try { coordinator.releasePersistentLock(svcId, propertyLockId); } catch (Exception e) { log.error("Failed to release the property lock:", e); } retrySleep(); } else { log.info("Step4: Setting vdc properties and rebooting for multi-vdc config change"); localRepository.setVdcPropertyInfo(targetVdcPropInfo); reboot(); } } else { log.info("Step4: Setting vdc properties not rebooting for single VDC change"); localRepository.setVdcPropertyInfo(targetVdcPropInfo); } }
/** * Check if VDC configuration is different in the database vs. what is stored locally * * @return */ private boolean vdcPropertiesChanged() { if (!coordinator.isControlNode()) { return false; } int localVdcConfigHashcode = localVdcPropInfo.getProperty(VdcConfigUtil.VDC_CONFIG_HASHCODE) == null ? 0 : Integer.parseInt(localVdcPropInfo.getProperty(VdcConfigUtil.VDC_CONFIG_HASHCODE)); int targetVdcConfigHashcode = targetVdcPropInfo.getProperty(VdcConfigUtil.VDC_CONFIG_HASHCODE) == null ? 0 : Integer.parseInt(targetVdcPropInfo.getProperty(VdcConfigUtil.VDC_CONFIG_HASHCODE)); return localVdcConfigHashcode != targetVdcConfigHashcode; }
/** * Update properties * * @param svcId node service id * @throws Exception */ private void updateProperties(String svcId) throws Exception { if (targetPropInfo.TARGET_PROPERTY.equals(targetPropInfo.OLD_TARGET_PROPERTY)) { coordinator.removeTargetInfo(targetPropInfo, true); } PropertyInfoExt diffProperties = new PropertyInfoExt(targetPropInfo.getDiffProperties(localTargetPropInfo)); PropertyInfoExt override_properties = new PropertyInfoExt(localRepository.getOverrideProperties().getAllProperties()); log.info("Step3a: Updating User Changed properties file: {}", override_properties); PropertyInfoExt updatedUserChangedProps = combineProps(override_properties, diffProperties); if (diffProperties.hasRebootProperty()) { if (!getPropertyLock(svcId)) { retrySleep(); } else if (!isQuorumMaintained()) { try { coordinator.releasePersistentLock(svcId, propertyLockId); } catch (Exception e) { log.error("Failed to release the property lock:", e); } retrySleep(); } else { log.info("Step3a: Reboot property found."); localRepository.setOverrideProperties(updatedUserChangedProps); log.info("Step3a: Updating properties: {}", updatedUserChangedProps); reboot(); } } else if (diffProperties.hasReconfigProperty() || !diffProperties.getNotifierTags().isEmpty()) { log.info("Step3a: Reconfig property found or notifiers specified."); // CTRL-9860: don't update the local config version until everything is done. String targetVersion = targetPropInfo.getProperty(PropertyInfoExt.CONFIG_VERSION); updatedUserChangedProps.addProperty(PropertyInfoExt.CONFIG_VERSION, localConfigVersion); localRepository.setOverrideProperties(updatedUserChangedProps); log.info( "Step3a: Updating properties without updating the config version: {}", updatedUserChangedProps); if (diffProperties.hasReconfigAttributeWithoutNotifiers()) { // this is the old-school "complete" reconfig that takes no notifiers as arguments. // moving forward this will diminish // i.e., all reconfigRequired properties will have notifier specified. localRepository.reconfig(); } else if (diffProperties.hasReconfigProperty()) { reconfigProperties(diffProperties); } // the notifier list can be empty, in which case nothing will be done. notifyPropertyChanges(diffProperties); // update the local config version to target version now log.info("Step3a: Updating the config version to {}", targetVersion); updatedUserChangedProps.addProperty(PropertyInfoExt.CONFIG_VERSION, targetVersion); localRepository.setOverrideProperties(updatedUserChangedProps); } else { log.info("Step3a: No reboot property found."); localRepository.setOverrideProperties(updatedUserChangedProps); log.info("Step3a: Updating properties: {}", updatedUserChangedProps); } }
/** * Initialize local and target info * * @throws Exception */ private void initializeLocalAndTargetInfo(String svcId) throws Exception { // publish config_version which is also a target property // used as a flag denoting whether target properties have been changed PropertyInfoExt localPropInfo = localRepository.getOverrideProperties(); localConfigVersion = localPropInfo.getProperty(PropertyInfoExt.CONFIG_VERSION); if (localConfigVersion == null) { localConfigVersion = "0"; localPropInfo.addProperty(PropertyInfoExt.CONFIG_VERSION, localConfigVersion); } coordinator.setNodeSessionScopeInfo(new ConfigVersion(localConfigVersion)); log.info("Step1a: Local config version: {}", localConfigVersion); // set node scope properties for the 1st time only since they are invariants. localNodePropInfo = coordinator.getNodeGlobalScopeInfo(PropertyInfoExt.class, "propertyinfo", svcId); // The PropertyInfoExt object will be persisted in the zookeeper path // config/propertyinfo/(svcId) if (localNodePropInfo == null) { localNodePropInfo = getNodeScopeProperties(localPropInfo); coordinator.setNodeGlobalScopeInfo(localNodePropInfo, "propertyinfo", svcId); // The PropertyInfoExt object can be fetched from the zookeeper path // config/propertyinfo/(svcId) log.info("Step1a: Local node scope properties: {}", localNodePropInfo); } // get local target property info localTargetPropInfo = getLocalTargetPropInfo(localPropInfo); log.debug("Step1a: Local target properties: {}", localTargetPropInfo); // set target if empty targetPropInfo = coordinator.getTargetInfo(PropertyInfoExt.class); targetPowerOffState = coordinator.getTargetInfo(PowerOffState.class); if (targetPropInfo == null || targetPowerOffState == null) { // only control node can set target try { // Set the updated propperty info in coordinator coordinator.setTargetInfo(localPropInfo); coordinator.setTargetInfo(new PowerOffState(PowerOffState.State.NONE)); targetPropInfo = coordinator.getTargetInfo(PropertyInfoExt.class); log.info("Step1b: Target property set to local state: {}", targetPropInfo); targetPowerOffState = coordinator.getTargetInfo(PowerOffState.class); log.info("Step1b: Target poweroff state set to: {}", PowerOffState.State.NONE); } catch (CoordinatorClientException e) { log.info("Step1b: Wait another control node to set target"); retrySleep(); throw e; } } // Initialize vdc prop info localVdcPropInfo = localRepository.getVdcPropertyInfo(); targetVdcPropInfo = loadVdcConfigFromDatabase(); if (localVdcPropInfo.getProperty(VdcConfigUtil.VDC_CONFIG_HASHCODE) == null) { localRepository.setVdcPropertyInfo(targetVdcPropInfo); localVdcPropInfo = localRepository.getVdcPropertyInfo(); String vdc_ids = targetVdcPropInfo.getProperty(VDC_IDS_KEY); String[] vdcIds = vdc_ids.split(","); if (vdcIds.length > 1) { log.info("More than one Vdc, so set reboot flag"); shouldReboot = true; } } }
@Override protected void innerRun() { final String svcId = coordinator.getMySvcId(); while (doRun) { log.debug("Main loop: Start"); shortSleep = false; if (shouldReboot) { reboot(); } // Step0: check if we have the property lock boolean hasLock; try { hasLock = coordinator.hasPersistentLock(svcId, propertyLockId); } catch (Exception e) { log.info("Step1: Failed to verify if the current node has the property lock ", e); retrySleep(); continue; } if (hasLock) { try { coordinator.releasePersistentLock(svcId, propertyLockId); log.info("Step0: Released property lock for node: {}", svcId); wakeupOtherNodes(); } catch (InvalidLockOwnerException e) { log.error("Step0: Failed to release the property lock: Not owner."); } catch (Exception e) { log.info("Step0: Failed to release the property lock and will retry: {}", e.getMessage()); retrySleep(); continue; } } // Step1: publish current state, and set target if empty try { initializeLocalAndTargetInfo(svcId); } catch (Exception e) { log.info("Step1b failed and will be retried: {}", e.getMessage()); retrySleep(); continue; } // Step2: power off if all nodes agree. log.info("Step2: Power off if poweroff state != NONE. {}", targetPowerOffState); try { gracefulPoweroffCluster(); } catch (Exception e) { log.error("Step2: Failed to poweroff. {}", e); } // Step3: if target property is changed, update log.info("Step3: If target property is changed, update"); if (localTargetPropInfo != null && targetPropInfo != null && !localConfigVersion.equals( targetPropInfo.getProperty(PropertyInfoExt.CONFIG_VERSION))) { log.info("Step3a: Current properties are not same as target properties. Updating."); log.debug("Current local target properties: " + localTargetPropInfo); log.debug("Target properties: " + targetPropInfo); try { updateProperties(svcId); } catch (Exception e) { log.info("Step3a: Update failed and will be retried: {}", e.getMessage()); // Restart the loop immediately so that we release the upgrade lock. continue; } continue; } log.info("Step4: If VDC configuration is changed update"); if (vdcPropertiesChanged()) { log.info("Step4: Current vdc properties are not same as target vdc properties. Updating."); log.debug("Current local vdc properties: " + localVdcPropInfo); log.debug("Target vdc properties: " + targetVdcPropInfo); try { updateVdcProperties(svcId); } catch (Exception e) { log.info("Step4: VDC properties update failed and will be retried: {}", e.getMessage()); // Restart the loop immediately so that we release the upgrade lock. continue; } continue; } if (shouldReboot == false) { // Step5: sleep log.info("Step5: sleep"); longSleep(); } } }