All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cloudfoundry.multiapps.controller.process.steps.PollStartAppStatusExecution Maven / Gradle / Ivy

There is a newer version: 1.183.0
Show newest version
package org.cloudfoundry.multiapps.controller.process.steps;

import static java.text.MessageFormat.format;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory;
import org.cloudfoundry.multiapps.controller.core.security.token.TokenService;
import org.cloudfoundry.multiapps.controller.core.util.UriUtil;
import org.cloudfoundry.multiapps.controller.persistence.services.ProcessLoggerProvider;
import org.cloudfoundry.multiapps.controller.process.Messages;
import org.cloudfoundry.multiapps.controller.process.variables.Variables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sap.cloudfoundry.client.facade.CloudControllerClient;
import com.sap.cloudfoundry.client.facade.domain.CloudApplication;
import com.sap.cloudfoundry.client.facade.domain.CloudRoute;
import com.sap.cloudfoundry.client.facade.domain.InstanceInfo;
import com.sap.cloudfoundry.client.facade.domain.InstanceState;

public class PollStartAppStatusExecution implements AsyncExecution {

    private static final Logger LOGGER = LoggerFactory.getLogger(PollStartAppStatusExecution.class);
    private final CloudControllerClientFactory clientFactory;
    private final TokenService tokenService;

    public PollStartAppStatusExecution(CloudControllerClientFactory clientFactory, TokenService tokenService) {
        this.clientFactory = clientFactory;
        this.tokenService = tokenService;
    }

    @Override
    public AsyncExecutionState execute(ProcessContext context) {
        String appToPoll = getAppToPoll(context).getName();
        CloudControllerClient client = context.getControllerClient();

        context.getStepLogger()
               .debug(Messages.CHECKING_APP_STATUS, appToPoll);

        CloudApplication app = getApplication(context, appToPoll, client);
        List appInstances = client.getApplicationInstances(app)
                                                .getInstances();
        StartupStatus status = getStartupStatus(context, app.getName(), appInstances);
        ProcessLoggerProvider processLoggerProvider = context.getStepLogger()
                                                             .getProcessLoggerProvider();

        var user = context.getVariable(Variables.USER);
        var correlationId = context.getVariable(Variables.CORRELATION_ID);
        var logCacheClient = clientFactory.createLogCacheClient(tokenService.getToken(user), correlationId);

        StepsUtil.saveAppLogs(context, logCacheClient, app.getGuid(), app.getName(), LOGGER, processLoggerProvider);
        return checkStartupStatus(context, app, status);
    }

    public String getPollingErrorMessage(ProcessContext context) {
        String appToPoll = getAppToPoll(context).getName();
        return format(Messages.ERROR_STARTING_APP_0, appToPoll);
    }

    protected CloudApplication getAppToPoll(ProcessContext context) {
        return context.getVariable(Variables.APP_TO_PROCESS);
    }

    protected CloudApplication getApplication(ProcessContext context, String appToPoll, CloudControllerClient client) {
        CloudApplication application = context.getVariable(Variables.EXISTING_APP_TO_POLL);
        if (application == null) {
            application = client.getApplication(appToPoll);
            context.setVariable(Variables.EXISTING_APP_TO_POLL, application);
        }
        return application;
    }

    private StartupStatus getStartupStatus(ProcessContext context, String appName, List appInstances) {
        int expectedInstances = appInstances.size();
        long runningInstances = getInstanceCount(appInstances, InstanceState.RUNNING);
        long downInstances = getInstanceCount(appInstances, InstanceState.DOWN);
        long crashedInstances = getInstanceCount(appInstances, InstanceState.CRASHED);
        long startingInstances = getInstanceCount(appInstances, InstanceState.STARTING);

        String states = composeStatesMessage(appInstances);

        context.getStepLogger()
               .debug(Messages.APPLICATION_0_X_OF_Y_INSTANCES_RUNNING, appName, runningInstances, expectedInstances, states);

        if (runningInstances == expectedInstances) {
            return StartupStatus.STARTED;
        }
        if (startingInstances > 0) {
            return StartupStatus.STARTING;
        }
        if (downInstances > 0) {
            return StartupStatus.DOWN;
        }
        if (crashedInstances > 0) {
            return StartupStatus.CRASHED;
        }
        return StartupStatus.STARTING;
    }

    private AsyncExecutionState checkStartupStatus(ProcessContext context, CloudApplication app, StartupStatus status) {
        if (status == StartupStatus.CRASHED) {
            onError(context, Messages.ERROR_STARTING_APP_0_DESCRIPTION_1, app.getName(), Messages.SOME_INSTANCES_HAVE_CRASHED);
            return AsyncExecutionState.ERROR;
        }
        if (status == StartupStatus.DOWN) {
            onError(context, Messages.ERROR_STARTING_APP_0_DESCRIPTION_1, app.getName(), Messages.SOME_INSTANCES_ARE_DOWN);
            return AsyncExecutionState.ERROR;
        }
        if (status == StartupStatus.STARTED) {
            List routes = context.getControllerClient()
                                             .getApplicationRoutes(app.getGuid());
            if (routes.isEmpty()) {
                onSuccess(context, Messages.APP_STARTED, app.getName());
            } else {
                onSuccess(context, Messages.APP_STARTED_URLS, app.getName(), UriUtil.prettyPrintRoutes(routes));
            }
            return AsyncExecutionState.FINISHED;
        }
        return AsyncExecutionState.RUNNING;
    }

    protected void onError(ProcessContext context, String message, Object... arguments) {
        context.getStepLogger()
               .error(message, arguments);
    }

    protected void onSuccess(ProcessContext context, String message, Object... arguments) {
        context.getStepLogger()
               .info(message, arguments);
    }

    private String composeStatesMessage(List instances) {
        Map stateCounts;
        if (instances.isEmpty()) {
            stateCounts = Map.of(InstanceState.STARTING.toString(), 0L);
        } else {
            stateCounts = instances.stream()
                                   .collect(Collectors.groupingBy(instance -> instance.getState()
                                                                                      .toString(),
                                                                  Collectors.counting()));
        }
        return stateCounts.entrySet()
                          .stream()
                          .map(this::formatStateString)
                          .collect(Collectors.joining(","));
    }

    private String formatStateString(Map.Entry entry) {
        return format("{0} {1}", entry.getValue(), entry.getKey()
                                                        .toLowerCase());
    }

    private long getInstanceCount(List instances, InstanceState state) {
        return instances.stream()
                        .filter(instance -> instance.getState()
                                                    .equals(state))
                        .count();
    }

    enum StartupStatus {
        STARTING, STARTED, CRASHED, DOWN
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy