fr.treeptik.cloudunit.service.impl.FileServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for fr.treeptik.cloudunit.service.impl.FileServiceImpl.java

Source

/*
 * LICENCE : CloudUnit is available under the GNU Affero General Public License : https://gnu.org/licenses/agpl.html
 * but CloudUnit is licensed too under a standard commercial license.
 * Please contact our sales team if you would like to discuss the specifics of our Enterprise license.
 * If you are not sure whether the AGPL is right for you,
 * you can always test our software under the AGPL and inspect the source code before you contact us
 * about purchasing a commercial license.
 *
 * LEGAL TERMS : "CloudUnit" is a registered trademark of Treeptik and can't be used to endorse
 * or promote products derived from this project without prior written permission from Treeptik.
 * Products or services derived from this software may not be called "CloudUnit"
 * nor may "Treeptik" or similar confusing terms appear in their names without prior written permission.
 * For any questions, contact us : contact@treeptik.fr
 */

package fr.treeptik.cloudunit.service.impl;

import com.google.common.collect.Lists;
import com.spotify.docker.client.*;
import com.spotify.docker.client.messages.Container;
import fr.treeptik.cloudunit.dto.FileUnit;
import fr.treeptik.cloudunit.dto.LogLine;
import fr.treeptik.cloudunit.dto.SourceUnit;
import fr.treeptik.cloudunit.exception.CheckException;
import fr.treeptik.cloudunit.exception.ServiceException;
import fr.treeptik.cloudunit.filters.explorer.ExplorerFactory;
import fr.treeptik.cloudunit.filters.explorer.ExplorerFilter;
import fr.treeptik.cloudunit.model.Application;
import fr.treeptik.cloudunit.model.Module;
import fr.treeptik.cloudunit.model.Server;
import fr.treeptik.cloudunit.service.ApplicationService;
import fr.treeptik.cloudunit.service.FileService;
import fr.treeptik.cloudunit.service.ModuleService;
import fr.treeptik.cloudunit.service.ServerService;
import fr.treeptik.cloudunit.utils.AuthentificationUtils;
import fr.treeptik.cloudunit.utils.FilesUtils;
import fr.treeptik.cloudunit.utils.ShellUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.io.File;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Service for file management into container
 * Created by nicolas on 20/05/15.
 */
@Service
public class FileServiceImpl implements FileService {

    private Logger logger = LoggerFactory.getLogger(FileServiceImpl.class);

    @Inject
    private AuthentificationUtils authentificationUtils;

    @Inject
    private ApplicationService applicationService;

    @Inject
    private ShellUtils shellUtils;

    @Inject
    private ModuleService moduleService;

    @Inject
    private ServerService serverService;

    @Value("${docker.manager.ip:192.168.50.4:2376}")
    private String dockerManagerIp;

    @Value("${certs.dir.path}")
    private String certsDirPath;

    @Value("${docker.endpoint.mode}")
    private String dockerEndpointMode;

    private boolean isHttpMode;

    @PostConstruct
    public void initDockerEndPointMode() {
        if ("http".equalsIgnoreCase(dockerEndpointMode)) {
            logger.warn("Docker TLS mode is disabled");
            isHttpMode = true;
        } else {
            isHttpMode = false;
        }
    }

    /**
     * File Explorer Feature
     *
     * Delete all resources (files and folders) for an application + container +
     * path.
     *
     * @param applicationName
     * @param containerId
     * @param path
     * @throws ServiceException
     */
    public void deleteFilesFromContainer(String applicationName, String containerId, String path)
            throws ServiceException {
        try {
            DockerClient docker = null;
            if (isHttpMode) {
                docker = DefaultDockerClient.builder().uri("http://" + dockerManagerIp).build();
            } else {
                final DockerCertificates certs = new DockerCertificates(Paths.get(certsDirPath));
                docker = DefaultDockerClient.builder().uri("https://" + dockerManagerIp).dockerCertificates(certs)
                        .build();
            }
            List<Container> containers = docker.listContainers();
            for (Container container : containers) {
                if (container.id().substring(0, 12).equals(containerId) == false) {
                    continue;
                }
                final String[] command = { "bash", "-c", "rm -rf " + path };
                String containerName = container.names().get(0);
                String execId = docker.execCreate(containerName, command, DockerClient.ExecParameter.STDOUT,
                        DockerClient.ExecParameter.STDERR);
                final LogStream output = docker.execStart(execId);
                if (output != null) {
                    output.close();
                }
            }
        } catch (DockerException | InterruptedException | DockerCertificateException e) {
            throw new ServiceException("Error in listByContainerIdAndPath", e);
        }
    }

    /**
     * Logs Display Feature
     *
     * List the files into the Log directory
     *
     * @param containerId
     * @return
     * @throws ServiceException
     */
    public List<SourceUnit> listLogsFilesByContainer(String containerId) throws ServiceException {

        List<SourceUnit> files = new ArrayList<>();
        try {
            DockerClient docker = null;
            if (Boolean.valueOf(isHttpMode)) {
                docker = DefaultDockerClient.builder().uri("http://" + dockerManagerIp).build();
            } else {
                final DockerCertificates certs = new DockerCertificates(Paths.get(certsDirPath));
                docker = DefaultDockerClient.builder().uri("https://" + dockerManagerIp).dockerCertificates(certs)
                        .build();
            }
            List<Container> containers = docker.listContainers();
            for (Container container : containers) {
                if (container.id().substring(0, 12).equals(containerId) == false) {
                    continue;
                }
                String logDirectory = getLogDirectory(containerId);
                // Exec command inside running container with attached STDOUT
                // and STDERR
                final String[] command = { "bash", "-c", "find " + logDirectory + " -type f ! -size 0 " };
                String execId;

                String containerName = container.names().get(0);
                if (containerName.startsWith("/"))
                    containerName = containerName.substring(1);
                execId = docker.execCreate(containerName, command, DockerClient.ExecParameter.STDOUT,
                        DockerClient.ExecParameter.STDERR);
                ExplorerFilter filter = ExplorerFactory.getInstance().getCustomFilter(containerName);
                final LogStream output = docker.execStart(execId);
                final String execOutput = output.readFully();
                if (execOutput != null && execOutput.contains("cannot access") == false) {

                    if (logger.isDebugEnabled()) {
                        logger.debug(execOutput);
                    }

                    StringTokenizer lignes = new StringTokenizer(execOutput, "\n");

                    while (lignes.hasMoreTokens()) {
                        String name = lignes.nextToken();
                        name = name.substring(name.lastIndexOf("/") + 1);
                        SourceUnit sourceUnit = new SourceUnit(name);
                        files.add(sourceUnit);
                    }
                    output.close();
                }
            }
        } catch (DockerException | InterruptedException | DockerCertificateException e) {
            throw new ServiceException("Error in listByContainerIdAndPath", e);
        }

        return files;
    }

    /**
     * Logs Display Feature
     *
     * List the files and folder for a container
     *
     * @param containerId
     * @return
     * @throws ServiceException
     */
    public List<LogLine> catFileForNLines(String containerId, String file, Integer nbRows) throws ServiceException {

        List<LogLine> files = new ArrayList<>();
        try {
            DockerClient docker = null;
            if (Boolean.valueOf(isHttpMode)) {
                docker = DefaultDockerClient.builder().uri("http://" + dockerManagerIp).build();
            } else {
                final DockerCertificates certs = new DockerCertificates(Paths.get(certsDirPath));
                docker = DefaultDockerClient.builder().uri("https://" + dockerManagerIp).dockerCertificates(certs)
                        .build();
            }
            List<Container> containers = docker.listContainers();
            containers = containers.stream()
                    .filter(container1 -> container1.id().substring(0, 12).equalsIgnoreCase(containerId))
                    .collect(Collectors.toList());
            for (Container container : containers) {
                String logDirectory = getLogDirectory(containerId);
                // Exec command inside running container with attached STDOUT
                // and STDERR
                final String[] command = { "bash", "-c", "tail -n " + nbRows + " /cloudunit/appconf/logs/" + file };
                String execId;
                String containerName = container.names().get(0);
                execId = docker.execCreate(containerName, command, DockerClient.ExecParameter.STDOUT,
                        DockerClient.ExecParameter.STDERR);
                final LogStream output = docker.execStart(execId);
                final String execOutput = output.readFully();
                if (execOutput != null && execOutput.contains("cannot access") == false) {
                    StringTokenizer lignes = new StringTokenizer(execOutput, "\n");
                    while (lignes.hasMoreTokens()) {
                        String line = lignes.nextToken();
                        LogLine logLine = new LogLine(file, line);
                        files.add(logLine);
                    }
                    files = Lists.reverse(files);
                    output.close();
                }
            }
        } catch (DockerException | InterruptedException | DockerCertificateException e) {
            throw new ServiceException("Error in listByContainerIdAndPath", e);
        }

        return files;
    }

    /**
     * File Explorer Feature
     *
     * List the files by Container and Path
     *
     * @param containerId
     * @param path
     * @return
     * @throws ServiceException
     */
    public List<FileUnit> listByContainerIdAndPath(String containerId, String path) throws ServiceException {

        List<FileUnit> files = new ArrayList<>();
        try {

            DockerClient docker = null;
            if (Boolean.valueOf(isHttpMode)) {
                docker = DefaultDockerClient.builder().uri("http://" + dockerManagerIp).build();
            } else {
                final DockerCertificates certs = new DockerCertificates(Paths.get(certsDirPath));
                docker = DefaultDockerClient.builder().uri("https://" + dockerManagerIp).dockerCertificates(certs)
                        .build();
            }
            List<Container> containers = docker.listContainers();
            for (Container container : containers) {
                // b10da42def6c1737c40b981b1692acb24e28414944b4017814713afb811ae51b
                // log.debug(container.id() + " : " + container.names());
                if (container.id().substring(0, 12).equals(containerId) == false) {
                    continue;
                }

                // Exec command inside running container with attached STDOUT
                // and STDERR
                final String[] command = { "bash", "-c", "ls -laF " + path };
                String execId;

                String containerName = container.names().get(0);
                execId = docker.execCreate(containerName, command, DockerClient.ExecParameter.STDOUT,
                        DockerClient.ExecParameter.STDERR);
                ExplorerFilter filter = ExplorerFactory.getInstance().getCustomFilter(containerName);
                final LogStream output = docker.execStart(execId);
                final String execOutput = output.readFully();
                if (execOutput != null && execOutput.contains("cannot access") == false) {

                    if (logger.isDebugEnabled()) {
                        logger.debug(execOutput);
                    }

                    StringTokenizer lignes = new StringTokenizer(execOutput, "\n");
                    while (lignes.hasMoreTokens()) {
                        String ligne = lignes.nextToken();
                        if (logger.isDebugEnabled()) {
                            logger.debug(ligne);
                        }
                        if (ligne.startsWith("total"))
                            continue;
                        StringTokenizer fields = new StringTokenizer(ligne, " ");
                        String rights = fields.nextToken();
                        String id = fields.nextToken();
                        String user = fields.nextToken();
                        String group = fields.nextToken();
                        String size = fields.nextToken();
                        String month = fields.nextToken();
                        String day = fields.nextToken();
                        String hour = fields.nextToken();
                        String name = fields.nextToken();
                        boolean dir = false;
                        boolean exec = false;
                        if (name.endsWith("/")) {
                            dir = true;
                            name = name.substring(0, name.length() - 1);
                        } else {
                            boolean isNotAuth = FilesUtils.isNotAuthorizedExtension(name);
                            if (isNotAuth) {
                                continue;
                            }
                        }
                        if (name.endsWith("*")) {
                            exec = true;
                            name = name.substring(0, name.length() - 1);
                        }
                        StringBuilder absolutePath = new StringBuilder(128);
                        absolutePath.append(path.replaceAll("__", "/").replaceAll("//", "/")).append(name);

                        if (name.equalsIgnoreCase("."))
                            continue;
                        if (name.equalsIgnoreCase(".."))
                            continue;

                        FileUnit fileUnit = new FileUnit(name, user, day, month, hour, false, dir, exec,
                                absolutePath.toString());

                        if (filter.isValid(fileUnit)) {
                            // Add test to know if resource is removable or not
                            filter.isRemovable(fileUnit);
                            // add test to know if resource is saved or not
                            // during cloning
                            filter.isSafe(fileUnit);
                            // we add the file to explorer ui
                            files.add(fileUnit);
                        }
                    }
                    if (output != null) {
                        output.close();
                    }
                }

            }
        } catch (DockerException | InterruptedException | DockerCertificateException e) {
            throw new ServiceException("Error in listByContainerIdAndPath", e);
        }

        return files;
    }

    /**
     * File Explorer feature
     *
     * Send a file into a container
     *
     * @param applicationName
     * @param containerId
     * @param file
     * @param originalName
     * @param destFile
     * @throws ServiceException
     */
    @Override
    public void sendFileToContainer(String applicationName, String containerId, File file, String originalName,
            String destFile) throws ServiceException {

        Application application;
        try {
            application = applicationService.findByNameAndUser(authentificationUtils.getAuthentificatedUser(),
                    applicationName);
            Map<String, String> configShell = new HashMap<>();

            String sshPort = application.getSShPortByContainerId(containerId);
            String rootPassword = application.getUser().getPassword();
            configShell.put("port", sshPort);
            configShell.put("dockerManagerAddress", application.getManagerIp());
            configShell.put("password", rootPassword);

            // send the file on container
            shellUtils.sendFile(file, rootPassword, sshPort, application.getManagerIp(),
                    convertDestPathFile(destFile));
            /*
             * dporter ce script dans le container (au plus au niveau)
            * 
            * renommer le fichier sur place et met les droits au user
            */

            shellUtils.executeShell("mv " + convertDestPathFile(destFile) + file.getName() + " "
                    + convertDestPathFile(destFile) + originalName + " && chown "
                    + authentificationUtils.getAuthentificatedUser().getLogin() + ":"
                    + authentificationUtils.getAuthentificatedUser().getLogin() + " "
                    + convertDestPathFile(destFile) + originalName, configShell);
        } catch (ServiceException | CheckException e) {
            throw new ServiceException("error in send file into the container", e);
        }

    }

    /**
     * File Explorer feature
     *
     * Gather a file from a container
     *
     * @param applicationName
     * @param containerId
     * @param file
     * @param originalName
     * @param destFile
     * @return
     * @throws ServiceException
     */
    @Override
    public Optional<File> getFileFromContainer(String applicationName, String containerId, File file,
            String originalName, String destFile) throws ServiceException {

        Application application;
        try {
            application = applicationService.findByNameAndUser(authentificationUtils.getAuthentificatedUser(),
                    applicationName);

            Map<String, String> configShell = new HashMap<>();

            String sshPort = application.getSShPortByContainerId(containerId);
            String rootPassword = application.getUser().getPassword();
            configShell.put("port", sshPort);
            configShell.put("dockerManagerAddress", application.getManagerIp());
            configShell.put("password", rootPassword);

            shellUtils.downloadFile(file, rootPassword, sshPort, application.getManagerIp(),
                    convertDestPathFile(destFile) + originalName);

        } catch (ServiceException | CheckException e) {
            StringBuilder msgError = new StringBuilder();
            msgError.append("applicationName=").append("=").append(applicationName);
            msgError.append(",containerId=").append("=").append(containerId);
            msgError.append(",file.toPath()=").append(file.toPath());
            msgError.append("originalName=").append(originalName);
            msgError.append("destFile=").append(destFile);
            throw new ServiceException(msgError.toString(), e);
        }

        return Optional.of(file);
    }

    ;

    private String convertDestPathFile(String pathFile) {
        return "/" + pathFile.replaceAll("__", "/") + "/";
    }

    private String getLogDirectory(String containerId) throws ServiceException {

        Module module = null;
        Server server = null;
        String location = null;
        try {
            module = moduleService.findByContainerID(containerId);
            server = serverService.findByContainerID(containerId);
            if (module != null) {
                location = module.getModuleAction().getLogLocation();
            }
            if (server != null) {
                location = server.getServerAction().getLogLocation();
            }

        } catch (ServiceException e) {
            throw new ServiceException("error in send file into the container", e);
        }

        return location;
    }

    public String getDefaultLogFile(String containerId) throws ServiceException {
        Module module = null;
        Server server = null;
        String file = null;
        try {
            server = serverService.findByContainerID(containerId);
            if (server != null) {
                file = server.getServerAction().getDefaultLogFile();
            }
        } catch (ServiceException e) {
            throw new ServiceException("error in send file into the container", e);
        }
        return file;
    }

}