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

org.cloudfoundry.multiapps.controller.process.steps.UploadAppAsyncExecution 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.nio.file.Path;
import java.text.MessageFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;

import org.cloudfoundry.multiapps.common.SLException;
import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudApplicationExtended;
import org.cloudfoundry.multiapps.controller.client.lib.domain.UploadStatusCallbackExtended;
import org.cloudfoundry.multiapps.controller.core.Constants;
import org.cloudfoundry.multiapps.controller.core.helpers.ApplicationEnvironmentUpdater;
import org.cloudfoundry.multiapps.controller.core.helpers.MtaArchiveElements;
import org.cloudfoundry.multiapps.controller.core.util.ApplicationConfiguration;
import org.cloudfoundry.multiapps.controller.core.util.FileUtils;
import org.cloudfoundry.multiapps.controller.persistence.services.ProcessLoggerPersister;
import org.cloudfoundry.multiapps.controller.process.Messages;
import org.cloudfoundry.multiapps.controller.process.context.ApplicationToUploadContext;
import org.cloudfoundry.multiapps.controller.process.context.ImmutableApplicationToUploadContext;
import org.cloudfoundry.multiapps.controller.process.util.ApplicationArchiveContext;
import org.cloudfoundry.multiapps.controller.process.util.ApplicationZipBuilder;
import org.cloudfoundry.multiapps.controller.process.util.StepLogger;
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.CloudPackage;
import com.sap.cloudfoundry.client.facade.domain.Status;

public class UploadAppAsyncExecution implements AsyncExecution {

    private static final Logger LOGGER = LoggerFactory.getLogger(UploadAppAsyncExecution.class);

    private final ApplicationZipBuilder applicationZipBuilder;
    private final ProcessLoggerPersister processLoggerPersister;
    private final ApplicationConfiguration applicationConfiguration;
    private final ExecutorService appUploaderThreadPool;

    public UploadAppAsyncExecution(ApplicationZipBuilder applicationZipBuilder, ProcessLoggerPersister processLoggerPersister,
                                   ApplicationConfiguration applicationConfiguration, ExecutorService appUploaderThreadPool) {
        this.applicationZipBuilder = applicationZipBuilder;
        this.processLoggerPersister = processLoggerPersister;
        this.applicationConfiguration = applicationConfiguration;
        this.appUploaderThreadPool = appUploaderThreadPool;
    }

    @Override
    public AsyncExecutionState execute(ProcessContext context) {
        CloudApplicationExtended applicationToProcess = context.getVariable(Variables.APP_TO_PROCESS);
        if (context.getVariable(Variables.SHOULD_SKIP_APPLICATION_UPLOAD)) {
            context.getStepLogger()
                   .debug(Messages.SKIPPING_UPLOAD_OF_APPLICATION_0, applicationToProcess.getName());
            return AsyncExecutionState.FINISHED;
        }
        if (context.getVariable(Variables.UPLOAD_START_TIME) == null) {
            context.setVariable(Variables.UPLOAD_START_TIME, LocalDateTime.now());
        }
        ApplicationToUploadContext applicationToUploadContext = buildApplicationToUploadContext(context, applicationToProcess);
        CloudControllerClient client = context.getControllerClient();
        Future runningUpload;
        try {
            runningUpload = appUploaderThreadPool.submit(() -> doUpload(context, applicationToProcess, applicationToUploadContext));
        } catch (RejectedExecutionException rejectedExecutionException) {
            LOGGER.warn(rejectedExecutionException.getMessage(), rejectedExecutionException);
            context.getStepLogger()
                   .warn(Messages.UPLOAD_OF_APPLICATION_0_WAS_NOT_ACCEPTED_BY_INSTANCE_1, applicationToProcess.getName(),
                         applicationConfiguration.getApplicationInstanceIndex());
            return AsyncExecutionState.RUNNING;
        }
        CloudPackage cloudPackage;
        try {
            cloudPackage = runningUpload.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new SLException(e, e.getMessage());
        }
        LocalDateTime startTime = context.getVariable(Variables.UPLOAD_START_TIME);
        long timeElapsedForUpload = Duration.between(startTime, LocalDateTime.now())
                                            .toMillis();
        context.getStepLogger()
               .infoWithoutProgressMessage(Messages.TIME_ELAPSED_FOR_UPLOAD_0_IN_MILLIS, timeElapsedForUpload);
        return processCloudPackage(context, client, cloudPackage);
    }

    private ApplicationToUploadContext buildApplicationToUploadContext(ProcessContext context,
                                                                       CloudApplicationExtended applicationToProcess) {
        MtaArchiveElements mtaArchiveElements = context.getVariable(Variables.MTA_ARCHIVE_ELEMENTS);
        return ImmutableApplicationToUploadContext.builder()
                                                  .application(applicationToProcess)
                                                  .moduleFileName(mtaArchiveElements.getModuleFileName(applicationToProcess.getModuleName()))
                                                  .spaceGuid(context.getVariable(Variables.SPACE_GUID))
                                                  .correlationId(context.getVariable(Variables.CORRELATION_ID))
                                                  .taskId(context.getVariable(Variables.TASK_ID))
                                                  .appArchiveId(context.getRequiredVariable(Variables.APP_ARCHIVE_ID))
                                                  .stepLogger(context.getStepLogger())
                                                  .archiveEntries(context.getVariable(Variables.ARCHIVE_ENTRIES_POSITIONS))
                                                  .build();
    }

    private CloudPackage doUpload(ProcessContext context, CloudApplicationExtended applicationToProcess,
                                  ApplicationToUploadContext applicationToUploadContext) {
        context.getStepLogger()
               .debug(Messages.UPLOAD_OF_APPLICATION_0_STARTED_ON_INSTANCE_1, applicationToProcess.getName(),
                      applicationConfiguration.getApplicationInstanceIndex());
        return proceedWithUpload(context.getControllerClient(), applicationToUploadContext);
    }

    private CloudPackage proceedWithUpload(CloudControllerClient client, ApplicationToUploadContext applicationToUploadContext) {
        applicationToUploadContext.getStepLogger()
                                  .debug(Messages.UPLOADING_FILE_0_FOR_APP_1, applicationToUploadContext.getModuleFileName(),
                                         applicationToUploadContext.getApplication()
                                                                   .getName());
        CloudPackage cloudPackage = asyncUploadFiles(client, applicationToUploadContext);
        applicationToUploadContext.getStepLogger()
                                  .info(Messages.STARTED_ASYNC_UPLOAD_OF_APP_0, applicationToUploadContext.getApplication()
                                                                                                          .getName());
        LOGGER.info(format(Messages.UPLOADED_PACKAGE_0, cloudPackage));
        return cloudPackage;
    }

    private CloudPackage asyncUploadFiles(CloudControllerClient client, ApplicationToUploadContext applicationToUploadContext) {
        Path extractedAppPath = extractApplicationFromArchive(applicationToUploadContext);
        LOGGER.debug(MessageFormat.format(Messages.APPLICATION_WITH_NAME_0_SAVED_TO_1, applicationToUploadContext.getApplication()
                                                                                                                 .getName(),
                                          extractedAppPath));
        applicationToUploadContext.getStepLogger()
                                  .infoWithoutProgressMessage(Messages.SIZE_OF_APP_0_IS_1_BYTES, applicationToUploadContext.getApplication()
                                                                                                                           .getName(),
                                                              extractedAppPath.toFile()
                                                                              .length());
        return upload(client, applicationToUploadContext, extractedAppPath);
    }

    private Path extractApplicationFromArchive(ApplicationToUploadContext applicationToUploadContext) {
        LocalDateTime startTime = LocalDateTime.now();
        Path extractedAppPath = extractFromMtar(createApplicationArchiveContext(applicationToUploadContext,
                                                                                applicationConfiguration.getMaxResourceFileSize()));
        long timeElapsedForUpload = Duration.between(startTime, LocalDateTime.now())
                                            .toMillis();
        applicationToUploadContext.getStepLogger()
                                  .infoWithoutProgressMessage(Messages.TIME_ELAPSED_FOR_APP_BINARY_DOWNLOAD_0_IN_MILLIS,
                                                              timeElapsedForUpload);
        return extractedAppPath;
    }

    protected ApplicationArchiveContext createApplicationArchiveContext(ApplicationToUploadContext applicationToUploadContext,
                                                                        long maxSize) {
        return new ApplicationArchiveContext(applicationToUploadContext.getModuleFileName(),
                                             maxSize,
                                             applicationToUploadContext.getArchiveEntries(),
                                             applicationToUploadContext.getSpaceGuid(),
                                             applicationToUploadContext.getAppArchiveId());
    }

    protected Path extractFromMtar(ApplicationArchiveContext applicationArchiveContext) {
        return applicationZipBuilder.extractApplicationInNewArchive(applicationArchiveContext);
    }

    private CloudPackage upload(CloudControllerClient client, ApplicationToUploadContext applicationToUploadContext,
                                Path extractedModulePath) {
        try {
            return client.asyncUploadApplicationWithExponentialBackoff(applicationToUploadContext.getApplication()
                                                                                                 .getName(),
                                                                       extractedModulePath,
                                                                       getMonitorUploadStatusCallback(applicationToUploadContext.getApplication(),
                                                                                                      extractedModulePath,
                                                                                                      applicationToUploadContext.getStepLogger(),
                                                                                                      applicationToUploadContext.getCorrelationId(),
                                                                                                      applicationToUploadContext.getTaskId()),
                                                                       null);
        } catch (Exception e) {
            FileUtils.cleanUp(extractedModulePath, LOGGER);
            throw new SLException(e,
                                  Messages.ERROR_WHILE_STARTING_ASYNC_UPLOAD_OF_APP_WITH_NAME_0,
                                  applicationToUploadContext.getApplication()
                                                            .getName());
        }
    }

    private AsyncExecutionState processCloudPackage(ProcessContext context, CloudControllerClient client, CloudPackage cloudPackage) {
        CloudApplication cloudApp = client.getApplication(context.getVariable(Variables.APP_TO_PROCESS)
                                                                 .getName());
        if (context.getVariable(Variables.SHOULD_UPDATE_APPLICATION_DIGEST)) {
            var appEnv = client.getApplicationEnvironment(cloudApp.getGuid());
            String newApplicationDigest = context.getVariable(Variables.CALCULATED_APPLICATION_DIGEST);
            attemptToUpdateApplicationDigest(client, cloudApp, appEnv, newApplicationDigest);
        }
        context.setVariable(Variables.CLOUD_PACKAGE, cloudPackage);
        context.setVariable(Variables.APP_CONTENT_CHANGED, true);
        return AsyncExecutionState.FINISHED;
    }

    private void attemptToUpdateApplicationDigest(CloudControllerClient client, CloudApplication app, Map appEnv,
                                                  String newApplicationDigest) {
        new ApplicationEnvironmentUpdater(app, appEnv, client).updateApplicationEnvironment(Constants.ENV_DEPLOY_ATTRIBUTES,
                                                                                            Constants.ATTR_APP_CONTENT_DIGEST,
                                                                                            newApplicationDigest);
    }

    @Override
    public String getPollingErrorMessage(ProcessContext context) {
        CloudApplicationExtended appToProcess = context.getVariable(Variables.APP_TO_PROCESS);
        return MessageFormat.format(Messages.ERROR_OCCURRED_DURING_APPLICATION_UPLOAD_0, appToProcess.getName());
    }

    MonitorUploadStatusCallback getMonitorUploadStatusCallback(CloudApplication app, Path file, StepLogger stepLogger, String correlationId,
                                                               String taskId) {
        return new MonitorUploadStatusCallback(app, file, stepLogger, correlationId, taskId);
    }

    class MonitorUploadStatusCallback implements UploadStatusCallbackExtended {

        private final CloudApplication app;
        private final Path file;
        private final StepLogger stepLogger;
        private final String correlationId;
        private final String taskId;

        public MonitorUploadStatusCallback(CloudApplication app, Path file, StepLogger stepLogger, String correlationId, String taskId) {
            this.app = app;
            this.file = file;
            this.stepLogger = stepLogger;
            this.correlationId = correlationId;
            this.taskId = taskId;
        }

        @Override
        public void onCheckResources() {
            stepLogger.debug("Resources checked");
        }

        @Override
        public void onMatchedFileNames(Set matchedFileNames) {
            stepLogger.debug(Messages.MATCHED_FILES_COUNT_0, matchedFileNames.size());
        }

        @Override
        public void onProcessMatchedResources(int length) {
            stepLogger.debug(Messages.MATCHED_RESOURCES_PROCESSED_TOTAL_SIZE_0, length);
        }

        @Override
        public boolean onProgress(String status) {
            stepLogger.debug(Messages.UPLOAD_STATUS_0, status);
            if (status.equals(Status.READY.toString())) {
                FileUtils.cleanUp(file, LOGGER);
                processLoggerPersister.persistLogs(correlationId, taskId);
            }
            return false;
        }

        @Override
        public void onError(Exception e) {
            stepLogger.error(e, Messages.ERROR_UPLOADING_APP_0, app.getName());
            FileUtils.cleanUp(file, LOGGER);
        }

        @Override
        public void onError(String description) {
            stepLogger.error(Messages.ERROR_UPLOADING_APP_0_STATUS_1_DESCRIPTION_2, app.getName(), Status.FAILED, description);
            FileUtils.cleanUp(file, LOGGER);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy