Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b2d8bb8
Add labels to servers
GabrielCWT Sep 19, 2025
71e549f
Add labels to FE
GabrielCWT Sep 19, 2025
7dee2ca
Fix missing assignment to labels variable
GabrielCWT Sep 19, 2025
1c24c13
Update docs
GabrielCWT Sep 19, 2025
22de456
Remove labels default value
GabrielCWT Sep 23, 2025
da63bf9
Return labels as JSON object instead of string
GabrielCWT Sep 23, 2025
69a6025
Fix checkstyle
GabrielCWT Sep 23, 2025
8113e17
Update tests
GabrielCWT Sep 23, 2025
adb0f92
Revert Intellij change
GabrielCWT Sep 23, 2025
34e5656
Update spelling
GabrielCWT Sep 23, 2025
71fddfb
Update IT json
GabrielCWT Sep 24, 2025
440be3b
Fix format for scss
GabrielCWT Sep 24, 2025
0b8e2c2
Update snapshot
GabrielCWT Sep 24, 2025
fec3d61
Fix based on comments
GabrielCWT Sep 24, 2025
466e00f
Add DruidNode tests
GabrielCWT Sep 24, 2025
01f49f0
Refactor to use JacksonUtils.writeValueAsString
GabrielCWT Sep 24, 2025
b722389
Remove unused case for columnType
GabrielCWT Sep 24, 2025
ff9bed7
Update services-view to expect string return for labels
GabrielCWT Sep 24, 2025
8ae4dfd
Throw InternalServerError instead of InvalidInput
GabrielCWT Sep 24, 2025
b0cc6b6
Merge branch 'master' into gh-82-add-label
GabrielCWT Sep 25, 2025
89d4d19
Update snapshot and format
GabrielCWT Sep 25, 2025
b03bc3d
Update test with new row size
GabrielCWT Sep 26, 2025
5cda052
Hide labels during aggregation
GabrielCWT Oct 8, 2025
632be3e
Merge branch 'master' into gh-82-add-label
GabrielCWT Oct 8, 2025
2261145
Merge branch 'master' into gh-82-add-label
GabrielCWT Oct 10, 2025
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
7 changes: 7 additions & 0 deletions docs/configuration/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -1558,6 +1562,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

Expand Down Expand Up @@ -1671,6 +1676,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

Expand Down Expand Up @@ -2290,6 +2296,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

Expand Down
1 change: 1 addition & 0 deletions docs/querying/sql-metadata-tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public void configure(Binder binder)
.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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public void configure(Binder binder)

// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -23,6 +24,7 @@
"max_size": 1000000000,
"is_leader": null,
"start_time": "0",
"version": "0.0.0"
"version": "0.0.0",
"labels": null
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
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;
Expand Down Expand Up @@ -119,6 +121,16 @@ public static void writeObjectUsingSerializerProvider(
}
}

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}
Expand Down
32 changes: 24 additions & 8 deletions server/src/main/java/org/apache/druid/server/DruidNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@
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;

/**
Expand Down Expand Up @@ -91,6 +92,9 @@ public class DruidNode
UNKNOWN_VERSION
);

@JsonProperty
private Map<String, String> labels;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private Map<String, String> labels;
private final Map<String, String> labels;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently all variables are being assigned in the init function, this prevents the object's variables from being final. I will be following this convention and as such not be assigning final to the variable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I missed the init() call. final is always better for such bean fields.
But you are right, we cannot do it in this PR.


public DruidNode(
String serviceName,
String host,
Expand All @@ -101,7 +105,7 @@ public DruidNode(
boolean enableTlsPort
)
{
this(serviceName, host, bindOnHost, plaintextPort, null, tlsPort, enablePlaintextPort, enableTlsPort);
this(serviceName, host, bindOnHost, plaintextPort, null, tlsPort, enablePlaintextPort, enableTlsPort, null);
}

/**
Expand Down Expand Up @@ -129,7 +133,8 @@ public 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(
Expand All @@ -138,8 +143,9 @@ public DruidNode(
bindOnHost,
plaintextPort != null ? plaintextPort : port,
tlsPort,
enablePlaintextPort == null ? true : enablePlaintextPort.booleanValue(),
enableTlsPort
enablePlaintextPort == null || enablePlaintextPort.booleanValue(),
enableTlsPort,
labels
);
}

Expand All @@ -150,7 +156,8 @@ private void init(
Integer plainTextPort,
Integer tlsPort,
boolean enablePlaintextPort,
boolean enableTlsPort
boolean enableTlsPort,
Map<String, String> labels
)
{
Preconditions.checkNotNull(serviceName);
Expand Down Expand Up @@ -210,6 +217,13 @@ private void init(
this.serviceName = serviceName;
this.host = host;
this.bindOnHost = bindOnHost;
this.labels = labels;
}

@Nullable
public Map<String, String> getLabels()
{
return labels;
}

public String getServiceName()
Expand Down Expand Up @@ -336,13 +350,14 @@ public boolean equals(Object o)
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
Expand All @@ -357,6 +372,7 @@ public String toString()
", enablePlaintextPort=" + enablePlaintextPort +
", tlsPort=" + tlsPort +
", enableTlsPort=" + enableTlsPort +
", labels=" + labels +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ public void testSerdeWithDataNodeAndLookupNodeServices() throws JsonProcessingEx
-1,
8282,
true,
true
true,
null
),
NodeRole.BROKER,
ImmutableMap.of(
Expand Down Expand Up @@ -167,7 +168,8 @@ public void testDeserializeWithDataNodeServiceWithAWrongPropertyOrder() throws J
-1,
8282,
true,
true
true,
null
),
NodeRole.BROKER,
ImmutableMap.of(
Expand Down Expand Up @@ -216,7 +218,8 @@ public void testDeserialize_duplicateProperties_shouldSucceedToDeserialize() thr
-1,
8282,
true,
true
true,
null
),
NodeRole.BROKER,
ImmutableMap.of(
Expand Down Expand Up @@ -266,7 +269,8 @@ public void testDeserialize_duplicateKeysWithDifferentValus_shouldIgnoreDataNode
-1,
8282,
true,
true
true,
null
),
NodeRole.BROKER,
ImmutableMap.of()
Expand Down
Loading