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

io.fabric8.utils.Processes Maven / Gradle / Ivy

There is a newer version: 3.0.12
Show newest version
/**
 *  Copyright 2005-2016 Red Hat, Inc.
 *
 *  Red Hat licenses this file to you under the Apache License, version
 *  2.0 (the "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 *  implied.  See the License for the specific language governing
 *  permissions and limitations under the License.
 */
package io.fabric8.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import static java.lang.String.format;

/**
 * Platform, Java and Docker specific process utilities.
 */
public class Processes {
    private static final transient Logger LOG = LoggerFactory.getLogger(Processes.class);

    private static boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows");

    /**
     * Returns true if the given PID is still alive
     */
    public static boolean isProcessAlive(long pid) {
        List processIds = getProcessIds();
        if (processIds.isEmpty()) {
            // we must be on a platform that the PID list doesn't work like windows
            return true;
        }
        return processIds.contains(pid);
    }

    /**
     * Returns the list of current active PIDs
     */
    public static List getProcessIds() {
        if (isWindows) {
            return getProcessIdsWindows();
        } else {
            return getProcessIdsUnix();
        }
    }

    private static List getProcessIdsWindows() {
        String commands = "tasklist /NH";
        String message = commands;
        LOG.debug("Executing commands: " + message);
        List answer = new ArrayList();
        try {
            Process process = Runtime.getRuntime().exec(commands);
            // on windows the tasklist returns memory usage as numbers, so we need to chop the line so we only include
            // the pid numbers
            parseProcesses(process.getInputStream(), answer, message, Filters.trueFilter(), Functions.chopLength(50));
            processErrors(process.getErrorStream(), message);
        } catch (Exception e) {
            LOG.error("Failed to execute process " + "stdin" + " for " +
                    message + ": " + e, e);
        }
        return answer;
    }

    private static List getProcessIdsUnix() {
        String commands = "ps -e";
        String message = commands;
        LOG.debug("Executing commands: " + message);
        List answer = new ArrayList();
        try {
            Process process = Runtime.getRuntime().exec(commands);
            parseProcesses(process.getInputStream(), answer, message, Filters.trueFilter(), null);
            processErrors(process.getErrorStream(), message);
        } catch (Exception e) {
            LOG.error("Failed to execute process " + "stdin" + " for " +
                    message + ": " + e, e);
        }
        return answer;
    }

    /**
     * Returns the list of current active PIDs for any java based process
     * that has a main class which contains any of the given bits of text
     */
    public static List getJavaProcessIds(String... classNameFilter) {
        String commands = "jps -l";
        String message = commands;
        LOG.debug("Executing commands: " + message);
        List answer = new ArrayList();
        Filter filter = Filters.containsAnyString(classNameFilter);
        try {
            Process process = Runtime.getRuntime().exec(commands);
            parseProcesses(process.getInputStream(), answer, message, filter, null);
            processErrors(process.getErrorStream(), message);
        } catch (Exception e) {
            LOG.error("Failed to execute process " + "stdin" + " for " +
                    message + ": " + e, e);
        }
        return answer;
    }

    /**
     * Kills all commonly created Java based processes created by fabric8 and its unit tests.
     *
     * This is handy for unit testing to ensure there's no stray karaf, wildfly, tomcat or java containers running.
     */
    public static int killJavaProcesses() {
        return killJavaProcesses("karaf", "jboss", "catalina", "spring.Main", "FabricSpringApplication");
    }

    /**
     * Kills all java processes found which include the classNameFilter in their main class
     */
    public static int killJavaProcesses(String... classNameFilters) {
        int count = 0;
        List javaProcessIds = getJavaProcessIds(classNameFilters);
        for (Long processId : javaProcessIds) {
            // lets log to the console too as this tends to show up in the junit output
            System.out.println("WARNING: Killing Java process " + processId);
            LOG.warn("Killing Java process " + processId);
            killProcess(processId, "-9");
            count++;
        }
        return count;
    }

    /**
     * Returns a list of active docker containers
     */
    public static List getDockerContainerIds() {
        String commands = "docker ps -q";
        String message = "output of command: " + commands;
        LOG.debug("Executing commands: " + message);
        final List answer = new ArrayList<>();
        try {
            Process process = Runtime.getRuntime().exec(commands);
            Function fn = new Function() {
                @Override
                public Void apply(String line) {
                    if (Strings.isNotBlank(line)) {
                        answer.add(line.trim());
                    }
                    return null;
                }
            };
            processOutput(process.getInputStream(), fn, message);
            processErrors(process.getErrorStream(), message);
        } catch (Exception e) {
            LOG.error("Failed to execute process " + "stdin" + " for " +
                    message + ": " + e, e);
        }
        return answer;
    }

    /**
     * Returns a list of active docker containers
     */
    public static int killDockerContainer(String containerId) {
        // lets log to the console too as this tends to show up in the junit output
        System.out.println("Killing Docker container " + containerId);
        LOG.warn("WARNING: Killing Docker container " + containerId);

        String commands = "docker kill " + containerId;
        String message =commands;
        LOG.debug("Executing commands: " + message);
        final List answer = new ArrayList<>();
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(commands);
            processInput(process.getInputStream(), commands);
            processErrors(process.getErrorStream(), commands);
        } catch (Exception e) {
            LOG.error("Failed to execute process " + "stdin" + " for " +
                    message + ": " + e, e);
        }
        return process != null ? process.exitValue() : -1;
    }

    /**
     * Kills all docker containers on the current host
     */
    public static void killDockerContainers() {
        // lets run this in a background thread in case the command blocks due to the docker daemon not running
        new Thread(new Runnable() {

            @Override
            public void run() {
                int count = 0;
                List ids = getDockerContainerIds();
                for (String id : ids) {
                    if (killDockerContainer(id) == 0) {
                        count++;
                    }
                }
            }
        }).run();
    }

    /**
     * Attempts to kill the given process
     */
    public static int killProcess(Long pid, String params) {
        if (pid == null || !isProcessAlive(pid)) {
            return 0;
        }

        if (isWindows) {
            if ("-9".equals(params)) {
                params = "/F";
            }
            return killProcessWindows(pid, params);
        } else {
            return killProcessUnix(pid, params);
        }
    }

    protected static int killProcessWindows(Long pid, String params) {
        String commands = "taskkill " + (params != null ? params + " " : "") + "/PID " + pid;
        Process process = null;
        Runtime runtime = Runtime.getRuntime();
        LOG.debug("Executing commands: " + commands);
        try {
            process = runtime.exec(commands);
            processInput(process.getInputStream(), commands);
            processErrors(process.getErrorStream(), commands);
        } catch (Exception e) {
            LOG.error("Failed to execute process " + "stdin" + " for " +
                    commands + ": " + e, e);
        }
        try {
            return process != null ? process.waitFor() : 1;
        } catch (InterruptedException e) {
            String message = format("Interrupted while waiting for 'taskkill /PID %d ' command to finish", pid);
            throw new RuntimeException(message, e);
        }
    }

    protected static int killProcessUnix(Long pid, String params) {
        String commands = "kill " + (params != null ? params + " " : "") + pid;
        Process process = null;
        Runtime runtime = Runtime.getRuntime();
        LOG.debug("Executing commands: " + commands);
        try {
            process = runtime.exec(commands);
            processInput(process.getInputStream(), commands);
            processErrors(process.getErrorStream(), commands);
        } catch (Exception e) {
            LOG.error("Failed to execute process " + "stdin" + " for " +
                    commands + ": " + e, e);
        }
        try {
            return process != null ? process.waitFor() : 1;
        } catch (InterruptedException e) {
            String message = format("Interrupted while waiting for 'kill %d ' command to finish", pid);
            throw new RuntimeException(message, e);
        }
    }

    protected static void parseProcesses(InputStream inputStream, List answer, String message,
                                         Filter lineFilter, Function preFunction) throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        try {
            while (true) {
                String line = reader.readLine();
                if (line == null) break;
                if (preFunction != null) {
                    line = preFunction.apply(line);
                }
                if (lineFilter.matches(line)) {
                    StringTokenizer tokenizer = new StringTokenizer(line);
                    boolean found = false;
                    // find the first number which is the pid
                    while (tokenizer.hasMoreTokens() && !found) {
                        String pidText = tokenizer.nextToken();
                        try {
                            long pid = Long.parseLong(pidText);
                            answer.add(pid);
                            found = true;
                        } catch (NumberFormatException e) {
                            LOG.debug("Could not parse pid " + pidText + " from command: " + message);
                        }
                    }
                }
            }

        } catch (Exception e) {
            LOG.debug("Failed to process stdin for " + message + ": " + e, e);
            throw e;
        } finally {
            Closeables.closeQuietly(reader);
        }
    }

    protected static void processInput(InputStream inputStream, String message) throws Exception {
        readProcessOutput(inputStream, "stdout for ", message);
    }

    protected static void processErrors(InputStream inputStream, String message) throws Exception {
        readProcessOutput(inputStream, "stderr for ", message);
    }

    protected static void readProcessOutput(InputStream inputStream, final String prefix, final String message) throws Exception {
        Function function = new Function() {
            @Override
            public Void apply(String line) {
                LOG.debug("Error " + prefix + message + ": " + line);
                return null;
            }
        };
        processOutput(inputStream, function, prefix + message);
    }

    protected static void processOutput(InputStream inputStream, Function function, String errrorMessage) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        try {
            while (true) {
                String line = reader.readLine();
                if (line == null) break;
                function.apply(line);
            }

        } catch (Exception e) {
            LOG.error("Failed to process " + errrorMessage + ": " + e, e);
            throw e;
        } finally {
            Closeables.closeQuietly(reader);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy