private static ProxyRolloutGroup createProxy(final RolloutGroup rolloutGroup) { final ProxyRolloutGroup proxyRolloutGroup = new ProxyRolloutGroup(); proxyRolloutGroup.setName(rolloutGroup.getName()); proxyRolloutGroup.setDescription(rolloutGroup.getDescription()); proxyRolloutGroup.setCreatedDate(SPDateTimeUtil.getFormattedDate(rolloutGroup.getCreatedAt())); proxyRolloutGroup.setModifiedDate(SPDateTimeUtil.getFormattedDate(rolloutGroup.getLastModifiedAt())); proxyRolloutGroup.setCreatedBy(UserDetailsFormatter.loadAndFormatCreatedBy(rolloutGroup)); proxyRolloutGroup.setLastModifiedBy(UserDetailsFormatter.loadAndFormatLastModifiedBy(rolloutGroup)); proxyRolloutGroup.setId(rolloutGroup.getId()); proxyRolloutGroup.setStatus(rolloutGroup.getStatus()); proxyRolloutGroup.setErrorAction(rolloutGroup.getErrorAction()); proxyRolloutGroup.setErrorActionExp(rolloutGroup.getErrorActionExp()); proxyRolloutGroup.setErrorCondition(rolloutGroup.getErrorCondition()); proxyRolloutGroup.setErrorConditionExp(rolloutGroup.getErrorConditionExp()); proxyRolloutGroup.setSuccessCondition(rolloutGroup.getSuccessCondition()); proxyRolloutGroup.setSuccessConditionExp(rolloutGroup.getSuccessConditionExp()); proxyRolloutGroup.setFinishedPercentage(HawkbitCommonUtil.formattingFinishedPercentage(rolloutGroup, rolloutGroup.getTotalTargetCountStatus().getFinishedPercent())); proxyRolloutGroup.setRolloutRendererData(new RolloutRendererData(rolloutGroup.getName(), null)); proxyRolloutGroup.setTotalTargetsCount(String.valueOf(rolloutGroup.getTotalTargets())); proxyRolloutGroup.setTotalTargetCountStatus(rolloutGroup.getTotalTargetCountStatus()); return proxyRolloutGroup; }
/** * Populates the row with the data from the provided groups. * * @param group * the data source */ public void populateByGroup(final RolloutGroup group) { initialized = false; groupName.setValue(group.getName()); targetFilterQuery.setValue(group.getTargetFilterQuery()); populateTargetFilterQuery(group); targetPercentage.setValue(String.format("%.2f", group.getTargetPercentage())); triggerThreshold.setValue(group.getSuccessConditionExp()); errorThreshold.setValue(group.getErrorConditionExp()); populated = true; initialized = true; }
private void callErrorAction(final Rollout rollout, final RolloutGroup rolloutGroup) { try { context.getBean(rolloutGroup.getErrorAction().getBeanName(), RolloutGroupActionEvaluator.class) .eval(rollout, rolloutGroup, rolloutGroup.getErrorActionExp()); } catch (final BeansException e) { LOGGER.error("Something bad happend when accessing the error action bean {}", rolloutGroup.getErrorAction().getBeanName(), e); } }
/** * Verifies that the group has the required success condition and action and * a falid target percentage. * * @param group * the input group * @return the verified group */ public static RolloutGroup verifyRolloutGroupHasConditions(final RolloutGroup group) { if (group.getTargetPercentage() < 1F || group.getTargetPercentage() > 100F) { throw new ValidationException("Target percentage has to be between 1 and 100"); } if (group.getSuccessCondition() == null) { throw new ValidationException("Rollout group is missing success condition"); } if (group.getSuccessAction() == null) { throw new ValidationException("Rollout group is missing success action"); } return group; }
static MgmtRolloutGroupResponseBody toResponseRolloutGroup(final RolloutGroup rolloutGroup, final boolean withDetailedStatus) { final MgmtRolloutGroupResponseBody body = new MgmtRolloutGroupResponseBody(); body.setCreatedAt(rolloutGroup.getCreatedAt()); body.setCreatedBy(rolloutGroup.getCreatedBy()); body.setDescription(rolloutGroup.getDescription()); body.setLastModifiedAt(rolloutGroup.getLastModifiedAt()); body.setLastModifiedBy(rolloutGroup.getLastModifiedBy()); body.setName(rolloutGroup.getName()); body.setRolloutGroupId(rolloutGroup.getId()); body.setStatus(rolloutGroup.getStatus().toString().toLowerCase()); body.setTargetPercentage(rolloutGroup.getTargetPercentage()); body.setTargetFilterQuery(rolloutGroup.getTargetFilterQuery()); body.setTotalTargets(rolloutGroup.getTotalTargets()); body.setSuccessCondition(new MgmtRolloutCondition(map(rolloutGroup.getSuccessCondition()), rolloutGroup.getSuccessConditionExp())); body.setSuccessAction( new MgmtRolloutSuccessAction(map(rolloutGroup.getSuccessAction()), rolloutGroup.getSuccessActionExp())); new MgmtRolloutCondition(map(rolloutGroup.getErrorCondition()), rolloutGroup.getErrorConditionExp())); body.setErrorAction( new MgmtRolloutErrorAction(map(rolloutGroup.getErrorAction()), rolloutGroup.getErrorActionExp())); rolloutGroup.getTotalTargetCountStatus().getTotalTargetCountByStatus(status)); body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRolloutGroup(rolloutGroup.getRollout().getId(), rolloutGroup.getId())).withSelfRel()); return body;
for (final RolloutGroup srcGroup : groups) { final JpaRolloutGroup group = new JpaRolloutGroup(); group.setName(srcGroup.getName()); group.setDescription(srcGroup.getDescription()); group.setRollout(savedRollout); group.setParent(lastSavedGroup); group.setStatus(RolloutGroupStatus.CREATING); group.setTargetPercentage(srcGroup.getTargetPercentage()); if (srcGroup.getTargetFilterQuery() != null) { group.setTargetFilterQuery(srcGroup.getTargetFilterQuery()); } else { group.setTargetFilterQuery(""); group.setSuccessCondition(srcGroup.getSuccessCondition()); group.setSuccessConditionExp(srcGroup.getSuccessConditionExp()); group.setSuccessAction(srcGroup.getSuccessAction()); group.setSuccessActionExp(srcGroup.getSuccessActionExp()); group.setErrorCondition(srcGroup.getErrorCondition()); group.setErrorConditionExp(srcGroup.getErrorConditionExp()); group.setErrorAction(srcGroup.getErrorAction()); group.setErrorActionExp(srcGroup.getErrorActionExp());
/** * Constructor. * * @param rolloutGroup * the rollout group for this key * @param target * the target for this key */ public RolloutTargetGroupId(final RolloutGroup rolloutGroup, final Target target) { this.rolloutGroup = rolloutGroup.getId(); this.target = target.getId(); }
private static boolean isTargetFilterInGroups(final String groupFilter, final List<RolloutGroup> groups) { return !StringUtils.isEmpty(groupFilter) && groups.stream().anyMatch(prevGroup -> !StringUtils.isEmpty(prevGroup.getTargetFilterQuery()) && prevGroup.getTargetFilterQuery().equals(groupFilter)); }
private boolean checkErrorState(final Rollout rollout, final RolloutGroup rolloutGroup) { final RolloutGroupErrorCondition errorCondition = rolloutGroup.getErrorCondition(); if (errorCondition == null) { // there is no error condition, so return false, don't have error. return false; } try { return context.getBean(errorCondition.getBeanName(), RolloutGroupConditionEvaluator.class).eval(rollout, rolloutGroup, rolloutGroup.getErrorConditionExp()); } catch (final BeansException e) { LOGGER.error("Something bad happend when accessing the error condition bean {}", errorCondition.getBeanName(), e); return false; } }
private void startNextGroup(final Rollout rollout, final RolloutGroup rolloutGroup) { // retrieve all actions according to the parent group of the finished // rolloutGroup, so retrieve all child-group actions which need to be // started. final long countOfStartedActions = deploymentManagement.startScheduledActionsByRolloutGroupParent( rollout.getId(), rollout.getDistributionSet().getId(), rolloutGroup.getId()); logger.debug("{} Next actions started for rollout {} and parent group {}", countOfStartedActions, rollout, rolloutGroup); if (countOfStartedActions > 0) { // get all next scheduled groups and set them in state running rolloutGroupRepository.setStatusForCildren(RolloutGroupStatus.RUNNING, rolloutGroup); } else { logger.info("No actions to start for next rolloutgroup of parent {} {}", rolloutGroup.getId(), rolloutGroup.getName()); // nothing for next group, just finish the group, this can happen // e.g. if targets has been deleted after the group has been // scheduled. If the group is empty now, we just finish the group if // there are not actions available for this group. final List<JpaRolloutGroup> findByRolloutGroupParent = rolloutGroupRepository .findByParentIdAndStatus(rolloutGroup.getId(), RolloutGroupStatus.SCHEDULED); findByRolloutGroupParent.forEach(nextGroup -> { logger.debug("Rolloutgroup {} is finished, starting next group", nextGroup); nextGroup.setStatus(RolloutGroupStatus.FINISHED); rolloutGroupRepository.save(nextGroup); // find the next group to set in running state startNextGroup(rollout, nextGroup); }); } } }
@Override public boolean eval(final Rollout rollout, final RolloutGroup rolloutGroup, final String expression) { final long totalGroup = rolloutGroup.getTotalTargets(); if (totalGroup == 0) { // in case e.g. targets has been deleted we don't have any // actions left for this group, so the group is finished return true; } final long finished = this.actionRepository.countByRolloutIdAndRolloutGroupIdAndStatus(rollout.getId(), rolloutGroup.getId(), Action.Status.FINISHED); try { final Integer threshold = Integer.valueOf(expression); // calculate threshold return ((float) finished / (float) totalGroup) >= ((float) threshold / 100F); } catch (final NumberFormatException e) { LOGGER.error("Cannot evaluate condition expression " + expression, e); return false; } }
/** * Populates the legend based on a list of groups. * * @param groups * List of groups with their name */ public void populateGroupsLegendByGroups(final List<RolloutGroup> groups) { loadingLabel.setVisible(false); for (int i = 0; i < getGroupsWithoutToBeContinuedLabel(groups.size()); i++) { final Component component = groupsLegend.getComponent(i); final Label label = (Label) component; if (groups.size() > i) { final int targetCount = groups.get(i).getTotalTargets(); final String groupName = groups.get(i).getName(); label.setValue(getTargetsInGroupMessage((long) targetCount, groupName)); label.setVisible(true); } else { label.setValue(""); label.setVisible(false); } } showOrHideToBeContinueLabel(groups); }
protected RolloutGroupsValidation validateTargetsInGroups(final List<RolloutGroup> groups, final String baseFilter, final long totalTargets) { final List<Long> groupTargetCounts = new ArrayList<>(groups.size()); final Map<String, Long> targetFilterCounts = groups.stream() .map(group -> RolloutHelper.getGroupTargetFilter(baseFilter, group)).distinct() .collect(Collectors.toMap(Function.identity(), targetManagement::countByRsql)); long unusedTargetsCount = 0; for (int i = 0; i < groups.size(); i++) { final RolloutGroup group = groups.get(i); final String groupTargetFilter = RolloutHelper.getGroupTargetFilter(baseFilter, group); RolloutHelper.verifyRolloutGroupTargetPercentage(group.getTargetPercentage()); final long targetsInGroupFilter = targetFilterCounts.get(groupTargetFilter); final long overlappingTargets = countOverlappingTargetsWithPreviousGroups(baseFilter, groups, group, i, targetFilterCounts); final long realTargetsInGroup; // Assume that targets which were not used in the previous groups // are used in this group if (overlappingTargets > 0 && unusedTargetsCount > 0) { realTargetsInGroup = targetsInGroupFilter - overlappingTargets + unusedTargetsCount; unusedTargetsCount = 0; } else { realTargetsInGroup = targetsInGroupFilter - overlappingTargets; } final long reducedTargetsInGroup = Math .round(group.getTargetPercentage() / 100 * (double) realTargetsInGroup); groupTargetCounts.add(reducedTargetsInGroup); unusedTargetsCount += realTargetsInGroup - reducedTargetsInGroup; } return new RolloutGroupsValidation(totalTargets, groupTargetCounts); }
if (targetsPerGroup.size() > i && groups.size() > i && labelsToUpdate > i) { final Long targetCount = targetsPerGroup.get(i); final String groupName = groups.get(i).build().getName();
for (final RolloutGroup srcGroup : groups) { final JpaRolloutGroup group = new JpaRolloutGroup(); group.setName(srcGroup.getName()); group.setDescription(srcGroup.getDescription()); group.setRollout(savedRollout); group.setParent(lastSavedGroup); group.setStatus(RolloutGroupStatus.CREATING); group.setTargetPercentage(srcGroup.getTargetPercentage()); if (srcGroup.getTargetFilterQuery() != null) { group.setTargetFilterQuery(srcGroup.getTargetFilterQuery()); } else { group.setTargetFilterQuery(""); group.setSuccessCondition(srcGroup.getSuccessCondition()); group.setSuccessConditionExp(srcGroup.getSuccessConditionExp()); group.setSuccessAction(srcGroup.getSuccessAction()); group.setSuccessActionExp(srcGroup.getSuccessActionExp()); group.setErrorCondition(srcGroup.getErrorCondition()); group.setErrorConditionExp(srcGroup.getErrorConditionExp()); group.setErrorAction(srcGroup.getErrorAction()); group.setErrorActionExp(srcGroup.getErrorActionExp());
/** * Constructor. * * @param rolloutGroup * the rollout group for this key * @param target * the target for this key */ public RolloutTargetGroupId(final RolloutGroup rolloutGroup, final Target target) { this.rolloutGroup = rolloutGroup.getId(); this.target = target.getId(); }
/** * @param baseFilter * the base filter from the rollout * @param group * group for which the filter string should be created * @return the final target filter query for a rollout group */ static String getGroupTargetFilter(final String baseFilter, final RolloutGroup group) { if (StringUtils.isEmpty(group.getTargetFilterQuery())) { return baseFilter; } else { return concatAndTargetFilters(baseFilter, group.getTargetFilterQuery()); } }
private void callErrorAction(final Rollout rollout, final RolloutGroup rolloutGroup) { try { context.getBean(rolloutGroup.getErrorAction().getBeanName(), RolloutGroupActionEvaluator.class) .eval(rollout, rolloutGroup, rolloutGroup.getErrorActionExp()); } catch (final BeansException e) { LOGGER.error("Something bad happend when accessing the error action bean {}", rolloutGroup.getErrorAction().getBeanName(), e); } }
private boolean checkErrorState(final Rollout rollout, final RolloutGroup rolloutGroup) { final RolloutGroupErrorCondition errorCondition = rolloutGroup.getErrorCondition(); if (errorCondition == null) { // there is no error condition, so return false, don't have error. return false; } try { return context.getBean(errorCondition.getBeanName(), RolloutGroupConditionEvaluator.class).eval(rollout, rolloutGroup, rolloutGroup.getErrorConditionExp()); } catch (final BeansException e) { LOGGER.error("Something bad happend when accessing the error condition bean {}", errorCondition.getBeanName(), e); return false; } }
private void startNextGroup(final Rollout rollout, final RolloutGroup rolloutGroup) { // retrieve all actions according to the parent group of the finished // rolloutGroup, so retrieve all child-group actions which need to be // started. final long countOfStartedActions = deploymentManagement.startScheduledActionsByRolloutGroupParent( rollout.getId(), rollout.getDistributionSet().getId(), rolloutGroup.getId()); logger.debug("{} Next actions started for rollout {} and parent group {}", countOfStartedActions, rollout, rolloutGroup); if (countOfStartedActions > 0) { // get all next scheduled groups and set them in state running rolloutGroupRepository.setStatusForCildren(RolloutGroupStatus.RUNNING, rolloutGroup); } else { logger.info("No actions to start for next rolloutgroup of parent {} {}", rolloutGroup.getId(), rolloutGroup.getName()); // nothing for next group, just finish the group, this can happen // e.g. if targets has been deleted after the group has been // scheduled. If the group is empty now, we just finish the group if // there are not actions available for this group. final List<JpaRolloutGroup> findByRolloutGroupParent = rolloutGroupRepository .findByParentIdAndStatus(rolloutGroup.getId(), RolloutGroupStatus.SCHEDULED); findByRolloutGroupParent.forEach(nextGroup -> { logger.debug("Rolloutgroup {} is finished, starting next group", nextGroup); nextGroup.setStatus(RolloutGroupStatus.FINISHED); rolloutGroupRepository.save(nextGroup); // find the next group to set in running state startNextGroup(rollout, nextGroup); }); } } }