Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/reference/cluster/stats.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ Will return, for example:
"count": 1
}
],
"pretty_names": [
{
"pretty_name": "Mac OS X",
"count": 1
}
],
"mem" : {
"total" : "16gb",
"total_in_bytes" : 17179869184,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.elasticsearch.monitor.os;

import org.apache.lucene.util.Constants;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.test.ESTestCase;

import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.hamcrest.Matchers.equalTo;

public class EvilOsProbeTests extends ESTestCase {

public void testOsPrettyName() throws IOException {
final OsInfo osInfo = OsProbe.getInstance().osInfo(randomLongBetween(1, 100), randomIntBetween(1, 8));
if (Constants.LINUX) {
final List<String> lines = Files.readAllLines(PathUtils.get("/etc/os-release"));
for (final String line : lines) {
if (line != null && line.startsWith("PRETTY_NAME=")) {
final Matcher matcher = Pattern.compile("PRETTY_NAME=(\"?|'?)?([^\"']+)\\1").matcher(line);
assert matcher.matches() : line;
final String prettyName = matcher.group(2);
assertThat(osInfo.getPrettyName(), equalTo(prettyName));
return;
}
}
assertThat(osInfo.getPrettyName(), equalTo("Linux"));
} else {
assertThat(osInfo.getPrettyName(), equalTo(Constants.OS_NAME));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,15 @@ public static class OsStats implements ToXContentFragment {
final int availableProcessors;
final int allocatedProcessors;
final ObjectIntHashMap<String> names;
final ObjectIntHashMap<String> prettyNames;
final org.elasticsearch.monitor.os.OsStats.Mem mem;

/**
* Build the stats from information about each node.
*/
private OsStats(List<NodeInfo> nodeInfos, List<NodeStats> nodeStatsList) {
this.names = new ObjectIntHashMap<>();
this.prettyNames = new ObjectIntHashMap<>();
int availableProcessors = 0;
int allocatedProcessors = 0;
for (NodeInfo nodeInfo : nodeInfos) {
Expand All @@ -242,6 +244,9 @@ private OsStats(List<NodeInfo> nodeInfos, List<NodeStats> nodeStatsList) {
if (nodeInfo.getOs().getName() != null) {
names.addTo(nodeInfo.getOs().getName(), 1);
}
if (nodeInfo.getOs().getPrettyName() != null) {
prettyNames.addTo(nodeInfo.getOs().getPrettyName(), 1);
}
}
this.availableProcessors = availableProcessors;
this.allocatedProcessors = allocatedProcessors;
Expand Down Expand Up @@ -280,6 +285,8 @@ static final class Fields {
static final String ALLOCATED_PROCESSORS = "allocated_processors";
static final String NAME = "name";
static final String NAMES = "names";
static final String PRETTY_NAME = "pretty_name";
static final String PRETTY_NAMES = "pretty_names";
static final String COUNT = "count";
}

Expand All @@ -289,11 +296,27 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params)
builder.field(Fields.AVAILABLE_PROCESSORS, availableProcessors);
builder.field(Fields.ALLOCATED_PROCESSORS, allocatedProcessors);
builder.startArray(Fields.NAMES);
for (ObjectIntCursor<String> name : names) {
builder.startObject();
builder.field(Fields.NAME, name.key);
builder.field(Fields.COUNT, name.value);
builder.endObject();
{
for (ObjectIntCursor<String> name : names) {
builder.startObject();
{
builder.field(Fields.NAME, name.key);
builder.field(Fields.COUNT, name.value);
}
builder.endObject();
}
}
builder.endArray();
builder.startArray(Fields.PRETTY_NAMES);
{
for (final ObjectIntCursor<String> prettyName : prettyNames) {
builder.startObject();
{
builder.field(Fields.PRETTY_NAME, prettyName.key);
builder.field(Fields.COUNT, prettyName.value);
}
builder.endObject();
}
}
builder.endArray();
mem.toXContent(builder, params);
Expand Down
29 changes: 0 additions & 29 deletions server/src/main/java/org/elasticsearch/monitor/os/DummyOsInfo.java

This file was deleted.

29 changes: 27 additions & 2 deletions server/src/main/java/org/elasticsearch/monitor/os/OsInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@

package org.elasticsearch.monitor.os;

import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent.Params;
import org.elasticsearch.common.xcontent.ToXContentFragment;
import org.elasticsearch.common.xcontent.XContentBuilder;

Expand All @@ -35,14 +35,23 @@ public class OsInfo implements Writeable, ToXContentFragment {
private final int availableProcessors;
private final int allocatedProcessors;
private final String name;
private final String prettyName;
private final String arch;
private final String version;

public OsInfo(long refreshInterval, int availableProcessors, int allocatedProcessors, String name, String arch, String version) {
public OsInfo(
final long refreshInterval,
final int availableProcessors,
final int allocatedProcessors,
final String name,
final String prettyName,
final String arch,
final String version) {
this.refreshInterval = refreshInterval;
this.availableProcessors = availableProcessors;
this.allocatedProcessors = allocatedProcessors;
this.name = name;
this.prettyName = prettyName;
this.arch = arch;
this.version = version;
}
Expand All @@ -52,6 +61,11 @@ public OsInfo(StreamInput in) throws IOException {
this.availableProcessors = in.readInt();
this.allocatedProcessors = in.readInt();
this.name = in.readOptionalString();
if (in.getVersion().onOrAfter(Version.V_7_0_0)) {
this.prettyName = in.readOptionalString();
} else {
this.prettyName = null;
}
this.arch = in.readOptionalString();
this.version = in.readOptionalString();
}
Expand All @@ -62,6 +76,9 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeInt(availableProcessors);
out.writeInt(allocatedProcessors);
out.writeOptionalString(name);
if (out.getVersion().onOrAfter(Version.V_7_0_0)) {
out.writeOptionalString(prettyName);
}
out.writeOptionalString(arch);
out.writeOptionalString(version);
}
Expand All @@ -82,6 +99,10 @@ public String getName() {
return name;
}

public String getPrettyName() {
return prettyName;
}

public String getArch() {
return arch;
}
Expand All @@ -93,6 +114,7 @@ public String getVersion() {
static final class Fields {
static final String OS = "os";
static final String NAME = "name";
static final String PRETTY_NAME = "pretty_name";
static final String ARCH = "arch";
static final String VERSION = "version";
static final String REFRESH_INTERVAL = "refresh_interval";
Expand All @@ -108,6 +130,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
if (name != null) {
builder.field(Fields.NAME, name);
}
if (prettyName != null) {
builder.field(Fields.PRETTY_NAME, prettyName);
}
if (arch != null) {
builder.field(Fields.ARCH, arch);
}
Expand Down
69 changes: 65 additions & 4 deletions server/src/main/java/org/elasticsearch/monitor/os/OsProbe.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

package org.elasticsearch.monitor.os;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.util.Constants;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.io.PathUtils;
Expand All @@ -36,6 +36,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

public class OsProbe {

Expand Down Expand Up @@ -519,9 +521,68 @@ public static OsProbe getInstance() {

private final Logger logger = LogManager.getLogger(getClass());

public OsInfo osInfo(long refreshInterval, int allocatedProcessors) {
return new OsInfo(refreshInterval, Runtime.getRuntime().availableProcessors(),
allocatedProcessors, Constants.OS_NAME, Constants.OS_ARCH, Constants.OS_VERSION);
OsInfo osInfo(long refreshInterval, int allocatedProcessors) throws IOException {
return new OsInfo(
refreshInterval,
Runtime.getRuntime().availableProcessors(),
allocatedProcessors,
Constants.OS_NAME,
getPrettyName(),
Constants.OS_ARCH,
Constants.OS_VERSION);
}

private String getPrettyName() throws IOException {
// TODO: return a prettier name on non-Linux OS
if (Constants.LINUX) {
/*
* We read the lines from /etc/os-release (or /usr/lib/os-release) to extract the PRETTY_NAME. The format of this file is
* newline-separated key-value pairs. The key and value are separated by an equals symbol (=). The value can unquoted, or
* wrapped in single- or double-quotes.
*/
final List<String> etcOsReleaseLines = readOsRelease();
final List<String> prettyNameLines =
etcOsReleaseLines.stream().filter(line -> line.startsWith("PRETTY_NAME")).collect(Collectors.toList());
assert prettyNameLines.size() <= 1 : prettyNameLines;
final Optional<String> maybePrettyNameLine =
prettyNameLines.size() == 1 ? Optional.of(prettyNameLines.get(0)) : Optional.empty();
if (maybePrettyNameLine.isPresent()) {
final String prettyNameLine = maybePrettyNameLine.get();
final String[] prettyNameFields = prettyNameLine.split("=");
assert prettyNameFields.length == 2 : prettyNameLine;
if (prettyNameFields[1].length() >= 3 &&
(prettyNameFields[1].startsWith("\"") && prettyNameFields[1].endsWith("\"")) ||
(prettyNameFields[1].startsWith("'") && prettyNameFields[1].endsWith("'"))) {
return prettyNameFields[1].substring(1, prettyNameFields[1].length() - 1);
} else {
return prettyNameFields[1];
}
} else {
return Constants.OS_NAME;
}

} else {
return Constants.OS_NAME;
}
}

/**
* The lines from {@code /etc/os-release} or {@code /usr/lib/os-release} as a fallback. These file represents identification of the
* underlying operating system. The structure of the file is newlines of key-value pairs of shell-compatible variable assignments.
*
* @return the lines from {@code /etc/os-release} or {@code /usr/lib/os-release}
* @throws IOException if an I/O exception occurs reading {@code /etc/os-release} or {@code /usr/lib/os-release}
*/
@SuppressForbidden(reason = "access /etc/os-release or /usr/lib/os-release")
List<String> readOsRelease() throws IOException {
final List<String> lines;
if (Files.exists(PathUtils.get("/etc/os-release"))) {
lines = Files.readAllLines(PathUtils.get("/etc/os-release"));
} else {
lines = Files.readAllLines(PathUtils.get("/usr/lib/os-release"));
}
assert lines != null && lines.isEmpty() == false;
return lines;
}

public OsStats osStats() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.elasticsearch.common.util.SingleObjectCache;
import org.elasticsearch.common.util.concurrent.EsExecutors;

import java.io.IOException;

public class OsService extends AbstractComponent {

private final OsProbe probe;
Expand All @@ -37,7 +39,7 @@ public class OsService extends AbstractComponent {
Setting.timeSetting("monitor.os.refresh_interval", TimeValue.timeValueSeconds(1), TimeValue.timeValueSeconds(1),
Property.NodeScope);

public OsService(Settings settings) {
public OsService(Settings settings) throws IOException {
this.probe = OsProbe.getInstance();
TimeValue refreshInterval = REFRESH_INTERVAL_SETTING.get(settings);
this.info = probe.osInfo(refreshInterval.millis(), EsExecutors.numberOfProcessors(settings));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ grant {
// read max virtual memory areas
permission java.io.FilePermission "/proc/sys/vm/max_map_count", "read";

// OS release on Linux
permission java.io.FilePermission "/etc/os-release", "read";
permission java.io.FilePermission "/usr/lib/os-release", "read";

// io stats on Linux
permission java.io.FilePermission "/proc/self/mountinfo", "read";
permission java.io.FilePermission "/proc/diskstats", "read";
Expand Down
Loading