Add phase-configs support to Hook model for target-app resolution#1812
Add phase-configs support to Hook model for target-app resolution#1812stiv03 wants to merge 12 commits into
Conversation
20deee7 to
0827e89
Compare
…reen deployments Route hook task execution to idle or live app based on phase-configs in the hook descriptor. Pass idleMtaColor, liveMtaColor, subprocessPhase and phase variables to all hook call activities in BPMN processes. Add determineDeploymentTypeSafely to avoid SERVICE_ID lookup failures in hook subprocesses. # Conflicts: # pom.xml
buildCurrentPhaseString was always picking the first phase from hook.getPhases(), causing wrong target-app resolution when a hook registered for multiple phases fired during a later phase. Also fixed getDeploymentTypeString returning "deploy" instead of "blue-green" inside hook subprocesses where SERVICE_ID is absent. Introduced HOOK_EXECUTION_PHASE variable set by HooksExecutor to record which phase triggered the current hook execution. ExecuteTaskStep now matches against this value to find the correct phase-config entry. Variable is passed to all hook call activities in deploy-app, undeploy-app, backup-existing-app and stop-dependent-modules BPMNs.
0827e89 to
c5bab3b
Compare
c5bab3b to
9165d29
Compare
13a5600 to
7deb07c
Compare
| void appNameUnchangedWhenNoPhasesConfigMatchesCurrentPhase() { | ||
| context.setVariable(Variables.APP_TO_PROCESS, buildApp(APP_NAME_LIVE)); | ||
| context.setVariable(Variables.HOOK_EXECUTION_PHASES, List.of(BEFORE_STOP_LIVE)); | ||
| context.setVariable(Variables.HOOK_FOR_EXECUTION, buildHookWithPhasesConfig( | ||
| List.of(BEFORE_STOP_LIVE), | ||
| List.of(Map.of(PHASE_KEY, BEFORE_START_IDLE, TARGET_APP_KEY, TARGET_IDLE)) | ||
| )); | ||
|
|
||
| step.execute(execution); | ||
|
|
||
| assertStepFinishedSuccessfully(); | ||
| assertEquals(APP_NAME_LIVE, context.getVariable(Variables.APP_TO_PROCESS) | ||
| .getName()); | ||
| } | ||
|
|
||
| @Test | ||
| void bgDeploy_targetIdle_resolvesToIdleColorApp() { |
There was a problem hiding this comment.
Stick to one naming convention for the test method names
| public static final String CANNOT_RETRIEVE_PARAMETERS_OF_BINDING_BETWEEN_APPLICATION_0_AND_SERVICE_INSTANCE_1 = "Cannot retrieve parameters of binding between application \"{0}\" and service instance \"{1}\""; | ||
| public static final String CANNOT_RETRIEVE_PARAMETERS_OF_BINDING_BETWEEN_APPLICATION_0_AND_SERVICE_INSTANCE_1_FIX = "Cannot retrieve parameters of binding between application \"{0}\" and service instance \"{1}\". Got 502."; | ||
| public static final String CANNOT_RETRIEVE_INSTANCE_OF_SERVICE = "Cannot retrieve service instance of service \"{0}\""; | ||
| public static final String HOOK_PHASE_BLUE_GREEN_BEFORE_UNMAP_ROUTES_IDLE_USED = "Hook \"{0}\" uses deprecated phase \"blue-green.application.before-unmap-routes.idle\" which is unreachable and will be removed in a future version"; |
There was a problem hiding this comment.
This log message flows a bit better to me:
Hook \"{0}\" uses the deprecated phase \"blue-green.application.before-unmap-routes.idle\". This phase is unreachable and will be removed in a future version.
| SERVICE_BINDING_CONFIG, DELETE_SERVICE_KEY_AFTER_DEPLOYMENT); | ||
|
|
||
| public static final Set<String> MODULE_HOOK_PARAMETERS = Set.of(NAME, COMMAND, MEMORY, DISK_QUOTA, HOOK_REQUIRES); | ||
| public static final String PHASES_CONFIG = "phases-config"; |
There was a problem hiding this comment.
Move PHASES_CONFIG up with the other public static final declarations.
| @SuppressWarnings("unchecked") | ||
| private void validateHookHasNoDuplicatePhaseConfigs(Hook hook) { | ||
| Object phasesConfigValue = hook.getParameters().get(SupportedParameters.PHASES_CONFIG); | ||
| if (phasesConfigValue == null) { | ||
| return; | ||
| } | ||
| if (!(phasesConfigValue instanceof List)) { | ||
| throw new SLException(MessageFormat.format(Messages.INVALID_PHASES_CONFIG_NOT_A_LIST, hook.getName())); | ||
| } | ||
| List<Map<String, String>> phasesConfig = (List<Map<String, String>>) phasesConfigValue; |
There was a problem hiding this comment.
Can we scope @SuppressWarnings("unchecked") to just the cast instead of the whole method?
| @SuppressWarnings("unchecked") | ||
| private List<Map<String, String>> getPhasesConfig(Hook hook) { | ||
| Object phasesConfigValue = hook.getParameters() | ||
| .get(SupportedParameters.PHASES_CONFIG); | ||
| if (phasesConfigValue instanceof List) { | ||
| return (List<Map<String, String>>) phasesConfigValue; | ||
| } | ||
| return List.of(); | ||
| } |
There was a problem hiding this comment.
We treat missing or null PHASES_CONFIG as empty, but silently ignore cases where it’s present with the wrong type. Would it make sense to log or validate that here?
| private String resolveTargetAppName(ProcessContext context, CloudApplicationExtended app) { | ||
| Hook hook = context.getVariable(Variables.HOOK_FOR_EXECUTION); | ||
| if (hook == null) { | ||
| return app.getName(); | ||
| } | ||
|
|
||
| List<Map<String, String>> phasesConfig = getPhasesConfig(hook); | ||
| if (phasesConfig.isEmpty()) { | ||
| return app.getName(); | ||
| } | ||
|
|
||
| String currentPhase = buildCurrentPhaseString(context, hook); | ||
| String targetApp = phasesConfig.stream() | ||
| .filter(config -> currentPhase.equals(config.get(PHASE_KEY))) | ||
| .map(config -> config.get(TARGET_APP_KEY)) | ||
| .findFirst() | ||
| .orElse(null); | ||
|
|
||
| if (targetApp == null) { | ||
| return app.getName(); | ||
| } | ||
|
|
||
| return resolveAppNameForTarget(context, app, targetApp); | ||
| } |
There was a problem hiding this comment.
Small refactoring suggestion: app.getName() is returned in multiple branches here. Consider assigning it as the default result and only changing it when a target app is found, to reduce repetition.
| if (resolvedAppName == null) { | ||
| context.setVariable(Variables.TASKS_TO_EXECUTE, List.of()); | ||
| return StepPhase.DONE; | ||
| } | ||
| if (!resolvedAppName.equals(app.getName())) { | ||
| context.setVariable(Variables.APP_TO_PROCESS, buildAppWithName(app, resolvedAppName)); | ||
| } | ||
|
|
||
| return StepPhase.DONE; | ||
| } |
There was a problem hiding this comment.
Here all branches return StepPhase.DONE. Would it be clearer to return once at the end and update the context conditionally (e.g., using an else if)?
No description provided.