package com.hubspot.singularity.executor.task; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import org.slf4j.Logger; import com.google.common.collect.ImmutableList; import com.hubspot.singularity.executor.config.SingularityExecutorConfiguration; import com.hubspot.singularity.executor.utils.DockerUtils; import com.hubspot.singularity.runner.base.shared.ExceptionChainParser; import com.hubspot.singularity.runner.base.shared.SimpleProcessManager; import com.spotify.docker.client.ContainerNotFoundException; import com.spotify.docker.client.DockerException; import com.spotify.docker.client.messages.ContainerInfo; public class SingularityExecutorTaskCleanup { private final SingularityExecutorTaskDefinition taskDefinition; private final SingularityExecutorTaskLogManager taskLogManager; private final SingularityExecutorConfiguration configuration; private final Logger log; private final DockerUtils dockerUtils; public SingularityExecutorTaskCleanup(SingularityExecutorTaskLogManager taskLogManager, SingularityExecutorConfiguration configuration, SingularityExecutorTaskDefinition taskDefinition, Logger log, DockerUtils dockerUtils) { this.configuration = configuration; this.taskLogManager = taskLogManager; this.taskDefinition = taskDefinition; this.log = log; this.dockerUtils = dockerUtils; } public TaskCleanupResult cleanup(boolean cleanupTaskAppDirectory, boolean isDocker) { final Path taskDirectory = Paths.get(taskDefinition.getTaskDirectory()); boolean dockerCleanSuccess = true; if (isDocker) { try { String containerName = String.format("%s%s", configuration.getDockerPrefix(), taskDefinition.getTaskId()); ContainerInfo containerInfo = dockerUtils.inspectContainer(containerName); if (containerInfo.state().running()) { dockerUtils.stopContainer(containerName, configuration.getDockerStopTimeout()); } dockerUtils.removeContainer(containerName, true); } catch (DockerException e) { if (ExceptionChainParser.exceptionChainContains(e, ContainerNotFoundException.class)) { log.trace("Container for task {} was already removed", taskDefinition.getTaskId()); } else { log.error("Could not ensure removal of container", e); dockerCleanSuccess = false; } } catch (Exception e) { log.error("Could not ensure removal of container", e); dockerCleanSuccess = false; } } if (!Files.exists(taskDirectory)) { log.info("Directory {} didn't exist for cleanup", taskDirectory); taskLogManager.removeLogrotateFile(); return finishTaskCleanup(dockerCleanSuccess); } boolean logTearDownSuccess = taskLogManager.teardown(); if (!cleanupTaskAppDirectory) { log.info("Not finishing cleanup because taskApp directory is being preserved"); return TaskCleanupResult.WAITING; } boolean cleanupTaskAppDirectorySuccess = cleanupTaskAppDirectory(); log.info("Cleaned up logs ({}) and task app directory ({})", logTearDownSuccess, cleanupTaskAppDirectorySuccess); if (logTearDownSuccess && cleanupTaskAppDirectorySuccess) { return finishTaskCleanup(dockerCleanSuccess); } else { return TaskCleanupResult.ERROR; } } private TaskCleanupResult finishTaskCleanup(boolean dockerCleanSuccess) { boolean cleanTaskDefinitionFile = cleanTaskDefinitionFile(); if (cleanTaskDefinitionFile && dockerCleanSuccess) { return TaskCleanupResult.SUCCESS; } return TaskCleanupResult.ERROR; } public boolean cleanTaskDefinitionFile() { Path taskDefinitionPath = configuration.getTaskDefinitionPath(taskDefinition.getTaskId()); log.info("Successful cleanup, deleting file {}", taskDefinitionPath); try { boolean deleted = Files.deleteIfExists(taskDefinitionPath); log.info("File deleted ({})", deleted); return true; } catch (IOException e) { log.error("Failed deleting {}", taskDefinitionPath, e); return false; } } private boolean cleanupTaskAppDirectory() { final String pathToDelete = taskDefinition.getTaskAppDirectory(); log.info("Deleting: {}", pathToDelete); try { final List<String> cmd = ImmutableList.of( "rm", "-rf", pathToDelete ); new SimpleProcessManager(log).runCommand(cmd); return true; } catch (Throwable t) { log.error("While deleting directory {}", pathToDelete, t); } return false; } }