This is an automated email from the ASF dual-hosted git repository.
yqm pushed a commit to branch 35.0.0
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/35.0.0 by this push:
new c19faee7697 Add labels to sys.server (#18547)
c19faee7697 is described below
commit c19faee7697453ae28f22d8d8ea31a22ee93cfd9
Author: Gabriel Chang <[email protected]>
AuthorDate: Sat Oct 11 10:21:14 2025 +0800
Add labels to sys.server (#18547)
---
docs/configuration/index.md | 7 +++
docs/querying/sql-metadata-tables.md | 1 +
.../apache/druid/testsEx/config/Initializer.java | 2 +-
.../druid/testing/guice/DruidTestModule.java | 2 +-
.../results/auth_test_sys_schema_servers.json | 6 ++-
.../java/util/common/jackson/JacksonUtils.java | 12 +++++
.../java/org/apache/druid/server/DruidNode.java | 32 +++++++++---
.../druid/discovery/DiscoveryDruidNodeTest.java | 12 +++--
.../org/apache/druid/server/DruidNodeTest.java | 40 ++++++++++-----
.../druid/sql/calcite/schema/SystemSchema.java | 25 ++++++---
.../druid/sql/calcite/schema/SystemSchemaTest.java | 60 ++++++++++++++--------
web-console/src/react-table/react-table-extra.scss | 6 +++
.../__snapshots__/services-view.spec.tsx.snap | 13 ++++-
.../src/views/services-view/services-view.scss | 10 ++++
.../src/views/services-view/services-view.tsx | 31 ++++++++++-
15 files changed, 200 insertions(+), 59 deletions(-)
diff --git a/docs/configuration/index.md b/docs/configuration/index.md
index 55be9754b0d..8aa5e818468 100644
--- a/docs/configuration/index.md
+++ b/docs/configuration/index.md
@@ -741,6 +741,7 @@ These Coordinator static configurations can be defined in
the `coordinator/runti
|`druid.plaintextPort`|This is the port to actually listen on; unless port
mapping is used, this will be the same port as is on `druid.host`|8081|
|`druid.tlsPort`|TLS port for HTTPS connector, if
[druid.enableTlsPort](../operations/tls-support.md) is set then this config
will be used. If `druid.host` contains port then that port will be ignored.
This should be a non-negative integer.|8281|
|`druid.service`|The name of the service. This is used as a dimension when
emitting metrics and alerts to differentiate between the various
services.|`druid/coordinator`|
+|`druid.labels`|Optional JSON object of key-value pairs that define custom
labels for the server. These labels are displayed in the web console under the
"Services" tab. Example: `druid.labels={"location":"Airtrunk"}` or
`druid.labels.location=Airtrunk`|`null`|
##### Coordinator operation
@@ -984,6 +985,7 @@ These Overlord static configurations can be defined in the
`overlord/runtime.pro
|`druid.plaintextPort`|This is the port to actually listen on; unless port
mapping is used, this will be the same port as is on `druid.host`.|8090|
|`druid.tlsPort`|TLS port for HTTPS connector, if
[druid.enableTlsPort](../operations/tls-support.md) is set then this config
will be used. If `druid.host` contains port then that port will be ignored.
This should be a non-negative Integer.|8290|
|`druid.service`|The name of the service. This is used as a dimension when
emitting metrics and alerts to differentiate between the various
services.|`druid/overlord`|
+|`druid.labels`|Optional JSON object of key-value pairs that define custom
labels for the server. These labels are displayed in the web console under the
"Services" tab. Example: `druid.labels={"location":"Airtrunk"}` or
`druid.labels.location=Airtrunk`|`null`|
##### Overlord operations
@@ -1335,6 +1337,7 @@ These Middle Manager and Peon configurations can be
defined in the `middleManage
|`druid.plaintextPort`|This is the port to actually listen on; unless port
mapping is used, this will be the same port as is on `druid.host`|8091|
|`druid.tlsPort`|TLS port for HTTPS connector, if
[druid.enableTlsPort](../operations/tls-support.md) is set then this config
will be used. If `druid.host` contains port then that port will be ignored.
This should be a non-negative Integer.|8291|
|`druid.service`|The name of the service. This is used as a dimension when
emitting metrics and alerts to differentiate between the various
services|`druid/middlemanager`|
+|`druid.labels`|Optional JSON object of key-value pairs that define custom
labels for the server. These labels are displayed in the web console under the
"Services" tab. Example: `druid.labels={"location":"Airtrunk"}` or
`druid.labels.location=Airtrunk`|`null`|
#### Middle Manager configuration
@@ -1463,6 +1466,7 @@ For most types of tasks, `SegmentWriteOutMediumFactory`
can be configured per-ta
|`druid.plaintextPort`|This is the port to actually listen on; unless port
mapping is used, this will be the same port as is on `druid.host`|8091|
|`druid.tlsPort`|TLS port for HTTPS connector, if
[druid.enableTlsPort](../operations/tls-support.md) is set then this config
will be used. If `druid.host` contains port then that port will be ignored.
This should be a non-negative Integer.|8283|
|`druid.service`|The name of the service. This is used as a dimension when
emitting metrics and alerts to differentiate between the various
services|`druid/indexer`|
+|`druid.labels`|Optional JSON object of key-value pairs that define custom
labels for the server. These labels are displayed in the web console under the
"Services" tab. Example: `druid.labels={"location":"Airtrunk"}` or
`druid.labels.location=Airtrunk`|`null`|
#### Indexer general configuration
@@ -1559,6 +1563,7 @@ These Historical configurations can be defined in the
`historical/runtime.proper
|`druid.plaintextPort`|This is the port to actually listen on; unless port
mapping is used, this will be the same port as is on `druid.host`|8083|
|`druid.tlsPort`|TLS port for HTTPS connector, if
[druid.enableTlsPort](../operations/tls-support.md) is set then this config
will be used. If `druid.host` contains port then that port will be ignored.
This should be a non-negative Integer.|8283|
|`druid.service`|The name of the service. This is used as a dimension when
emitting metrics and alerts to differentiate between the various
services|`druid/historical`|
+|`druid.labels`|Optional JSON object of key-value pairs that define custom
labels for the server. These labels are displayed in the web console under the
"Services" tab. Example: `druid.labels={"location":"Airtrunk"}` or
`druid.labels.location=Airtrunk`|`null`|
#### Historical general configuration
@@ -1672,6 +1677,7 @@ These Broker configurations can be defined in the
`broker/runtime.properties` fi
|`druid.plaintextPort`|This is the port to actually listen on; unless port
mapping is used, this will be the same port as is on `druid.host`|8082|
|`druid.tlsPort`|TLS port for HTTPS connector, if
[druid.enableTlsPort](../operations/tls-support.md) is set then this config
will be used. If `druid.host` contains port then that port will be ignored.
This should be a non-negative Integer.|8282|
|`druid.service`|The name of the service. This is used as a dimension when
emitting metrics and alerts to differentiate between the various
services|`druid/broker`|
+|`druid.labels`|Optional JSON object of key-value pairs that define custom
labels for the server. These labels are displayed in the web console under the
"Services" tab. Example: `druid.labels={"location":"Airtrunk"}` or
`druid.labels.location=Airtrunk`|`null`|
#### Query configuration
@@ -2291,6 +2297,7 @@ Supported query contexts:
|`druid.plaintextPort`|This is the port to actually listen on; unless port
mapping is used, this will be the same port as is on `druid.host`|8888|
|`druid.tlsPort`|TLS port for HTTPS connector, if
[druid.enableTlsPort](../operations/tls-support.md) is set then this config
will be used. If `druid.host` contains port then that port will be ignored.
This should be a non-negative Integer.|9088|
|`druid.service`|The name of the service. This is used as a dimension when
emitting metrics and alerts to differentiate between the various
services|`druid/router`|
+|`druid.labels`|Optional JSON object of key-value pairs that define custom
labels for the server. These labels are displayed in the web console under the
"Services" tab. Example: `druid.labels={"location":"Airtrunk"}` or
`druid.labels.location=Airtrunk`|`null`|
#### Runtime configuration
diff --git a/docs/querying/sql-metadata-tables.md
b/docs/querying/sql-metadata-tables.md
index aa1804e29d5..6d59462fd1e 100644
--- a/docs/querying/sql-metadata-tables.md
+++ b/docs/querying/sql-metadata-tables.md
@@ -237,6 +237,7 @@ Servers table lists all discovered servers in the cluster.
|is_leader|BIGINT|1 if the server is currently the 'leader' (for services
which have the concept of leadership), otherwise 0 if the server is not the
leader, or null if the server type does not have the concept of leadership|
|start_time|STRING|Timestamp in ISO8601 format when the server was announced
in the cluster|
|version|VARCHAR|Druid version running on the server|
+|labels|VARCHAR|Labels for the server configured using the property
[`druid.labels`](../configuration/index.md)|
To retrieve information about all servers, use the query:
```sql
diff --git
a/integration-tests-ex/cases/src/test/java/org/apache/druid/testsEx/config/Initializer.java
b/integration-tests-ex/cases/src/test/java/org/apache/druid/testsEx/config/Initializer.java
index b09c18e7264..d350e5175f4 100644
---
a/integration-tests-ex/cases/src/test/java/org/apache/druid/testsEx/config/Initializer.java
+++
b/integration-tests-ex/cases/src/test/java/org/apache/druid/testsEx/config/Initializer.java
@@ -148,7 +148,7 @@ public class Initializer
.in(LazySingleton.class);
// Dummy DruidNode instance to make Guice happy. This instance is unused.
- DruidNode dummy = new DruidNode("integration-tests", "localhost", false,
9191, null, null, true, false);
+ DruidNode dummy = new DruidNode("integration-tests", "localhost", false,
9191, null, null, true, false, null);
binder
.bind(DruidNode.class)
.annotatedWith(Self.class)
diff --git
a/integration-tests/src/main/java/org/apache/druid/testing/guice/DruidTestModule.java
b/integration-tests/src/main/java/org/apache/druid/testing/guice/DruidTestModule.java
index ff381439d1e..3ac78bb9c35 100644
---
a/integration-tests/src/main/java/org/apache/druid/testing/guice/DruidTestModule.java
+++
b/integration-tests/src/main/java/org/apache/druid/testing/guice/DruidTestModule.java
@@ -56,7 +56,7 @@ public class DruidTestModule implements Module
// Bind DruidNode instance to make Guice happy. This instance is currently
unused.
binder.bind(DruidNode.class).annotatedWith(Self.class).toInstance(
- new DruidNode("integration-tests", "localhost", false, 9191, null,
null, true, false)
+ new DruidNode("integration-tests", "localhost", false, 9191, null,
null, true, false, null)
);
// Required for MSQIndexingModule
diff --git
a/integration-tests/src/test/resources/results/auth_test_sys_schema_servers.json
b/integration-tests/src/test/resources/results/auth_test_sys_schema_servers.json
index 520fde8ff56..ddbd92e3111 100644
---
a/integration-tests/src/test/resources/results/auth_test_sys_schema_servers.json
+++
b/integration-tests/src/test/resources/results/auth_test_sys_schema_servers.json
@@ -10,7 +10,8 @@
"max_size": 5000000000,
"is_leader": null,
"start_time": "0",
- "version": "0.0.0"
+ "version": "0.0.0",
+ "labels": null
},
{
"server": "%%BROKER%%:8282",
@@ -23,6 +24,7 @@
"max_size": 1000000000,
"is_leader": null,
"start_time": "0",
- "version": "0.0.0"
+ "version": "0.0.0",
+ "labels": null
}
]
diff --git
a/processing/src/main/java/org/apache/druid/java/util/common/jackson/JacksonUtils.java
b/processing/src/main/java/org/apache/druid/java/util/common/jackson/JacksonUtils.java
index ed6567bf931..3aebd02a9bb 100644
---
a/processing/src/main/java/org/apache/druid/java/util/common/jackson/JacksonUtils.java
+++
b/processing/src/main/java/org/apache/druid/java/util/common/jackson/JacksonUtils.java
@@ -30,6 +30,8 @@ import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.error.InternalServerError;
import org.apache.druid.java.util.common.ISE;
import javax.annotation.Nullable;
@@ -119,6 +121,16 @@ public final class JacksonUtils
}
}
+ public static String writeValueAsString(ObjectMapper jsonMapper, Object
value) throws DruidException
+ {
+ try {
+ return jsonMapper.writeValueAsString(value);
+ }
+ catch (JsonProcessingException e) {
+ throw InternalServerError.exception(e, "Failed to serialize object as
JSON");
+ }
+ }
+
/**
* Reads an object using the {@link JsonParser}. It reuses the provided
{@link DeserializationContext} which offers
* better performance that calling {@link JsonParser#readValueAs(Class)}
because it avoids re-creating the {@link DeserializationContext}
diff --git a/server/src/main/java/org/apache/druid/server/DruidNode.java
b/server/src/main/java/org/apache/druid/server/DruidNode.java
index 0e3b3e4b4d0..b6032bd0a1d 100644
--- a/server/src/main/java/org/apache/druid/server/DruidNode.java
+++ b/server/src/main/java/org/apache/druid/server/DruidNode.java
@@ -30,13 +30,14 @@ import org.apache.druid.common.utils.SocketUtil;
import org.apache.druid.java.util.common.IAE;
import org.apache.druid.java.util.common.ISE;
+import javax.annotation.Nullable;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;
-
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
+import java.util.Map;
import java.util.Objects;
/**
@@ -91,6 +92,9 @@ public class DruidNode
UNKNOWN_VERSION
);
+ @JsonProperty
+ private Map<String, String> labels;
+
public DruidNode(
String serviceName,
String host,
@@ -101,7 +105,7 @@ public class DruidNode
boolean enableTlsPort
)
{
- this(serviceName, host, bindOnHost, plaintextPort, null, tlsPort,
enablePlaintextPort, enableTlsPort);
+ this(serviceName, host, bindOnHost, plaintextPort, null, tlsPort,
enablePlaintextPort, enableTlsPort, null);
}
/**
@@ -129,7 +133,8 @@ public class DruidNode
@JacksonInject @Named("servicePort") @JsonProperty("port") Integer port,
@JacksonInject @Named("tlsServicePort") @JsonProperty("tlsPort") Integer
tlsPort,
@JsonProperty("enablePlaintextPort") Boolean enablePlaintextPort,
- @JsonProperty("enableTlsPort") boolean enableTlsPort
+ @JsonProperty("enableTlsPort") boolean enableTlsPort,
+ @JsonProperty("labels") @Nullable Map<String, String> labels
)
{
init(
@@ -138,8 +143,9 @@ public class DruidNode
bindOnHost,
plaintextPort != null ? plaintextPort : port,
tlsPort,
- enablePlaintextPort == null ? true :
enablePlaintextPort.booleanValue(),
- enableTlsPort
+ enablePlaintextPort == null || enablePlaintextPort.booleanValue(),
+ enableTlsPort,
+ labels
);
}
@@ -150,7 +156,8 @@ public class DruidNode
Integer plainTextPort,
Integer tlsPort,
boolean enablePlaintextPort,
- boolean enableTlsPort
+ boolean enableTlsPort,
+ Map<String, String> labels
)
{
Preconditions.checkNotNull(serviceName);
@@ -210,6 +217,13 @@ public class DruidNode
this.serviceName = serviceName;
this.host = host;
this.bindOnHost = bindOnHost;
+ this.labels = labels;
+ }
+
+ @Nullable
+ public Map<String, String> getLabels()
+ {
+ return labels;
}
public String getServiceName()
@@ -336,13 +350,14 @@ public class DruidNode
tlsPort == druidNode.tlsPort &&
enableTlsPort == druidNode.enableTlsPort &&
Objects.equals(serviceName, druidNode.serviceName) &&
- Objects.equals(host, druidNode.host);
+ Objects.equals(host, druidNode.host) &&
+ Objects.equals(labels, druidNode.labels);
}
@Override
public int hashCode()
{
- return Objects.hash(serviceName, host, port, plaintextPort,
enablePlaintextPort, tlsPort, enableTlsPort);
+ return Objects.hash(serviceName, host, port, plaintextPort,
enablePlaintextPort, tlsPort, enableTlsPort, labels);
}
@Override
@@ -357,6 +372,7 @@ public class DruidNode
", enablePlaintextPort=" + enablePlaintextPort +
", tlsPort=" + tlsPort +
", enableTlsPort=" + enableTlsPort +
+ ", labels=" + labels +
'}';
}
}
diff --git
a/server/src/test/java/org/apache/druid/discovery/DiscoveryDruidNodeTest.java
b/server/src/test/java/org/apache/druid/discovery/DiscoveryDruidNodeTest.java
index 0e55e5b68eb..b9c99a4fcb7 100644
---
a/server/src/test/java/org/apache/druid/discovery/DiscoveryDruidNodeTest.java
+++
b/server/src/test/java/org/apache/druid/discovery/DiscoveryDruidNodeTest.java
@@ -112,7 +112,8 @@ public class DiscoveryDruidNodeTest
-1,
8282,
true,
- true
+ true,
+ null
),
NodeRole.BROKER,
ImmutableMap.of(
@@ -167,7 +168,8 @@ public class DiscoveryDruidNodeTest
-1,
8282,
true,
- true
+ true,
+ null
),
NodeRole.BROKER,
ImmutableMap.of(
@@ -216,7 +218,8 @@ public class DiscoveryDruidNodeTest
-1,
8282,
true,
- true
+ true,
+ null
),
NodeRole.BROKER,
ImmutableMap.of(
@@ -266,7 +269,8 @@ public class DiscoveryDruidNodeTest
-1,
8282,
true,
- true
+ true,
+ null
),
NodeRole.BROKER,
ImmutableMap.of()
diff --git a/server/src/test/java/org/apache/druid/server/DruidNodeTest.java
b/server/src/test/java/org/apache/druid/server/DruidNodeTest.java
index 77edaaad137..9b7762904d1 100644
--- a/server/src/test/java/org/apache/druid/server/DruidNodeTest.java
+++ b/server/src/test/java/org/apache/druid/server/DruidNodeTest.java
@@ -21,11 +21,14 @@ package org.apache.druid.server;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableMap;
import com.google.common.net.HostAndPort;
import org.apache.druid.jackson.DefaultObjectMapper;
import org.junit.Assert;
import org.junit.Test;
+import java.util.Map;
+
public class DruidNodeTest
{
private final ObjectMapper mapper;
@@ -161,20 +164,23 @@ public class DruidNodeTest
Assert.assertEquals(-1, node.getPlaintextPort());
Assert.assertEquals(123, node.getTlsPort());
- node = new DruidNode("test", "host", false, -1, 123, false, true);
+ node = new DruidNode("test", "host", false, -1, null, 123, false, true,
ImmutableMap.of("labelKey1", "labelValue1"));
Assert.assertEquals("host", node.getHost());
Assert.assertEquals(-1, node.getPlaintextPort());
Assert.assertEquals(123, node.getTlsPort());
+ Assert.assertEquals(ImmutableMap.of("labelKey1", "labelValue1"),
node.getLabels());
- node = new DruidNode("test", "host", false, -1, 123, true, false);
+ node = new DruidNode("test", "host", false, -1, null, 123, true, false,
ImmutableMap.of("labelKey1", "labelValue1", "labelKey2", "labelValue2"));
Assert.assertEquals("host", node.getHost());
Assert.assertEquals(-1, node.getPlaintextPort());
Assert.assertEquals(-1, node.getTlsPort());
+ Assert.assertEquals(ImmutableMap.of("labelKey1", "labelValue1",
"labelKey2", "labelValue2"), node.getLabels());
node = new DruidNode("test", "host:123", false, 123, null, true, false);
Assert.assertEquals("host", node.getHost());
Assert.assertEquals(123, node.getPlaintextPort());
Assert.assertEquals(-1, node.getTlsPort());
+ Assert.assertNull(node.getLabels());
node = new DruidNode("test", "host:123", false, null, 123, true, false);
Assert.assertEquals("host", node.getHost());
@@ -260,7 +266,9 @@ public class DruidNodeTest
final String serviceName = "serviceName";
final String host = "some.host";
final int port = 9898;
- Assert.assertEquals(new DruidNode(serviceName, host, false, port, null,
true, false), new DruidNode(serviceName, host, false, port, null, true, false));
+ final Map<String, String> labels = ImmutableMap.of("key1", "value1");
+ Assert.assertEquals(new DruidNode(serviceName, host, false, port, null,
null, true, false, labels), new DruidNode(serviceName, host, false, port, null,
null, true, false, labels));
+ Assert.assertEquals(new DruidNode(serviceName, host, false, port, null,
null, true, false, labels), new DruidNode(serviceName, host, false, port, null,
null, true, false, ImmutableMap.of("key1", "value1")));
Assert.assertNotEquals(new DruidNode(serviceName, host, false, port, null,
true, false), new DruidNode(serviceName, host, false, -1, null, true, false));
Assert.assertNotEquals(new DruidNode(serviceName, host, false, port, null,
true, false), new DruidNode(serviceName, "other.host", false, port, null, true,
false));
Assert.assertNotEquals(new DruidNode(serviceName, host, false, port, null,
true, false), new DruidNode("otherServiceName", host, false, port, null, true,
false));
@@ -273,7 +281,11 @@ public class DruidNodeTest
final String serviceName = "serviceName";
final String host = "some.host";
final int port = 9898;
- Assert.assertEquals(new DruidNode(serviceName, host, false, port, null,
true, false).hashCode(), new DruidNode(serviceName, host, false, port, null,
true, false).hashCode());
+ final Map<String, String> labels = ImmutableMap.of("key1", "value1");
+ Assert.assertEquals(
+ new DruidNode(serviceName, host, false, port, null, null, true, false,
labels).hashCode(),
+ new DruidNode(serviceName, host, false, port, null, null, true, false,
labels).hashCode()
+ );
// Potential hash collision if hashCode method ever changes
Assert.assertNotEquals(new DruidNode(serviceName, host, false, port, null,
true, false).hashCode(), new DruidNode(serviceName, host, false, -1, null,
true, false).hashCode());
Assert.assertNotEquals(new DruidNode(serviceName, host, false, port, null,
true, false).hashCode(), new DruidNode(serviceName, "other.host", false, port,
null, true, false).hashCode());
@@ -285,7 +297,7 @@ public class DruidNodeTest
public void testSerde1() throws Exception
{
DruidNode actual = mapper.readValue(
- mapper.writeValueAsString(new DruidNode("service", "host", true, 1234,
null, 5678, true, true)),
+ mapper.writeValueAsString(new DruidNode("service", "host", true, 1234,
null, 5678, true, true, ImmutableMap.of("key1", "value1"))),
DruidNode.class
);
Assert.assertEquals("service", actual.getServiceName());
@@ -295,13 +307,14 @@ public class DruidNodeTest
Assert.assertTrue(actual.isEnableTlsPort());
Assert.assertEquals(1234, actual.getPlaintextPort());
Assert.assertEquals(5678, actual.getTlsPort());
+ Assert.assertEquals(ImmutableMap.of("key1", "value1"), actual.getLabels());
}
@Test
public void testSerde2() throws Exception
{
DruidNode actual = mapper.readValue(
- mapper.writeValueAsString(new DruidNode("service", "host", false,
1234, null, 5678, null, false)),
+ mapper.writeValueAsString(new DruidNode("service", "host", false,
1234, null, 5678, null, false, null)),
DruidNode.class
);
Assert.assertEquals("service", actual.getServiceName());
@@ -311,13 +324,14 @@ public class DruidNodeTest
Assert.assertFalse(actual.isEnableTlsPort());
Assert.assertEquals(1234, actual.getPlaintextPort());
Assert.assertEquals(-1, actual.getTlsPort());
+ Assert.assertNull(actual.getLabels());
}
@Test
public void testSerde3() throws Exception
{
DruidNode actual = mapper.readValue(
- mapper.writeValueAsString(new DruidNode("service", "host", true, 1234,
null, 5678, false, true)),
+ mapper.writeValueAsString(new DruidNode("service", "host", true, 1234,
null, 5678, false, true, ImmutableMap.of("key1", "value1", "key2", "value2"))),
DruidNode.class
);
Assert.assertEquals("service", actual.getServiceName());
@@ -327,6 +341,7 @@ public class DruidNodeTest
Assert.assertTrue(actual.isEnableTlsPort());
Assert.assertEquals(-1, actual.getPlaintextPort());
Assert.assertEquals(5678, actual.getTlsPort());
+ Assert.assertEquals(ImmutableMap.of("key1", "value1", "key2", "value2"),
actual.getLabels());
}
@Test
@@ -339,12 +354,13 @@ public class DruidNodeTest
+ " \"plaintextPort\":1234,\n"
+ " \"tlsPort\":5678,\n"
+ " \"enablePlaintextPort\":true,\n"
- + " \"enableTlsPort\":true\n"
+ + " \"enableTlsPort\":true,\n"
+ + " \"labels\":{\"key1\":\"value1\"}"
+ "}\n";
DruidNode actual = mapper.readValue(json, DruidNode.class);
- Assert.assertEquals(new DruidNode("service", "host", true, 1234, null,
5678, true, true), actual);
+ Assert.assertEquals(new DruidNode("service", "host", true, 1234, null,
5678, true, true, ImmutableMap.of("key1", "value1")), actual);
Assert.assertEquals("https", actual.getServiceScheme());
Assert.assertEquals("host:1234", actual.getHostAndPort());
@@ -365,7 +381,7 @@ public class DruidNodeTest
DruidNode actual = mapper.readValue(json, DruidNode.class);
- Assert.assertEquals(new DruidNode("service", "host", false, 1234, null,
5678, true, false), actual);
+ Assert.assertEquals(new DruidNode("service", "host", false, 1234, null,
5678, true, false, null), actual);
Assert.assertEquals("http", actual.getServiceScheme());
Assert.assertEquals("host:1234", actual.getHostAndPort());
@@ -385,7 +401,7 @@ public class DruidNodeTest
DruidNode actual = mapper.readValue(json, DruidNode.class);
- Assert.assertEquals(new DruidNode("service", "host", false, 1234, null,
5678, null, false), actual);
+ Assert.assertEquals(new DruidNode("service", "host", false, 1234, null,
5678, null, false, null), actual);
Assert.assertEquals("http", actual.getServiceScheme());
Assert.assertEquals("host:1234", actual.getHostAndPort());
@@ -405,7 +421,7 @@ public class DruidNodeTest
DruidNode actual = mapper.readValue(json, DruidNode.class);
- Assert.assertEquals(new DruidNode("service", "host", false, null, 1234,
5678, null, false), actual);
+ Assert.assertEquals(new DruidNode("service", "host", false, null, 1234,
5678, null, false, null), actual);
Assert.assertEquals("http", actual.getServiceScheme());
Assert.assertEquals("host:1234", actual.getHostAndPort());
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
index 932404f21e7..1343ace28fe 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
@@ -57,6 +57,7 @@ import org.apache.druid.indexer.TaskStatusPlus;
import org.apache.druid.indexing.overlord.supervisor.SupervisorStatus;
import org.apache.druid.java.util.common.ISE;
import org.apache.druid.java.util.common.StringUtils;
+import org.apache.druid.java.util.common.jackson.JacksonUtils;
import org.apache.druid.java.util.common.parsers.CloseableIterator;
import org.apache.druid.rpc.indexing.OverlordClient;
import org.apache.druid.segment.column.ColumnType;
@@ -181,6 +182,7 @@ public class SystemSchema extends AbstractSchema
.add("is_leader", ColumnType.LONG)
.add("start_time", ColumnType.STRING)
.add("version", ColumnType.STRING)
+ .add("labels", ColumnType.STRING)
.build();
static final RowSignature SERVER_SEGMENTS_SIGNATURE = RowSignature
@@ -245,7 +247,8 @@ public class SystemSchema extends AbstractSchema
serverInventoryView,
authorizerMapper,
overlordClient,
- coordinatorClient
+ coordinatorClient,
+ jsonMapper
),
SERVER_SEGMENTS_TABLE,
new ServerSegmentsTable(serverView, authorizerMapper),
@@ -526,13 +529,15 @@ public class SystemSchema extends AbstractSchema
private final FilteredServerInventoryView serverInventoryView;
private final OverlordClient overlordClient;
private final CoordinatorClient coordinatorClient;
+ private final ObjectMapper jsonMapper;
public ServersTable(
DruidNodeDiscoveryProvider druidNodeDiscoveryProvider,
FilteredServerInventoryView serverInventoryView,
AuthorizerMapper authorizerMapper,
OverlordClient overlordClient,
- CoordinatorClient coordinatorClient
+ CoordinatorClient coordinatorClient,
+ ObjectMapper jsonMapper
)
{
this.authorizerMapper = authorizerMapper;
@@ -540,6 +545,7 @@ public class SystemSchema extends AbstractSchema
this.serverInventoryView = serverInventoryView;
this.overlordClient = overlordClient;
this.coordinatorClient = coordinatorClient;
+ this.jsonMapper = jsonMapper;
}
@Override
@@ -627,7 +633,7 @@ public class SystemSchema extends AbstractSchema
/**
* Returns a row for all node types which don't serve data. The returned
row contains only static information.
*/
- private static Object[] buildRowForNonDataServer(DiscoveryDruidNode
discoveryDruidNode)
+ private Object[] buildRowForNonDataServer(DiscoveryDruidNode
discoveryDruidNode)
{
final DruidNode node = discoveryDruidNode.getDruidNode();
return new Object[]{
@@ -641,14 +647,15 @@ public class SystemSchema extends AbstractSchema
UNKNOWN_SIZE,
null,
toStringOrNull(discoveryDruidNode.getStartTime()),
- node.getVersion()
+ node.getVersion(),
+ node.getLabels() == null ? null :
JacksonUtils.writeValueAsString(jsonMapper, node.getLabels())
};
}
/**
* Returns a row for all node types which don't serve data. The returned
row contains only static information.
*/
- private static Object[] buildRowForNonDataServerWithLeadership(
+ private Object[] buildRowForNonDataServerWithLeadership(
DiscoveryDruidNode discoveryDruidNode,
boolean isLeader
)
@@ -665,7 +672,8 @@ public class SystemSchema extends AbstractSchema
UNKNOWN_SIZE,
isLeader ? 1L : 0L,
toStringOrNull(discoveryDruidNode.getStartTime()),
- node.getVersion()
+ node.getVersion(),
+ node.getLabels() == null ? null :
JacksonUtils.writeValueAsString(jsonMapper, node.getLabels())
};
}
@@ -674,7 +682,7 @@ public class SystemSchema extends AbstractSchema
* {@code serverFromInventoryView} if available which is the current state
of the server. Otherwise, it
* will get the information from {@code discoveryDruidNode} which has only
static configurations.
*/
- private static Object[] buildRowForDiscoverableDataServer(
+ private Object[] buildRowForDiscoverableDataServer(
DiscoveryDruidNode discoveryDruidNode,
@Nullable DruidServer serverFromInventoryView
)
@@ -701,7 +709,8 @@ public class SystemSchema extends AbstractSchema
druidServerToUse.getMaxSize(),
null,
toStringOrNull(discoveryDruidNode.getStartTime()),
- node.getVersion()
+ node.getVersion(),
+ node.getLabels() == null ? null :
JacksonUtils.writeValueAsString(jsonMapper, node.getLabels())
};
}
diff --git
a/sql/src/test/java/org/apache/druid/sql/calcite/schema/SystemSchemaTest.java
b/sql/src/test/java/org/apache/druid/sql/calcite/schema/SystemSchemaTest.java
index d523d970fcc..dd5af77e92f 100644
---
a/sql/src/test/java/org/apache/druid/sql/calcite/schema/SystemSchemaTest.java
+++
b/sql/src/test/java/org/apache/druid/sql/calcite/schema/SystemSchemaTest.java
@@ -402,7 +402,7 @@ public class SystemSchemaTest extends CalciteTestBase
);
private final DiscoveryDruidNode overlord = new DiscoveryDruidNode(
- new DruidNode("s2", "localhost", false, 8090, null, true, false),
+ new DruidNode("s2", "localhost", false, 8090, null, null, true, false,
ImmutableMap.of("overlordKey", "overlordValue")),
NodeRole.OVERLORD,
ImmutableMap.of(),
startTime
@@ -416,7 +416,7 @@ public class SystemSchemaTest extends CalciteTestBase
);
private final DiscoveryDruidNode broker1 = new DiscoveryDruidNode(
- new DruidNode("s3", "localhost", false, 8082, null, true, false),
+ new DruidNode("s3", "localhost", false, 8082, null, null, true, false,
ImmutableMap.of("brokerKey", "brokerValue", "brokerKey2", "brokerValue2")),
NodeRole.BROKER,
ImmutableMap.of(),
startTime
@@ -558,7 +558,7 @@ public class SystemSchemaTest extends CalciteTestBase
final SystemSchema.ServersTable serversTable = (SystemSchema.ServersTable)
schema.getTableMap().get("servers");
final RelDataType serverRowType = serversTable.getRowType(new
JavaTypeFactoryImpl());
final List<RelDataTypeField> serverFields = serverRowType.getFieldList();
- Assert.assertEquals(11, serverFields.size());
+ Assert.assertEquals(12, serverFields.size());
Assert.assertEquals("server", serverFields.get(0).getName());
Assert.assertEquals(SqlTypeName.VARCHAR,
serverFields.get(0).getType().getSqlTypeName());
}
@@ -761,7 +761,8 @@ public class SystemSchemaTest extends CalciteTestBase
serverInventoryView,
authMapper,
overlordClient,
- coordinatorClient
+ coordinatorClient,
+ MAPPER
)
.createMock();
EasyMock.replay(serversTable);
@@ -858,7 +859,8 @@ public class SystemSchemaTest extends CalciteTestBase
0L,
nonLeader,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(
@@ -873,7 +875,8 @@ public class SystemSchemaTest extends CalciteTestBase
1000L,
nonLeader,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(
@@ -888,7 +891,8 @@ public class SystemSchemaTest extends CalciteTestBase
1000L,
nonLeader,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(
@@ -903,7 +907,8 @@ public class SystemSchemaTest extends CalciteTestBase
1000L,
nonLeader,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(
@@ -918,7 +923,8 @@ public class SystemSchemaTest extends CalciteTestBase
1000L,
nonLeader,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(createExpectedRow(
@@ -932,7 +938,8 @@ public class SystemSchemaTest extends CalciteTestBase
1000L,
nonLeader,
startTimeStr,
- version
+ version,
+ null
));
expectedRows.add(
createExpectedRow(
@@ -946,7 +953,8 @@ public class SystemSchemaTest extends CalciteTestBase
0L,
1L,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(
@@ -961,7 +969,8 @@ public class SystemSchemaTest extends CalciteTestBase
0L,
nonLeader,
startTimeStr,
- version
+ version,
+ "{\"brokerKey\":\"brokerValue\",\"brokerKey2\":\"brokerValue2\"}"
)
);
expectedRows.add(
@@ -976,7 +985,8 @@ public class SystemSchemaTest extends CalciteTestBase
1000L,
nonLeader,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(
@@ -991,7 +1001,8 @@ public class SystemSchemaTest extends CalciteTestBase
0L,
1L,
startTimeStr,
- version
+ version,
+ "{\"overlordKey\":\"overlordValue\"}"
)
);
expectedRows.add(
@@ -1006,7 +1017,8 @@ public class SystemSchemaTest extends CalciteTestBase
0L,
0L,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(
@@ -1021,7 +1033,8 @@ public class SystemSchemaTest extends CalciteTestBase
0L,
0L,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(
@@ -1036,7 +1049,8 @@ public class SystemSchemaTest extends CalciteTestBase
0L,
nonLeader,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(
@@ -1051,7 +1065,8 @@ public class SystemSchemaTest extends CalciteTestBase
0L,
nonLeader,
startTimeStr,
- version
+ version,
+ null
)
);
expectedRows.add(createExpectedRow(
@@ -1065,7 +1080,8 @@ public class SystemSchemaTest extends CalciteTestBase
1000L,
nonLeader,
startTimeStr,
- version
+ version,
+ null
));
Assert.assertEquals(expectedRows.size(), rows.size());
for (int i = 0; i < rows.size(); i++) {
@@ -1099,7 +1115,8 @@ public class SystemSchemaTest extends CalciteTestBase
@Nullable Long maxSize,
@Nullable Long isLeader,
String startTime,
- String version
+ String version,
+ String labels
)
{
return new Object[]{
@@ -1113,7 +1130,8 @@ public class SystemSchemaTest extends CalciteTestBase
maxSize,
isLeader,
startTime,
- version
+ version,
+ labels
};
}
diff --git a/web-console/src/react-table/react-table-extra.scss
b/web-console/src/react-table/react-table-extra.scss
index 534b417298f..ecb9953330f 100644
--- a/web-console/src/react-table/react-table-extra.scss
+++ b/web-console/src/react-table/react-table-extra.scss
@@ -19,6 +19,12 @@
@import '../variables';
.ReactTable {
+ &.centered-table {
+ .rt-th,
+ .rt-td {
+ align-content: center;
+ }
+ }
.rt-tr {
min-height: 38px;
diff --git
a/web-console/src/views/services-view/__snapshots__/services-view.spec.tsx.snap
b/web-console/src/views/services-view/__snapshots__/services-view.spec.tsx.snap
index f17d35a1438..38e99faa1d2 100644
---
a/web-console/src/views/services-view/__snapshots__/services-view.spec.tsx.snap
+++
b/web-console/src/views/services-view/__snapshots__/services-view.spec.tsx.snap
@@ -59,6 +59,7 @@ exports[`ServicesView renders data 1`] = `
"Usage",
"Start time",
"Version",
+ "Labels",
"Detail",
]
}
@@ -89,7 +90,7 @@ exports[`ServicesView renders data 1`] = `
TrComponent={[Function]}
TrGroupComponent={[Function]}
aggregatedKey="_aggregated"
- className=""
+ className="centered-table -striped -highlight padded-header"
collapseOnDataChange={true}
collapseOnPageChange={true}
collapseOnSortingChange={true}
@@ -219,6 +220,16 @@ exports[`ServicesView renders data 1`] = `
"show": true,
"width": 200,
},
+ {
+ "Aggregated": [Function],
+ "Cell": [Function],
+ "Header": "Labels",
+ "accessor": "labels",
+ "className": "padded",
+ "filterable": false,
+ "show": true,
+ "width": 200,
+ },
{
"Aggregated": [Function],
"Cell": [Function],
diff --git a/web-console/src/views/services-view/services-view.scss
b/web-console/src/views/services-view/services-view.scss
index 642b65c6683..53bcac2d48c 100644
--- a/web-console/src/views/services-view/services-view.scss
+++ b/web-console/src/views/services-view/services-view.scss
@@ -36,4 +36,14 @@
ul {
line-height: 20px;
}
+ .labels-list {
+ list-style-type: none;
+ padding-left: 0;
+ margin: 0;
+
+ li {
+ margin: 0;
+ padding: 0;
+ }
+ }
}
diff --git a/web-console/src/views/services-view/services-view.tsx
b/web-console/src/views/services-view/services-view.tsx
index 6fe1fe0236e..f0d97f35612 100644
--- a/web-console/src/views/services-view/services-view.tsx
+++ b/web-console/src/views/services-view/services-view.tsx
@@ -43,6 +43,7 @@ import type { Capabilities, CapabilitiesMode } from
'../../helpers';
import {
booleanCustomTableFilter,
combineModeAndNeedle,
+ DEFAULT_TABLE_CLASS_NAME,
parseFilterModeAndNeedle,
STANDARD_TABLE_PAGE_SIZE,
STANDARD_TABLE_PAGE_SIZE_OPTIONS,
@@ -88,6 +89,7 @@ const TABLE_COLUMNS_BY_MODE: Record<CapabilitiesMode,
TableColumnSelectorColumn[
'Usage',
'Start time',
'Version',
+ 'Labels',
'Detail',
],
'no-sql': [
@@ -149,6 +151,7 @@ interface ServiceResultRow {
readonly tls_port: number;
readonly start_time: string;
readonly version: string;
+ readonly labels: string | null;
}
interface ServicesWithAuxiliaryInfo {
@@ -250,7 +253,8 @@ export class ServicesView extends
React.PureComponent<ServicesViewProps, Service
"max_size",
"is_leader",
"start_time",
- "version"
+ "version",
+ "labels"
FROM sys.servers
ORDER BY
(
@@ -300,6 +304,7 @@ ORDER BY
start_time: '1970:01:01T00:00:00Z',
is_leader: 0,
version: '',
+ labels: null,
};
},
);
@@ -434,6 +439,7 @@ ORDER BY
}
filterable
filtered={filters}
+ className={`centered-table ${DEFAULT_TABLE_CLASS_NAME}`}
onFilteredChange={onFiltersChange}
pivotBy={groupServicesBy ? [groupServicesBy] : []}
defaultPageSize={STANDARD_TABLE_PAGE_SIZE}
@@ -656,6 +662,29 @@ ORDER BY
Cell: this.renderFilterableCell('version'),
Aggregated: () => '',
},
+ {
+ Header: 'Labels',
+ show: visibleColumns.shown('Labels'),
+ accessor: 'labels',
+ className: 'padded',
+ filterable: false,
+ width: 200,
+ Cell: ({ value }: { value: string | null }) => {
+ if (!value) return '';
+ return (
+ <ul className="labels-list">
+ {Object.entries(JSON.parse(value)).map(([key, val]) => {
+ return (
+ <li key={key}>
+ {key}: {String(val)}
+ </li>
+ );
+ })}
+ </ul>
+ );
+ },
+ Aggregated: () => '',
+ },
{
Header: 'Detail',
show: visibleColumns.shown('Detail'),
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]