diff --git a/presto-docs/src/main/sphinx/admin/properties.rst b/presto-docs/src/main/sphinx/admin/properties.rst index a8942fa117bf1..cbbbe16ad920f 100644 --- a/presto-docs/src/main/sphinx/admin/properties.rst +++ b/presto-docs/src/main/sphinx/admin/properties.rst @@ -159,6 +159,15 @@ Maximum object size in bytes that can be considered serializable in a function c The corresponding session property is :ref:`admin/properties-session:\`\`max_serializable_object_size\`\``. +``cluster-tag`` +^^^^^^^^^^^^^^^ + +* **Type:** ``string`` +* **Default value:** (none) + +An optional identifier for the cluster. When set, this tag is included in the response from the +``/v1/cluster`` REST API endpoint, allowing clients to identify which cluster provided the response. + Memory Management Properties ---------------------------- diff --git a/presto-main-base/src/main/java/com/facebook/presto/server/ServerConfig.java b/presto-main-base/src/main/java/com/facebook/presto/server/ServerConfig.java index cc612e3d4c3d3..7e7bcbbffd1d4 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/server/ServerConfig.java +++ b/presto-main-base/src/main/java/com/facebook/presto/server/ServerConfig.java @@ -42,6 +42,7 @@ public class ServerConfig private Duration clusterStatsExpirationDuration = new Duration(0, MILLISECONDS); private boolean nestedDataSerializationEnabled = true; private Duration clusterResourceGroupStateInfoExpirationDuration = new Duration(0, MILLISECONDS); + private String clusterTag; public boolean isResourceManager() { @@ -240,4 +241,16 @@ public ServerConfig setClusterResourceGroupStateInfoExpirationDuration(Duration this.clusterResourceGroupStateInfoExpirationDuration = clusterResourceGroupStateInfoExpirationDuration; return this; } + + public String getClusterTag() + { + return clusterTag; + } + + @Config("cluster-tag") + public ServerConfig setClusterTag(String clusterTag) + { + this.clusterTag = clusterTag; + return this; + } } diff --git a/presto-main-base/src/test/java/com/facebook/presto/server/TestServerConfig.java b/presto-main-base/src/test/java/com/facebook/presto/server/TestServerConfig.java index d10949f15bb65..b570f157a36f4 100644 --- a/presto-main-base/src/test/java/com/facebook/presto/server/TestServerConfig.java +++ b/presto-main-base/src/test/java/com/facebook/presto/server/TestServerConfig.java @@ -49,7 +49,8 @@ public void testDefaults() .setPoolType(DEFAULT) .setClusterStatsExpirationDuration(new Duration(0, MILLISECONDS)) .setNestedDataSerializationEnabled(true) - .setClusterResourceGroupStateInfoExpirationDuration(new Duration(0, MILLISECONDS))); + .setClusterResourceGroupStateInfoExpirationDuration(new Duration(0, MILLISECONDS)) + .setClusterTag(null)); } @Test @@ -72,6 +73,7 @@ public void testExplicitPropertyMappings() .put("cluster-stats-expiration-duration", "10s") .put("nested-data-serialization-enabled", "false") .put("cluster-resource-group-state-info-expiration-duration", "10s") + .put("cluster-tag", "test-cluster") .build(); ServerConfig expected = new ServerConfig() @@ -90,7 +92,8 @@ public void testExplicitPropertyMappings() .setPoolType(LEAF) .setClusterStatsExpirationDuration(new Duration(10, SECONDS)) .setNestedDataSerializationEnabled(false) - .setClusterResourceGroupStateInfoExpirationDuration(new Duration(10, SECONDS)); + .setClusterResourceGroupStateInfoExpirationDuration(new Duration(10, SECONDS)) + .setClusterTag("test-cluster"); assertFullMapping(properties, expected); } diff --git a/presto-main/src/main/java/com/facebook/presto/resourcemanager/DistributedClusterStatsResource.java b/presto-main/src/main/java/com/facebook/presto/resourcemanager/DistributedClusterStatsResource.java index 5efac272478d4..e4de63b1eea3b 100644 --- a/presto-main/src/main/java/com/facebook/presto/resourcemanager/DistributedClusterStatsResource.java +++ b/presto-main/src/main/java/com/facebook/presto/resourcemanager/DistributedClusterStatsResource.java @@ -50,6 +50,7 @@ public class DistributedClusterStatsResource private final ResourceManagerClusterStateProvider clusterStateProvider; private final InternalNodeManager internalNodeManager; private final Supplier clusterStatsSupplier; + private final String clusterTag; @Inject public DistributedClusterStatsResource( @@ -61,7 +62,9 @@ public DistributedClusterStatsResource( this.isIncludeCoordinator = requireNonNull(nodeSchedulerConfig, "nodeSchedulerConfig is null").isIncludeCoordinator(); this.clusterStateProvider = requireNonNull(clusterStateProvider, "nodeStateManager is null"); this.internalNodeManager = requireNonNull(internalNodeManager, "internalNodeManager is null"); - Duration expirationDuration = requireNonNull(serverConfig, "serverConfig is null").getClusterStatsExpirationDuration(); + ServerConfig config = requireNonNull(serverConfig, "serverConfig is null"); + this.clusterTag = config.getClusterTag(); + Duration expirationDuration = config.getClusterStatsExpirationDuration(); this.clusterStatsSupplier = expirationDuration.getValue() > 0 ? memoizeWithExpiration(this::calculateClusterStats, expirationDuration.toMillis(), MILLISECONDS) : this::calculateClusterStats; } @@ -126,7 +129,8 @@ else if (query.getState() == QueryState.RUNNING) { totalInputRows, totalInputBytes, totalCpuTimeSecs, - clusterStateProvider.getAdjustedQueueSize()); + clusterStateProvider.getAdjustedQueueSize(), + clusterTag); } @GET diff --git a/presto-main/src/main/java/com/facebook/presto/server/ClusterStatsResource.java b/presto-main/src/main/java/com/facebook/presto/server/ClusterStatsResource.java index db24433f6c09d..c703212f79c89 100644 --- a/presto-main/src/main/java/com/facebook/presto/server/ClusterStatsResource.java +++ b/presto-main/src/main/java/com/facebook/presto/server/ClusterStatsResource.java @@ -76,6 +76,7 @@ public class ClusterStatsResource private final InternalResourceGroupManager internalResourceGroupManager; private final ClusterTtlProviderManager clusterTtlProviderManager; private final Supplier clusterStatsSupplier; + private final String clusterTag; @Inject public ClusterStatsResource( @@ -96,7 +97,9 @@ public ClusterStatsResource( this.proxyHelper = requireNonNull(proxyHelper, "internalNodeManager is null"); this.internalResourceGroupManager = requireNonNull(internalResourceGroupManager, "internalResourceGroupManager is null"); this.clusterTtlProviderManager = requireNonNull(clusterTtlProviderManager, "clusterTtlProvider is null"); - Duration expirationDuration = requireNonNull(serverConfig, "serverConfig is null").getClusterStatsExpirationDuration(); + ServerConfig config = requireNonNull(serverConfig, "serverConfig is null"); + this.clusterTag = config.getClusterTag(); + Duration expirationDuration = config.getClusterStatsExpirationDuration(); this.clusterStatsSupplier = expirationDuration.getValue() > 0 ? memoizeWithExpiration(this::calculateClusterStats, expirationDuration.toMillis(), MILLISECONDS) : this::calculateClusterStats; } @@ -170,7 +173,8 @@ else if (query.getState() == QueryState.RUNNING) { totalInputRows, totalInputBytes, totalCpuTimeSecs, - internalResourceGroupManager.getQueriesQueuedOnInternal()); + internalResourceGroupManager.getQueriesQueuedOnInternal(), + clusterTag); } @GET @@ -238,6 +242,8 @@ public static class ClusterStats private final long totalCpuTimeSecs; private final long adjustedQueueSize; + private final String clusterTag; + @JsonCreator @ThriftConstructor public ClusterStats( @@ -251,7 +257,8 @@ public ClusterStats( @JsonProperty("totalInputRows") long totalInputRows, @JsonProperty("totalInputBytes") long totalInputBytes, @JsonProperty("totalCpuTimeSecs") long totalCpuTimeSecs, - @JsonProperty("adjustedQueueSize") long adjustedQueueSize) + @JsonProperty("adjustedQueueSize") long adjustedQueueSize, + @JsonProperty("clusterTag") String clusterTag) { this.runningQueries = runningQueries; this.blockedQueries = blockedQueries; @@ -264,6 +271,7 @@ public ClusterStats( this.totalInputBytes = totalInputBytes; this.totalCpuTimeSecs = totalCpuTimeSecs; this.adjustedQueueSize = adjustedQueueSize; + this.clusterTag = clusterTag; } @JsonProperty @@ -342,5 +350,12 @@ public long getAdjustedQueueSize() { return adjustedQueueSize; } + + @JsonProperty + @ThriftField(12) + public String getClusterTag() + { + return clusterTag; + } } } diff --git a/presto-main/src/main/java/com/facebook/presto/server/ServerMainModule.java b/presto-main/src/main/java/com/facebook/presto/server/ServerMainModule.java index 7042ec9ef8bd9..88f191bcc05cf 100644 --- a/presto-main/src/main/java/com/facebook/presto/server/ServerMainModule.java +++ b/presto-main/src/main/java/com/facebook/presto/server/ServerMainModule.java @@ -338,6 +338,7 @@ else if (serverConfig.isCoordinator()) { install(new InternalCommunicationModule()); + configBinder(binder).bindConfig(ServerConfig.class); configBinder(binder).bindConfig(FeaturesConfig.class); configBinder(binder).bindConfig(FunctionsConfig.class); configBinder(binder).bindConfig(JavaFeaturesConfig.class); diff --git a/presto-main/src/test/java/com/facebook/presto/server/TestThriftClusterStats.java b/presto-main/src/test/java/com/facebook/presto/server/TestThriftClusterStats.java index c396f083da00b..4a8d6d944067f 100644 --- a/presto-main/src/test/java/com/facebook/presto/server/TestThriftClusterStats.java +++ b/presto-main/src/test/java/com/facebook/presto/server/TestThriftClusterStats.java @@ -46,6 +46,7 @@ public class TestThriftClusterStats public static final long TOTAL_INPUT_BYTES = 1003; public static final long TOTAL_CPU_TIME_SECS = 1004; public static final long ADJUSTED_QUEUE_SIZE = 1005; + public static final String CLUSTER_TAG = "test-cluster"; private static final ThriftCodecManager COMPILER_READ_CODEC_MANAGER = new ThriftCodecManager(new CompilerThriftCodecFactory(false)); private static final ThriftCodecManager COMPILER_WRITE_CODEC_MANAGER = new ThriftCodecManager(new CompilerThriftCodecFactory(false)); private static final ThriftCodec COMPILER_READ_CODEC = COMPILER_READ_CODEC_MANAGER.getCodec(ClusterStats.class); @@ -111,6 +112,7 @@ private void assertSerde(ClusterStats clusterStats) assertEquals(clusterStats.getTotalInputBytes(), TOTAL_INPUT_BYTES); assertEquals(clusterStats.getTotalCpuTimeSecs(), TOTAL_CPU_TIME_SECS); assertEquals(clusterStats.getAdjustedQueueSize(), ADJUSTED_QUEUE_SIZE); + assertEquals(clusterStats.getClusterTag(), CLUSTER_TAG); } private ClusterStats getRoundTripSerialize(ThriftCodec readCodec, ThriftCodec writeCodec, Function protocolFactory) @@ -134,6 +136,7 @@ private ClusterStats getClusterStats() TOTAL_INPUT_ROWS, TOTAL_INPUT_BYTES, TOTAL_CPU_TIME_SECS, - ADJUSTED_QUEUE_SIZE); + ADJUSTED_QUEUE_SIZE, + CLUSTER_TAG); } } diff --git a/presto-ui/src/components/PageTitle.tsx b/presto-ui/src/components/PageTitle.tsx index ea3f79fed52ce..0c12d07086060 100644 --- a/presto-ui/src/components/PageTitle.tsx +++ b/presto-ui/src/components/PageTitle.tsx @@ -58,6 +58,7 @@ export const PageTitle = (props: Props): React.ReactElement => { modalShown: false, errorText: null, }); + const [clusterTag, setClusterTag] = useState(null); const timeoutId = useRef(null); @@ -118,6 +119,17 @@ export const PageTitle = (props: Props): React.ReactElement => { }; }, []); + useEffect(() => { + fetch("/v1/cluster") + .then((response) => response.json()) + .then((clusterResponse) => { + setClusterTag(clusterResponse.clusterTag); + }) + .catch((error) => { + console.error("Could not fetch cluster response:", error); + }); + }, []); + const renderStatusLight = () => { if (state.noConnection) { if (state.lightShown) { @@ -138,7 +150,7 @@ export const PageTitle = (props: Props): React.ReactElement => { return (