/*
* Copyright (c) 2013 Technische Universitat Wien (TUW), Distributed Systems Group. http://dsg.tuwien.ac.at
*
* This work was partially supported by the European Commission in terms of the CELAR FP7 project (FP7-ICT-2011-8 #317790), http://www.celarcloud.eu/
*
* Licensed 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 at.ac.tuwien.dsg.cloud.salsa.engine.utils;
import java.io.File;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.Query;
import javax.management.ReflectionException;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
public class SystemFunctions {
private final static File envFileGlobal = new File("/etc/environment");
private static final Logger logger = EngineLogger.logger;
static private String localIP = null;
public static String getEth0IPAddress() {
if (localIP != null) {
logger.debug("Return local IP address:" + localIP);
return localIP;
}
// copy the getEth0IPv4 to /tmp and execute it, return the value
URL inputUrl = SystemFunctions.class.getResource("/scripts/getEth0IPv4.sh");
EngineLogger.logger.debug("Search script: " + inputUrl);
File dest = new File("/tmp/getEth0IPv4.sh");
try {
FileUtils.copyURLToFile(inputUrl, dest);
} catch (IOException ex) {
EngineLogger.logger.error("Cannot create template script file from: " + inputUrl + " to: " + dest.getPath());
}
localIP = executeCommandGetOutput("/bin/bash /tmp/getEth0IPv4.sh", "/tmp", null);
localIP = localIP.trim();
if (isIPv4Address(localIP)) {
logger.debug("The {} is IPv4 !", localIP);
return localIP;
} else {
logger.debug("Cannot get IPv4, the command return: {}", localIP);
localIP = null;
return "localhost";
}
}
public static boolean isIPv4Address(String address) {
if (address.isEmpty()) {
return false;
}
try {
Object res = InetAddress.getByName(address);
return (res.getClass().equals(Inet4Address.class));
} catch (final UnknownHostException ex) {
logger.error("Cannot get the host IP address. The captured address is: {}. Error: {}", address, ex.getMessage());
return false;
}
}
public static void executeCommandSimple(String cmd, String workingDir) {
logger.debug("Running command: {} in folder: {}", cmd, workingDir);
Process p;
try {
String newCmd = "cd " + workingDir + " && " + cmd;
logger.debug("The whole command to execute: {}", newCmd);
p = Runtime.getRuntime().exec(newCmd);
p.waitFor();
} catch (IOException | InterruptedException ex) {
logger.error("Error when run command: {}", cmd, ex);
}
}
public static int executeCommandGetReturnCode(String cmd, String workingDir, String executeFrom) {
if (workingDir == null) {
workingDir = "/tmp";
}
logger.debug("Execute command: " + cmd + ". Working dir: " + workingDir);
try {
String[] splitStr = cmd.split("\\s+");
ProcessBuilder pb = new ProcessBuilder(splitStr);
pb.directory(new File(workingDir));
pb = pb.redirectErrorStream(true); // this is important to redirect the error stream to output stream, prevent blocking with long output
Map<String, String> env = pb.environment();
String path = env.get("PATH");
path = path + File.pathSeparator + "/usr/bin:/usr/sbin";
logger.debug("PATH to execute command: " + pb.environment().get("PATH"));
env.put("PATH", path);
Process p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
logger.debug(line);
}
p.waitFor();
int returnCode = p.exitValue();
logger.debug("Execute command done: " + cmd + ". Get return code: " + returnCode);
return returnCode;
} catch (InterruptedException | IOException e1) {
logger.error("Error when execute command. Error: " + e1);
}
return -1;
}
/**
* Run a command and wait
*
* @param cmd The command to run
* @param workingDir The folder where the command is run
* @param executeFrom For logging message to the center of where to execute the command.
* @return
*/
public static String executeCommandGetOutput(String cmd, String workingDir, String executeFrom) {
logger.debug("Execute command: " + cmd);
if (workingDir == null) {
workingDir = "/tmp";
}
try {
String[] splitStr = cmd.split("\\s+");
ProcessBuilder pb = new ProcessBuilder(splitStr);
pb.directory(new File(workingDir));
pb = pb.redirectErrorStream(true); // this is important to redirect the error stream to output stream, prevent blocking with long output
Map<String, String> env = pb.environment();
String path = env.get("PATH");
path = path + File.pathSeparator + "/usr/bin:/usr/sbin";
logger.debug("PATH to execute command: " + pb.environment().get("PATH"));
env.put("PATH", path);
Process p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
StringBuffer output = new StringBuffer();
int lineCount = 0;
while ((line = reader.readLine()) != null) {
// if (lineCount < 10) { // only get 10 lines to prevent the overflow
output.append(line+"\n");
// }
lineCount += 1;
// logger.debug(line);
}
// if (lineCount >= 10) {
// logger.debug("... there are alot of more output here which is not shown ! ...");
// }
p.waitFor();
System.out.println("Execute Command output: " + output.toString().trim());
if (p.exitValue() == 0) {
logger.debug("Command exit 0, result: " + output.toString().trim());
} else {
logger.debug("Command return non zero code: " + p.exitValue());
}
logger.debug("The output of the command contains {} character. Some first chars:", output.length(), output.substring(0, Math.min(output.length(), 50)));
return output.toString().trim();
} catch (InterruptedException | IOException e1) {
logger.error("Error when execute command. Error: " + e1);
return null;
}
}
/**
* Run a command and wait
*
* @param cmd The command to run
* @param workingDir The folder where the command is run
* @param executeFrom For logging message to the center of where to execute the command.
* @return
*/
public static Process executeCommandAndForget(String cmd, String workingDir, String executeFrom) {
logger.debug("Execute command: " + cmd);
if (workingDir == null) {
workingDir = "/tmp";
}
String[] splitStr = cmd.split("\\s+");
ProcessBuilder pb = new ProcessBuilder(splitStr);
pb.directory(new File(workingDir));
pb = pb.redirectErrorStream(true); // this is important to redirect the error stream to output stream, prevent blocking with long output
pb.redirectOutput(new File("/tmp/salsa.conductor.log"));
Map<String, String> env = pb.environment();
String path = env.get("PATH");
path = path + File.pathSeparator + "/usr/bin:/usr/sbin";
logger.debug("PATH to execute command: " + pb.environment().get("PATH"));
env.put("PATH", path);
Process p;
try {
p = pb.start();
return p;
} catch (IOException ex) {
logger.debug("Cannot run the command: " + cmd);
return null;
}
}
public static List<String> getEndPoints() throws MalformedObjectNameException,
NullPointerException, UnknownHostException, AttributeNotFoundException,
InstanceNotFoundException, MBeanException, ReflectionException {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> objs = mbs.queryNames(new ObjectName("*:type=Connector,*"),
Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));
String hostname = InetAddress.getLocalHost().getHostName();
InetAddress[] addresses = InetAddress.getAllByName(hostname);
ArrayList<String> endPoints = new ArrayList<>();
for (Iterator<ObjectName> i = objs.iterator(); i.hasNext();) {
ObjectName obj = i.next();
String scheme = mbs.getAttribute(obj, "scheme").toString();
String port = obj.getKeyProperty("port");
for (InetAddress addr : addresses) {
String host = addr.getHostAddress();
String ep = scheme + "://" + host + ":" + port;
endPoints.add(ep);
}
}
return endPoints;
}
/**
* This command try to get Port which the service is listening to. The port should be in the parameter -httpPort when running, or Tomcat port
*
* @return
*/
public static String getPort() {
try {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> objs = mbs.queryNames(new ObjectName("*:type=Connector,*"),
Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));
for (ObjectName obj : objs) {
String port = obj.getKeyProperty("port");
return port;
}
} catch (MalformedObjectNameException e) {
EngineLogger.logger.error("Cannot get listening port of salsa-engine service. return 8080 as default. Error: " + e.toString());
}
EngineLogger.logger.error("Cannot find listening port of salsa-engine service. return 8080 as default");
return "8080";
}
}