@Override public ResponseEntity<MgmtAction> getAction(@PathVariable("targetId") final String targetId, @PathVariable("actionId") final Long actionId) { final Action action = deploymentManagement.findAction(actionId) .orElseThrow(() -> new EntityNotFoundException(Action.class, actionId)); if (!action.getTarget().getControllerId().equals(targetId)) { LOG.warn(ACTION_TARGET_MISSING_ASSIGN_WARN, action.getId(), targetId); return ResponseEntity.notFound().build(); } return ResponseEntity.ok(MgmtTargetMapper.toResponseWithLinks(targetId, action)); }
public TargetAssignDistributionSetEvent(final Action action, final String applicationId) { this(action.getTenant(), action.getDistributionSet().getId(), Arrays.asList(action), applicationId, action.isMaintenanceWindowAvailable()); }
private StatusFontIcon createCancelButtonMetadata(final Action action) { final boolean isDisabled = !action.isActive() || action.isCancelingOrCanceled(); return new StatusFontIcon(FontAwesome.TIMES, STATUS_ICON_NEUTRAL, i18n.getMessage("message.cancel.action"), UIComponentIdProvider.ACTION_HISTORY_TABLE_CANCEL_ID, isDisabled); }
private static DdiMaintenanceWindowStatus calculateMaintenanceWindow(final Action action) { if (action.hasMaintenanceSchedule()) { return action.isMaintenanceWindowAvailable() ? DdiMaintenanceWindowStatus.AVAILABLE : DdiMaintenanceWindowStatus.UNAVAILABLE; } return null; }
/** * Generates a virtual IsActiveDecoration for the presentation layer that is * calculated from {@link Action#isActive()} and * {@link Action#getActionStatus()}. * * @param action * the action combined IsActiveDecoration is calculated from * @return IsActiveDecoration combined decoration for the presentation * layer. */ private static IsActiveDecoration buildIsActiveDecoration(final Action action) { final Action.Status status = action.getStatus(); if (status == Action.Status.SCHEDULED) { return IsActiveDecoration.SCHEDULED; } else if (status == Action.Status.ERROR) { return IsActiveDecoration.IN_ACTIVE_ERROR; } return action.isActive() ? IsActiveDecoration.ACTIVE : IsActiveDecoration.IN_ACTIVE; }
/** * @return {@code true} if either the {@link #getActionType()} is * {@link ActionType#FORCED} or {@link ActionType#TIMEFORCED} but * then if the {@link #getForcedTime()} has been exceeded otherwise * always {@code false} */ default boolean isForce() { switch (getActionType()) { case FORCED: return true; case TIMEFORCED: return isHitAutoForceTime(System.currentTimeMillis()); default: return false; } }
/** * Creates a list of {@link ProxyAction}s for presentation layer from slice * of {@link Action}s. * * @param actionBeans * slice of {@link Action}s * @return list of {@link ProxyAction}s */ private static List<ProxyAction> createProxyActions(final Slice<Action> actionBeans) { final List<ProxyAction> proxyActions = new ArrayList<>(); for (final Action action : actionBeans) { final ProxyAction proxyAction = new ProxyAction(); final String dsNameVersion = action.getDistributionSet().getName() + ":" + action.getDistributionSet().getVersion(); proxyAction.setActive(action.isActive()); proxyAction.setIsActiveDecoration(buildIsActiveDecoration(action)); proxyAction.setDsNameVersion(dsNameVersion); proxyAction.setAction(action); proxyAction.setId(action.getId()); proxyAction.setLastModifiedAt(action.getLastModifiedAt()); proxyAction.setRolloutName(action.getRollout() != null ? action.getRollout().getName() : ""); proxyAction.setStatus(action.getStatus()); proxyAction.setMaintenanceWindow( action.hasMaintenanceSchedule() ? buildMaintenanceWindowDisplayText(action) : ""); proxyActions.add(proxyAction); } return proxyActions; }
private void lookIfUpdateAvailable(final Target target) { final Optional<Action> actionOptional = controllerManagement .findOldestActiveActionByTarget(target.getControllerId()); if (!actionOptional.isPresent()) { return; } final Action action = actionOptional.get(); if (action.isCancelingOrCanceled()) { amqpMessageDispatcherService.sendCancelMessageToTarget(target.getTenant(), target.getControllerId(), action.getId(), target.getAddress()); return; } final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules = Maps .newHashMapWithExpectedSize(action.getDistributionSet().getModules().size()); final Map<Long, List<SoftwareModuleMetadata>> metadata = controllerManagement .findTargetVisibleMetaDataBySoftwareModuleId(action.getDistributionSet().getModules().stream() .map(SoftwareModule::getId).collect(Collectors.toList())); action.getDistributionSet().getModules().forEach(module -> modules.put(module, metadata.get(module.getId()))); amqpMessageDispatcherService.sendUpdateMessageToTarget(action.getTenant(), action.getTarget(), action.getId(), modules, action.isMaintenanceWindowAvailable()); }
static MgmtAction toResponse(final String targetId, final Action action) { final MgmtAction result = new MgmtAction(); result.setActionId(action.getId()); result.setType(getType(action)); if (ActionType.TIMEFORCED.equals(action.getActionType())) { result.setForceTime(action.getForcedTime()); } result.setForceType(MgmtRestModelMapper.convertActionType(action.getActionType())); if (action.isActive()) { result.setStatus(MgmtAction.ACTION_PENDING); } else { result.setStatus(MgmtAction.ACTION_FINISHED); } if (action.hasMaintenanceSchedule()) { final MgmtMaintenanceWindow maintenanceWindow = new MgmtMaintenanceWindow(); maintenanceWindow.setSchedule(action.getMaintenanceWindowSchedule()); maintenanceWindow.setDuration(action.getMaintenanceWindowDuration()); maintenanceWindow.setTimezone(action.getMaintenanceWindowTimeZone()); action.getMaintenanceWindowStartTime() .ifPresent(nextStart -> maintenanceWindow.setNextStartAt(nextStart.toInstant().toEpochMilli())); result.setMaintenanceWindow(maintenanceWindow); } MgmtRestModelMapper.mapBaseToBase(result, action); result.add(linkTo(methodOn(MgmtTargetRestApi.class).getAction(targetId, action.getId())).withSelfRel()); return result; }
if (!action.getTarget().getId().equals(target.getId())) { LOG.warn(GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET, action.getId(), target.getId()); return ResponseEntity.notFound().build(); if (!action.isCancelingOrCanceled()) { controllerManagement); final List<String> actionHistoryMsgs = controllerManagement.getActionHistoryMessages(action.getId(), actionHistoryMessageCount == null ? Integer.parseInt(DdiRestConstants.NO_ACTION_HISTORY) : actionHistoryMessageCount); : new DdiActionHistory(action.getStatus().name(), actionHistoryMsgs); final HandlingType downloadType = action.isForce() ? HandlingType.FORCED : HandlingType.ATTEMPT; final HandlingType updateType = calculateUpdateType(action, downloadType); final DdiDeploymentBase base = new DdiDeploymentBase(Long.toString(action.getId()), new DdiDeployment(downloadType, updateType, chunks, maintenanceWindow), actionHistory); controllerManagement.registerRetrieved(action.getId(), RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target retrieved update action and should start now the download.");
@Override public ResponseEntity<DdiControllerBase> getControllerBase(@PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId) { LOG.debug("getControllerBase({})", controllerId); final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(controllerId, IpUtil .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); final Action action = controllerManagement.findOldestActiveActionByTarget(controllerId).orElse(null); checkAndCancelExpiredAction(action); return new ResponseEntity<>( DataConversionHelper.fromTarget(target, action, action == null ? controllerManagement.getPollingTime() : controllerManagement.getPollingTimeForAction(action.getId()), tenantAware), HttpStatus.OK); }
/** * Method to update the action status of an action through the event. * * @param actionUpdateStatus * the object form the ampq message */ private void updateActionStatus(final Message message) { final DmfActionUpdateStatus actionUpdateStatus = convertMessage(message, DmfActionUpdateStatus.class); final Action action = checkActionExist(message, actionUpdateStatus); final List<String> messages = actionUpdateStatus.getMessage(); if (isCorrelationIdNotEmpty(message)) { messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX + "DMF message correlation-id " + message.getMessageProperties().getCorrelationId()); } final Status status = mapStatus(message, actionUpdateStatus, action); final ActionStatusCreate actionStatus = entityFactory.actionStatus().create(action.getId()).status(status) .messages(messages); final Action addUpdateActionStatus = getUpdateActionStatus(status, actionStatus); if (!addUpdateActionStatus.isActive() || (addUpdateActionStatus.hasMaintenanceSchedule() && addUpdateActionStatus.isMaintenanceWindowAvailable())) { lookIfUpdateAvailable(action.getTarget()); } }
@Override public ResponseEntity<DdiCancel> getControllerCancelAction(@PathVariable("tenant") final String tenant, @PathVariable("controllerId") @NotEmpty final String controllerId, @PathVariable("actionId") @NotEmpty final Long actionId) { LOG.debug("getControllerCancelAction({})", controllerId); final Target target = controllerManagement.getByControllerId(controllerId) .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); final Action action = findActionWithExceptionIfNotFound(actionId); if (!action.getTarget().getId().equals(target.getId())) { LOG.warn(GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET, action.getId(), target.getId()); return ResponseEntity.notFound().build(); } if (action.isCancelingOrCanceled()) { final DdiCancel cancel = new DdiCancel(String.valueOf(action.getId()), new DdiCancelActionToStop(String.valueOf(action.getId()))); LOG.debug("Found an active CancelAction for target {}. returning cancel: {}", controllerId, cancel); controllerManagement.registerRetrieved(action.getId(), RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target retrieved cancel action and should start now the cancelation."); return new ResponseEntity<>(cancel, HttpStatus.OK); } return ResponseEntity.notFound().build(); }
@Override public ResponseEntity<Void> postBasedeploymentActionFeedback(@Valid @RequestBody final DdiActionFeedback feedback, @PathVariable("tenant") final String tenant, @PathVariable("controllerId") final String controllerId, @PathVariable("actionId") @NotEmpty final Long actionId) { LOG.debug("provideBasedeploymentActionFeedback for target [{},{}]: {}", controllerId, actionId, feedback); final Target target = controllerManagement.getByControllerId(controllerId) .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); if (!actionId.equals(feedback.getId())) { LOG.warn( "provideBasedeploymentActionFeedback: action in payload ({}) was not identical to action in path ({}).", feedback.getId(), actionId); return ResponseEntity.notFound().build(); } final Action action = findActionWithExceptionIfNotFound(actionId); if (!action.getTarget().getId().equals(target.getId())) { LOG.warn(GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET, action.getId(), target.getId()); return ResponseEntity.notFound().build(); } if (!action.isActive()) { LOG.warn("Updating action {} with feedback {} not possible since action not active anymore.", action.getId(), feedback.getId()); return new ResponseEntity<>(HttpStatus.GONE); } controllerManagement.addUpdateActionStatus(generateUpdateStatus(feedback, controllerId, feedback.getId())); return ResponseEntity.ok().build(); }
static MgmtAction toResponseWithLinks(final String controllerId, final Action action) { final MgmtAction result = toResponse(controllerId, action); if (action.isCancelingOrCanceled()) { result.add(linkTo(methodOn(MgmtTargetRestApi.class).getAction(controllerId, action.getId())) .withRel(MgmtRestConstants.TARGET_V1_CANCELED_ACTION)); } result.add(linkTo( methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(action.getDistributionSet().getId())) .withRel("distributionset")); result.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionStatusList(controllerId, action.getId(), 0, MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, ActionStatusFields.ID.getFieldName() + ":" + SortDirection.DESC)) .withRel(MgmtRestConstants.TARGET_V1_ACTION_STATUS)); return result; }
/** * This method is called, when cancellation has been successful. It sets the * action to canceled, resets the meta data of the target and in case there * is a new action this action is triggered. * * @param action * the action which is set to canceled * @param actionRepository * for the operation * @param targetRepository * for the operation */ public static void successCancellation(final JpaAction action, final ActionRepository actionRepository, final TargetRepository targetRepository) { // set action inactive action.setActive(false); action.setStatus(Status.CANCELED); final JpaTarget target = (JpaTarget) action.getTarget(); final List<Action> nextActiveActions = actionRepository.findByTargetAndActiveOrderByIdAsc(target, true).stream() .filter(a -> !a.getId().equals(action.getId())).collect(Collectors.toList()); if (nextActiveActions.isEmpty()) { target.setAssignedDistributionSet(target.getInstalledDistributionSet()); target.setUpdateStatus(TargetUpdateStatus.IN_SYNC); } else { target.setAssignedDistributionSet(nextActiveActions.get(0).getDistributionSet()); } targetRepository.save(target); }
/** * If the action has a maintenance schedule defined but is no longer valid, * cancel the action. * * @param action * is the {@link Action} to check. */ private void checkAndCancelExpiredAction(final Action action) { if (action != null && action.hasMaintenanceSchedule() && action.isMaintenanceScheduleLapsed()) { try { controllerManagement.cancelAction(action.getId()); } catch (final CancelActionNotAllowedException e) { LOG.info("Cancel action not allowed exception :{}", e); } } }
if (action.isCancelingOrCanceled()) { result.add(ControllerLinkBuilder .linkTo(ControllerLinkBuilder.methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) .getControllerCancelAction(tenantAware.getCurrentTenant(), target.getControllerId(), action.getId())) .withRel(DdiRestConstants.CANCEL_ACTION)); } else { .linkTo(ControllerLinkBuilder.methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) .getControllerBasedeploymentAction(tenantAware.getCurrentTenant(), target.getControllerId(), action.getId(), calculateEtag(action), null)) .withRel(DdiRestConstants.DEPLOYMENT_BASE_ACTION));
private StatusFontIcon createForceButtonMetadata(final Action action) { final boolean isDisabled = !action.isActive() || action.isForce() || action.isCancelingOrCanceled(); return new StatusFontIcon(FontAwesome.BOLT, STATUS_ICON_NEUTRAL, i18n.getMessage("message.force.action"), UIComponentIdProvider.ACTION_HISTORY_TABLE_FORCE_ID, isDisabled); }
/** * Calculates an etag for the given {@link Action} based on the entities * hashcode and the {@link Action#isHitAutoForceTime(long)} to reflect a * force switch. * * @param action * to calculate the etag for * @return the etag */ private static int calculateEtag(final Action action) { final int prime = 31; int result = action.hashCode(); int offsetPrime = action.isHitAutoForceTime(System.currentTimeMillis()) ? 1231 : 1237; offsetPrime = (action.hasMaintenanceSchedule() && action.isMaintenanceWindowAvailable()) ? 1249 : offsetPrime; result = prime * result + offsetPrime; return result; }