Search in sources :

Example 21 with ProcessResult

use of io.hops.hopsworks.common.util.ProcessResult in project hopsworks by logicalclocks.

the class LibraryInstaller method uninstallLibrary.

private void uninstallLibrary(CondaCommands cc) throws IOException, ServiceDiscoveryException, ProjectException, ServiceException, PythonException {
    File baseDir = new File("/tmp/docker/" + cc.getProjectId().getName());
    baseDir.mkdirs();
    try {
        File dockerFile = new File(baseDir, "dockerFile_" + cc.getProjectId().getName());
        File home = new File(System.getProperty("user.home"));
        FileUtils.copyFileToDirectory(new File(home, ".condarc"), baseDir);
        FileUtils.copyDirectoryToDirectory(new File(home, ".pip"), baseDir);
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(dockerFile))) {
            writer.write("# syntax=docker/dockerfile:experimental");
            writer.newLine();
            writer.write("FROM " + projectUtils.getFullDockerImageName(cc.getProjectId(), false) + "\n");
            writer.newLine();
            writer.write("RUN --mount=type=bind,source=.condarc,target=/root/.condarc" + " --mount=type=bind,source=.pip,target=/root/.pip ");
            switch(cc.getInstallType()) {
                case CONDA:
                    writer.write(anaconda_dir + "/bin/conda remove -y -n " + settings.getCurrentCondaEnvironment() + " " + cc.getLib() + " || true\n");
                    break;
                case PIP:
                    writer.write(anaconda_project_dir + "/bin/pip uninstall -y " + cc.getLib() + " || true\n");
                    break;
                case ENVIRONMENT:
                default:
                    throw new UnsupportedOperationException("install type unknown: " + cc.getInstallType());
            }
        }
        Project project = projectFacade.findById(cc.getProjectId().getId()).orElseThrow(() -> new ProjectException(RESTCodes.ProjectErrorCode.PROJECT_NOT_FOUND, Level.FINE, "projectId: " + cc.getProjectId().getId()));
        String nextDockerImageName = getNextDockerImageName(project);
        ProcessDescriptor processDescriptor = new ProcessDescriptor.Builder().addCommand("/usr/bin/sudo").addCommand(prog).addCommand("create").addCommand(dockerFile.getAbsolutePath()).addCommand(projectUtils.getRegistryURL() + "/" + nextDockerImageName).redirectErrorStream(true).setCurrentWorkingDirectory(baseDir).setWaitTimeout(30, TimeUnit.MINUTES).build();
        ProcessResult processResult = osProcessExecutor.execute(processDescriptor);
        if (processResult.getExitCode() != 0) {
            String errorMsg = "Could not create the docker image. Exit code: " + processResult.getExitCode() + " out: " + processResult.getStdout() + "\n err: " + processResult.getStderr() + "||\n";
            throw new IOException(errorMsg);
        } else {
            project = projectFacade.findById(cc.getProjectId().getId()).orElseThrow(() -> new ProjectException(RESTCodes.ProjectErrorCode.PROJECT_NOT_FOUND, Level.FINE, "projectId: " + cc.getProjectId().getId()));
            project.setDockerImage(nextDockerImageName);
            project = projectFacade.update(project);
            projectFacade.flushEm();
            setPipConflicts(project);
            environmentController.updateInstalledDependencies(project);
            exportEnvironment(project, cc.getUserId(), Utils.getProjectPath(project.getName()) + Settings.PROJECT_PYTHON_ENVIRONMENT_FILE);
        }
    } finally {
        FileUtils.deleteDirectory(baseDir);
    }
}
Also used : ProjectException(io.hops.hopsworks.exceptions.ProjectException) Project(io.hops.hopsworks.persistence.entity.project.Project) FileWriter(java.io.FileWriter) ProcessResult(io.hops.hopsworks.common.util.ProcessResult) ProcessDescriptor(io.hops.hopsworks.common.util.ProcessDescriptor) IOException(java.io.IOException) File(java.io.File) BufferedWriter(java.io.BufferedWriter)

Example 22 with ProcessResult

use of io.hops.hopsworks.common.util.ProcessResult in project hopsworks by logicalclocks.

the class LibraryInstaller method installLibrary.

private void installLibrary(CondaCommands cc) throws IOException, ServiceException, ServiceDiscoveryException, ProjectException, UserException, PythonException {
    File baseDir = new File("/tmp/docker/" + cc.getProjectId().getName());
    baseDir.mkdirs();
    Project project = projectFacade.findById(cc.getProjectId().getId()).orElseThrow(() -> new ProjectException(RESTCodes.ProjectErrorCode.PROJECT_NOT_FOUND, Level.FINE, "projectId: " + cc.getProjectId().getId()));
    ArrayList<String> dockerBuildOpts = new ArrayList<>();
    dockerBuildOpts.add(DOCKER_HOST_NETWORK_OPT);
    try {
        File home = new File(System.getProperty("user.home"));
        File condarc = new File(home, ".condarc");
        File pip = new File(home, ".pip");
        FileUtils.copyFileToDirectory(condarc, baseDir);
        FileUtils.copyDirectoryToDirectory(pip, baseDir);
        File dockerFile = new File(baseDir, "dockerFile_" + cc.getProjectId().getName());
        String apiToken = null;
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(dockerFile))) {
            writer.write("# syntax=docker/dockerfile:experimental");
            writer.newLine();
            writer.write("FROM " + projectUtils.getFullDockerImageName(project, false));
            writer.newLine();
            writer.write("RUN --mount=type=bind,source=.condarc,target=/root/.condarc" + " --mount=type=bind,source=.pip,target=/root/.pip ");
            switch(cc.getInstallType()) {
                case CONDA:
                    String condaLib;
                    if (cc.getVersion().equals(Settings.UNKNOWN_LIBRARY_VERSION)) {
                        condaLib = cc.getLib();
                        dockerBuildOpts.add(DOCKER_NO_CACHE_OPT);
                    } else {
                        condaLib = cc.getLib() + "=" + cc.getVersion();
                    }
                    writer.write(anaconda_dir + "/bin/conda install -y -n " + settings.getCurrentCondaEnvironment() + " -c " + cc.getChannelUrl() + " " + condaLib);
                    break;
                case PIP:
                    String pipLib;
                    if (cc.getVersion().equals(Settings.UNKNOWN_LIBRARY_VERSION)) {
                        pipLib = cc.getLib();
                        dockerBuildOpts.add(DOCKER_NO_CACHE_OPT);
                    } else {
                        pipLib = cc.getLib() + "==" + cc.getVersion();
                    }
                    writer.write(anaconda_project_dir + "/bin/pip install --upgrade " + pipLib);
                    break;
                case EGG:
                    String eggName = cc.getLib();
                    String localEggPath = baseDir + File.separator + eggName;
                    copyCondaArtifactToLocal(cc.getArg(), localEggPath);
                    writer.write("--mount=type=bind,source=" + eggName + ",target=/root/" + eggName + " ");
                    writer.write(anaconda_project_dir + "/bin/easy_install --upgrade /root/" + eggName);
                    break;
                case WHEEL:
                    String wheelName = cc.getLib();
                    String localWheelPath = baseDir + File.separator + wheelName;
                    copyCondaArtifactToLocal(cc.getArg(), localWheelPath);
                    writer.write("--mount=type=bind,source=" + wheelName + ",target=/root/" + wheelName + " ");
                    writer.write(anaconda_project_dir + "/bin/pip install --upgrade /root/" + wheelName);
                    break;
                case REQUIREMENTS_TXT:
                    String requirementsName = cc.getLib();
                    String localRequirementsName = baseDir + File.separator + requirementsName;
                    copyCondaArtifactToLocal(cc.getArg(), localRequirementsName);
                    writer.write("--mount=type=bind,source=" + requirementsName + ",target=/root/" + requirementsName + " ");
                    writer.write(anaconda_project_dir + "/bin/pip install -r /root/" + requirementsName);
                    break;
                case ENVIRONMENT_YAML:
                    String environmentsName = cc.getLib();
                    String localEnvironmentsName = baseDir + File.separator + environmentsName;
                    copyCondaArtifactToLocal(cc.getArg(), localEnvironmentsName);
                    writer.write("--mount=type=bind,source=" + environmentsName + ",target=/root/" + environmentsName + " ");
                    writer.write(anaconda_dir + "/bin/conda env update -f /root/" + environmentsName + " -n " + settings.getCurrentCondaEnvironment());
                    break;
                case GIT:
                    if (cc.getGitBackend() != null && cc.getGitApiKeyName() != null) {
                        apiToken = this.secretsController.get(cc.getUserId(), cc.getGitApiKeyName()).getPlaintext();
                        URL repoUrl = new URL(cc.getArg());
                        if (cc.getGitBackend().equals(GitBackend.GITHUB)) {
                            writer.write(anaconda_project_dir + "/bin/pip install --upgrade 'git+https://" + apiToken + ":x-oauth-basic@" + repoUrl.getHost() + repoUrl.getPath() + "'");
                        } else if (cc.getGitBackend().equals(GitBackend.GITLAB)) {
                            writer.write(anaconda_project_dir + "/bin/pip install --upgrade 'git+https://oauth2:" + apiToken + "@" + repoUrl.getHost() + repoUrl.getPath() + "'");
                        }
                    } else {
                        writer.write(anaconda_project_dir + "/bin/pip install --upgrade 'git+" + cc.getArg() + "'");
                    }
                    dockerBuildOpts.add(DOCKER_NO_CACHE_OPT);
                    break;
                case ENVIRONMENT:
                default:
                    throw new UnsupportedOperationException("install type unknown: " + cc.getInstallType());
            }
            // Installing faulty libraries like broken .egg files can cause the list operation to fail
            // As we find library names and versions using that command we need to make sure it does not break
            writer.write(" && " + getCleanupCommand() + " && " + anaconda_dir + "/bin/conda list -n " + settings.getCurrentCondaEnvironment());
        }
        String nextDockerImageName = getNextDockerImageName(project);
        LOG.log(Level.FINEST, "project-nextDockerImageName:" + nextDockerImageName);
        ProcessDescriptor processDescriptor = new ProcessDescriptor.Builder().addCommand("/usr/bin/sudo").addCommand(prog).addCommand("create").addCommand(dockerFile.getAbsolutePath()).addCommand(projectUtils.getRegistryURL() + "/" + nextDockerImageName).addCommand("'" + String.join(" ", dockerBuildOpts) + "'").redirectErrorStream(true).setCurrentWorkingDirectory(baseDir).setWaitTimeout(1, TimeUnit.HOURS).build();
        ProcessResult processResult = osProcessExecutor.execute(processDescriptor);
        if (processResult.getExitCode() != 0) {
            // Avoid leeking the apitoken in the error logs by replacing it with the name
            if (cc.getInstallType().equals(CondaInstallType.GIT) && !Strings.isNullOrEmpty(apiToken)) {
                String errorMsg = "Could not create the docker image. Exit code: " + processResult.getExitCode();
                String stdout = processResult.getStdout();
                if (stdout != null) {
                    errorMsg = errorMsg + " out: " + stdout.replaceAll(apiToken, cc.getGitApiKeyName() + "_token");
                }
                String stderr = processResult.getStderr();
                if (stderr != null) {
                    errorMsg = errorMsg + "\n err: " + stderr.replaceAll(apiToken, cc.getGitApiKeyName() + "_token");
                }
                errorMsg = errorMsg + "||\n";
                throw new IOException(errorMsg);
            } else {
                String errorMsg = "Could not create the docker image. Exit code: " + processResult.getExitCode() + " out: " + processResult.getStdout() + "\n err: " + processResult.getStderr() + "||\n";
                throw new IOException(errorMsg);
            }
        } else {
            project = projectFacade.findById(cc.getProjectId().getId()).orElseThrow(() -> new ProjectException(RESTCodes.ProjectErrorCode.PROJECT_NOT_FOUND, Level.FINE, "projectId: " + cc.getProjectId().getId()));
            project.setDockerImage(nextDockerImageName);
            project = projectFacade.update(project);
            projectFacade.flushEm();
            setPipConflicts(project);
            environmentController.updateInstalledDependencies(project);
            exportEnvironment(project, cc.getUserId(), Utils.getProjectPath(project.getName()) + Settings.PROJECT_PYTHON_ENVIRONMENT_FILE);
        }
    } finally {
        FileUtils.deleteDirectory(baseDir);
    }
}
Also used : FileWriter(java.io.FileWriter) ArrayList(java.util.ArrayList) ProcessResult(io.hops.hopsworks.common.util.ProcessResult) IOException(java.io.IOException) URL(java.net.URL) BufferedWriter(java.io.BufferedWriter) ProjectException(io.hops.hopsworks.exceptions.ProjectException) Project(io.hops.hopsworks.persistence.entity.project.Project) ProcessDescriptor(io.hops.hopsworks.common.util.ProcessDescriptor) File(java.io.File)

Example 23 with ProcessResult

use of io.hops.hopsworks.common.util.ProcessResult in project hopsworks by logicalclocks.

the class JupyterController method convertIPythonNotebook.

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public String convertIPythonNotebook(String hdfsUsername, String notebookPath, Project project, String pyPath, NotebookConversion notebookConversion) throws ServiceException {
    File baseDir = new File(settings.getStagingDir() + settings.CONVERSION_DIR);
    if (!baseDir.exists()) {
        baseDir.mkdir();
    }
    File conversionDir = new File(baseDir, DigestUtils.sha256Hex(Integer.toString(ThreadLocalRandom.current().nextInt())));
    conversionDir.mkdir();
    HdfsUsers user = hdfsUsersFacade.findByName(hdfsUsername);
    try {
        String prog = settings.getSudoersDir() + "/convert-ipython-notebook.sh";
        ProcessDescriptor processDescriptor = new ProcessDescriptor.Builder().addCommand("/usr/bin/sudo").addCommand(prog).addCommand(notebookPath).addCommand(hdfsUsername).addCommand(settings.getAnacondaProjectDir()).addCommand(pyPath).addCommand(conversionDir.getAbsolutePath()).addCommand(notebookConversion.name()).addCommand(projectUtils.getFullDockerImageName(project, true)).setWaitTimeout(60l, // on a TLS VM the timeout needs to be greater than 20s
        TimeUnit.SECONDS).redirectErrorStream(true).build();
        LOGGER.log(Level.FINE, processDescriptor.toString());
        certificateMaterializer.materializeCertificatesLocalCustomDir(user.getUsername(), project.getName(), conversionDir.getAbsolutePath());
        ProcessResult processResult = osProcessExecutor.execute(processDescriptor);
        if (!processResult.processExited() || processResult.getExitCode() != 0) {
            LOGGER.log(Level.WARNING, "error code: " + processResult.getExitCode(), "Failed to convert " + notebookPath + "\nstderr: " + processResult.getStderr() + "\nstdout: " + processResult.getStdout());
            throw new ServiceException(RESTCodes.ServiceErrorCode.IPYTHON_CONVERT_ERROR, Level.SEVERE, "error code: " + processResult.getExitCode(), "Failed to convert " + notebookPath + "\nstderr: " + processResult.getStderr() + "\nstdout: " + processResult.getStdout());
        }
        String stdOut = processResult.getStdout();
        if (!Strings.isNullOrEmpty(stdOut) && notebookConversion.equals(NotebookConversion.HTML)) {
            StringBuilder renderedNotebookSB = new StringBuilder(stdOut);
            int startIndex = renderedNotebookSB.indexOf("<html>");
            int stopIndex = renderedNotebookSB.length();
            return renderedNotebookSB.substring(startIndex, stopIndex);
        }
        return null;
    } catch (IOException | ServiceDiscoveryException ex) {
        throw new ServiceException(RESTCodes.ServiceErrorCode.IPYTHON_CONVERT_ERROR, Level.SEVERE, null, ex.getMessage(), ex);
    } finally {
        certificateMaterializer.removeCertificatesLocalCustomDir(user.getUsername(), project.getName(), conversionDir.getAbsolutePath());
    }
}
Also used : ServiceException(io.hops.hopsworks.exceptions.ServiceException) ClientBuilder(javax.ws.rs.client.ClientBuilder) ProcessResult(io.hops.hopsworks.common.util.ProcessResult) ProcessDescriptor(io.hops.hopsworks.common.util.ProcessDescriptor) ServiceDiscoveryException(com.logicalclocks.servicediscoverclient.exceptions.ServiceDiscoveryException) IOException(java.io.IOException) File(java.io.File) HdfsUsers(io.hops.hopsworks.persistence.entity.hdfs.user.HdfsUsers) TransactionAttribute(javax.ejb.TransactionAttribute)

Example 24 with ProcessResult

use of io.hops.hopsworks.common.util.ProcessResult in project hopsworks by logicalclocks.

the class LocalHostJupyterProcessMgr method executeJupyterCommand.

private int executeJupyterCommand(String... args) {
    if (args == null || args.length == 0) {
        return -99;
    }
    int exitValue;
    Integer id = 1;
    String prog = settings.getSudoersDir() + "/jupyter.sh";
    ProcessDescriptor.Builder pdBuilder = new ProcessDescriptor.Builder().addCommand("/usr/bin/sudo").addCommand(prog);
    for (String arg : args) {
        pdBuilder.addCommand(arg);
    }
    pdBuilder.setWaitTimeout(20L, TimeUnit.SECONDS);
    if (!LOGGER.isLoggable(Level.FINE)) {
        pdBuilder.ignoreOutErrStreams(true);
    }
    try {
        ProcessResult processResult = osProcessExecutor.execute(pdBuilder.build());
        LOGGER.log(Level.FINE, processResult.getStdout());
        exitValue = processResult.getExitCode();
    } catch (IOException ex) {
        LOGGER.log(Level.SEVERE, "Problem checking if Jupyter Notebook server is running: {0}", ex);
        exitValue = -2;
    }
    return exitValue;
}
Also used : URIBuilder(org.apache.http.client.utils.URIBuilder) ProcessResult(io.hops.hopsworks.common.util.ProcessResult) ProcessDescriptor(io.hops.hopsworks.common.util.ProcessDescriptor) IOException(java.io.IOException)

Aggregations

ProcessDescriptor (io.hops.hopsworks.common.util.ProcessDescriptor)24 ProcessResult (io.hops.hopsworks.common.util.ProcessResult)24 IOException (java.io.IOException)22 File (java.io.File)9 TransactionAttribute (javax.ejb.TransactionAttribute)5 ServiceException (io.hops.hopsworks.exceptions.ServiceException)4 ProjectException (io.hops.hopsworks.exceptions.ProjectException)3 ServingException (io.hops.hopsworks.exceptions.ServingException)3 Project (io.hops.hopsworks.persistence.entity.project.Project)3 BufferedWriter (java.io.BufferedWriter)3 FileWriter (java.io.FileWriter)3 Path (java.nio.file.Path)3 ServiceDiscoveryException (com.logicalclocks.servicediscoverclient.exceptions.ServiceDiscoveryException)2 CompressionInfo (io.hops.hopsworks.common.dataset.util.CompressionInfo)2 DatasetException (io.hops.hopsworks.exceptions.DatasetException)2 JobException (io.hops.hopsworks.exceptions.JobException)2 PythonException (io.hops.hopsworks.exceptions.PythonException)2 TensorBoardException (io.hops.hopsworks.exceptions.TensorBoardException)2 FileNotFoundException (java.io.FileNotFoundException)2 URISyntaxException (java.net.URISyntaxException)2