blob: f7a8355f826b7264f26620e09d59b8e355d9264e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF 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 org.apache.geode.management.internal.cli.functions;
import static org.apache.geode.internal.lang.SystemUtils.getOsArchitecture;
import static org.apache.geode.internal.lang.SystemUtils.getOsName;
import static org.apache.geode.internal.lang.SystemUtils.getOsVersion;
import static org.apache.geode.internal.lang.SystemUtils.isLinux;
import static org.apache.geode.internal.lang.SystemUtils.isMacOSX;
import static org.apache.geode.internal.lang.SystemUtils.isSolaris;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.Logger;
import org.apache.geode.annotations.Immutable;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.internal.cache.execute.InternalFunction;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.management.internal.cli.CliUtil;
import org.apache.geode.management.internal.cli.CliUtil.DeflaterInflaterData;
import org.apache.geode.management.internal.cli.GfshParser;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
/**
* Executes 'netstat' OS command & returns the result as compressed bytes.
*
* @since GemFire 7.0
*/
@SuppressWarnings({"serial"})
public class NetstatFunction implements InternalFunction {
private static final Logger logger = LogService.getLogger();
private static final long serialVersionUID = 1L;
@Immutable
public static final NetstatFunction INSTANCE = new NetstatFunction();
private static final String ID = NetstatFunction.class.getName();
private static final String NETSTAT_COMMAND = "netstat";
private static final String LSOF_COMMAND = "lsof";
@Override
public boolean hasResult() {
return true;
}
@Override
public void execute(final FunctionContext context) {
DistributedSystem ds = InternalDistributedSystem.getConnectedInstance();
if (ds == null || !ds.isConnected()) {
return;
}
String host = ds.getDistributedMember().getHost();
NetstatFunctionArgument args = (NetstatFunctionArgument) context.getArguments();
boolean withlsof = args.isWithlsof();
String lineSeparator = args.getLineSeparator();
String netstatOutput = executeCommand(lineSeparator, withlsof);
StringBuilder netstatInfo = new StringBuilder();
// {0} will be replaced on Manager
addMemberHostHeader(netstatInfo, "{0}", host, lineSeparator);
NetstatFunctionResult result = new NetstatFunctionResult(host, netstatInfo.toString(),
CliUtil.compressBytes(netstatOutput.getBytes()));
context.getResultSender().lastResult(result);
}
private static void addMemberHostHeader(final StringBuilder netstatInfo, final String id,
final String host, final String lineSeparator) {
String osInfo = getOsName() + " " + getOsVersion() + " " + getOsArchitecture();
StringBuilder memberPlatFormInfo = new StringBuilder();
memberPlatFormInfo.append(CliStrings.format(CliStrings.NETSTAT__MSG__FOR_HOST_1_OS_2_MEMBER_0,
new Object[] {id, host, osInfo, lineSeparator}));
int nameIdLength = Math.max(Math.max(id.length(), host.length()), osInfo.length()) * 2;
StringBuilder netstatInfoBottom = new StringBuilder();
for (int i = 0; i < nameIdLength; i++) {
netstatInfo.append("#");
netstatInfoBottom.append("#");
}
netstatInfo.append(lineSeparator).append(memberPlatFormInfo.toString()).append(lineSeparator)
.append(netstatInfoBottom.toString()).append(lineSeparator);
}
private static void addNetstatDefaultOptions(final List<String> cmdOptionsList) {
cmdOptionsList.add("-v");
cmdOptionsList.add("-a");
cmdOptionsList.add("-n");
if (isLinux()) {
cmdOptionsList.add("-e");
}
}
private static void executeNetstat(final StringBuilder netstatInfo, final String lineSeparator) {
List<String> cmdOptionsList = new ArrayList<>();
cmdOptionsList.add(NETSTAT_COMMAND);
addNetstatDefaultOptions(cmdOptionsList);
if (logger.isDebugEnabled()) {
logger.debug("NetstatFunction executing {}", cmdOptionsList);
}
ProcessBuilder processBuilder = new ProcessBuilder(cmdOptionsList);
try {
Process netstat = processBuilder.start();
InputStream is = netstat.getInputStream();
BufferedReader breader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = breader.readLine()) != null) {
netstatInfo.append(line).append(lineSeparator);
}
// TODO: move to finally-block
netstat.destroy();
} catch (IOException e) {
// TODO: change this to keep the full stack trace
netstatInfo.append(CliStrings.format(CliStrings.NETSTAT__MSG__COULD_NOT_EXECUTE_0_REASON_1,
new Object[] {NETSTAT_COMMAND, e.getMessage()}));
} finally {
netstatInfo.append(lineSeparator); // additional new line
}
}
private static void executeLsof(final StringBuilder existingNetstatInfo,
final String lineSeparator) {
existingNetstatInfo.append("################ ").append(LSOF_COMMAND)
.append(" output ###################").append(lineSeparator);
if (isLinux() || isMacOSX() || isSolaris()) {
List<String> cmdOptionsList = new ArrayList<>();
cmdOptionsList.add(LSOF_COMMAND);
cmdOptionsList.add("-n");
cmdOptionsList.add("-P");
ProcessBuilder procBuilder = new ProcessBuilder(cmdOptionsList);
try {
Process lsof = procBuilder.start();
InputStreamReader reader = new InputStreamReader(lsof.getInputStream());
BufferedReader breader = new BufferedReader(reader);
String line = "";
while ((line = breader.readLine()) != null) {
existingNetstatInfo.append(line).append(lineSeparator);
}
// TODO: move this to finally-block
lsof.destroy();
} catch (IOException e) {
// TODO: change this to keep the full stack trace
String message = e.getMessage();
if (message.contains("error=2, No such file or directory")) {
existingNetstatInfo
.append(CliStrings.format(CliStrings.NETSTAT__MSG__COULD_NOT_EXECUTE_0_REASON_1,
new Object[] {LSOF_COMMAND, CliStrings.NETSTAT__MSG__LSOF_NOT_IN_PATH}));
} else {
existingNetstatInfo
.append(CliStrings.format(CliStrings.NETSTAT__MSG__COULD_NOT_EXECUTE_0_REASON_1,
new Object[] {LSOF_COMMAND, e.getMessage()}));
}
} finally {
existingNetstatInfo.append(lineSeparator); // additional new line
}
} else {
existingNetstatInfo.append(CliStrings.NETSTAT__MSG__NOT_AVAILABLE_FOR_WINDOWS)
.append(lineSeparator);
}
}
private static String executeCommand(final String lineSeparator, final boolean withlsof) {
StringBuilder netstatInfo = new StringBuilder();
executeNetstat(netstatInfo, lineSeparator);
if (withlsof) {
executeLsof(netstatInfo, lineSeparator);
}
return netstatInfo.toString();
}
@Override
public String getId() {
return ID;
}
@Override
public boolean optimizeForWrite() {
return false;
}
@Override
public boolean isHA() {
return false;
}
public static void main(final String[] args) {
String netstat = executeCommand(GfshParser.LINE_SEPARATOR, true);
System.out.println(netstat);
}
public static class NetstatFunctionArgument implements Serializable {
private static final long serialVersionUID = 1L;
private final String lineSeparator;
private final boolean withlsof;
public NetstatFunctionArgument(final String lineSeparator, final boolean withlsof) {
this.lineSeparator = lineSeparator;
this.withlsof = withlsof;
}
public String getLineSeparator() {
return lineSeparator;
}
public boolean isWithlsof() {
return withlsof;
}
}
public static class NetstatFunctionResult implements Serializable {
private static final long serialVersionUID = 1L;
private final String host;
private final String headerInfo;
private final DeflaterInflaterData compressedBytes;
protected NetstatFunctionResult(final String host, final String headerInfo,
final DeflaterInflaterData compressedBytes) {
this.host = host;
this.headerInfo = headerInfo;
this.compressedBytes = compressedBytes;
}
public String getHost() {
return host;
}
public String getHeaderInfo() {
return headerInfo;
}
public DeflaterInflaterData getCompressedBytes() {
return compressedBytes;
}
}
}