This is an automated email from the ASF dual-hosted git repository.
errose28 pushed a commit to branch HDDS-14496-zdu
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-14496-zdu by this push:
new dc1fd833496 HDDS-14825. Add Grafana Dashboard and Metrics for ZDU
(#10602)
dc1fd833496 is described below
commit dc1fd833496be950a9b58a869172c33f40252440
Author: Ethan Rose <[email protected]>
AuthorDate: Thu Jul 16 09:05:12 2026 -0400
HDDS-14825. Add Grafana Dashboard and Metrics for ZDU (#10602)
---
.../hadoop/hdds/server/http/BaseHttpServer.java | 2 +
.../hadoop/hdds/server/http/BuildInfoMetrics.java | 101 ++
.../hdds/server/http/TestBuildInfoMetrics.java | 117 ++
.../dashboards/Ozone - Rolling Upgrade.json | 1124 ++++++++++++++++++++
.../java/org/apache/hadoop/ozone/om/OMMetrics.java | 10 +
.../org/apache/hadoop/ozone/om/OzoneManager.java | 3 +
.../request/upgrade/OMFinalizeUpgradeRequest.java | 1 +
.../upgrade/OMStartFinalizeUpgradeRequest.java | 1 +
.../ozone/om/TestOzoneManagerHttpServer.java | 16 +-
.../upgrade/TestOMFinalizeUpgradeRequest.java | 6 +
.../upgrade/TestOMStartFinalizeUpgradeRequest.java | 4 +
.../java/org/apache/hadoop/ozone/s3/Gateway.java | 6 +
.../ozone/s3/metrics/S3GatewayVersionMetrics.java | 76 ++
.../s3/metrics/TestS3GatewayVersionMetrics.java | 41 +
14 files changed, 1494 insertions(+), 14 deletions(-)
diff --git
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BaseHttpServer.java
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BaseHttpServer.java
index 9b2a0a61fda..d56b96e2f51 100644
---
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BaseHttpServer.java
+++
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BaseHttpServer.java
@@ -329,6 +329,7 @@ public void start() throws IOException {
.register("prometheus", "Hadoop metrics prometheus exporter",
prometheusMetricsSink);
}
+ BuildInfoMetrics.create(name);
updateConnectorAddress();
}
@@ -341,6 +342,7 @@ private boolean isEnabled() {
public void stop() throws Exception {
if (httpServer != null) {
httpServer.stop();
+ BuildInfoMetrics.unregister();
}
}
diff --git
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BuildInfoMetrics.java
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BuildInfoMetrics.java
new file mode 100644
index 00000000000..2eda069b4c2
--- /dev/null
+++
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BuildInfoMetrics.java
@@ -0,0 +1,101 @@
+/*
+ * 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.hadoop.hdds.server.http;
+
+import org.apache.hadoop.hdds.utils.HddsVersionInfo;
+import org.apache.hadoop.hdds.utils.VersionInfo;
+import org.apache.hadoop.metrics2.MetricsCollector;
+import org.apache.hadoop.metrics2.MetricsRecordBuilder;
+import org.apache.hadoop.metrics2.MetricsSource;
+import org.apache.hadoop.metrics2.MetricsSystem;
+import org.apache.hadoop.metrics2.MetricsTag;
+import org.apache.hadoop.metrics2.annotation.Metrics;
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.apache.hadoop.metrics2.lib.Interns;
+import org.apache.hadoop.ozone.OzoneConsts;
+
+/**
+ * Exposes build version and git revision as a Prometheus info metric.
+ *
+ * <p>Follows the OpenMetrics Info pattern: the value is always 1, and the
+ * identifying strings are carried as labels. The metric name uses the
+ * conventional {@code _build_info} suffix.</p>
+ *
+ * <pre>
+ * ozone_build_info{component="OM",version="2.0.0",revision="abc1234"} 1
+ * </pre>
+ */
+@Metrics(about = "Ozone build version info", context = OzoneConsts.OZONE)
+public final class BuildInfoMetrics implements MetricsSource {
+
+ public static final String METRICS_SOURCE_NAME = "OzoneBuildInfo";
+ /**
+ * Record name chosen so that prometheusName("Ozone", "BuildInfo") produces
+ * the conventional "ozone_build_info" metric name.
+ */
+ public static final String RECORD_NAME = "Ozone";
+
+ private final String component;
+ private final String version;
+ private final String revision;
+
+ private BuildInfoMetrics(String component, VersionInfo versionInfo) {
+ this.component = component;
+ this.version = versionInfo.getVersion();
+ this.revision = versionInfo.getRevision();
+ }
+
+ /**
+ * Return the existing build-info source if one is already registered,
+ * otherwise create a new one, register it and return it. Build info is
+ * process-wide, so a single source is shared by every {@code BaseHttpServer}
+ * in the JVM (e.g. the S3 Gateway runs two). Making this idempotent keeps a
+ * second caller from failing with a duplicate-source error.
+ *
+ * @return a new or existing {@link BuildInfoMetrics}
+ */
+ public static synchronized BuildInfoMetrics create(String component) {
+ MetricsSystem ms = DefaultMetricsSystem.instance();
+ MetricsSource existing = ms.getSource(METRICS_SOURCE_NAME);
+ if (existing != null) {
+ return (BuildInfoMetrics) existing;
+ }
+ BuildInfoMetrics source =
+ new BuildInfoMetrics(component, HddsVersionInfo.HDDS_VERSION_INFO);
+ return ms.register(METRICS_SOURCE_NAME, "Ozone build version info",
source);
+ }
+
+ /**
+ * Unregister the build-info source. Idempotent: a no-op if it was never
+ * registered or was already removed. Called when the owning server stops so
+ * that a later {@link #create(String)} does not fail with a duplicate
source.
+ */
+ public static synchronized void unregister() {
+ DefaultMetricsSystem.instance().unregisterSource(METRICS_SOURCE_NAME);
+ }
+
+ @Override
+ public void getMetrics(MetricsCollector collector, boolean all) {
+ MetricsRecordBuilder builder = collector.addRecord(RECORD_NAME)
+ .add(new MetricsTag(Interns.info("component", "Ozone component name"),
component))
+ .add(new MetricsTag(Interns.info("revision", "Source control
revision"), revision))
+ .add(new MetricsTag(Interns.info("version", "Ozone build version"),
version))
+ .addGauge(Interns.info("BuildInfo", "Always 1; identifying info is in
labels"), 1L);
+ builder.endRecord();
+ }
+}
diff --git
a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestBuildInfoMetrics.java
b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestBuildInfoMetrics.java
new file mode 100644
index 00000000000..d669da1dba5
--- /dev/null
+++
b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestBuildInfoMetrics.java
@@ -0,0 +1,117 @@
+/*
+ * 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.hadoop.hdds.server.http;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.concurrent.TimeoutException;
+import org.apache.hadoop.metrics2.MetricsSystem;
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.apache.ozone.test.GenericTestUtils;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for {@link BuildInfoMetrics}.
+ */
+public class TestBuildInfoMetrics {
+
+ private MetricsSystem metricsSystem;
+ private PrometheusMetricsSink sink;
+
+ @BeforeEach
+ public void setUp() {
+ metricsSystem = DefaultMetricsSystem.instance();
+ metricsSystem.init("test");
+ sink = new PrometheusMetricsSink("testserver");
+ metricsSystem.register("Prometheus", "Prometheus", sink);
+ }
+
+ @AfterEach
+ public void tearDown() {
+ metricsSystem.unregisterSource(BuildInfoMetrics.METRICS_SOURCE_NAME);
+ metricsSystem.stop();
+ metricsSystem.shutdown();
+ }
+
+ @Test
+ public void testBuildInfoMetricPublished()
+ throws IOException, InterruptedException, TimeoutException {
+ BuildInfoMetrics.create("OM");
+
+ String output = waitForMetricsToPublish("ozone_build_info");
+
+ assertThat(output).contains("# TYPE ozone_build_info gauge");
+ assertThat(output).contains("ozone_build_info{");
+ assertThat(output).contains("component=\"OM\"");
+ assertThat(output).contains("version=");
+ assertThat(output).contains("revision=");
+ // Info metrics always have value 1
+ assertThat(output).containsPattern("ozone_build_info\\{.*\\} 1");
+ }
+
+ @Test
+ public void testBuildInfoMetricOnlyOneTypeComment()
+ throws IOException, InterruptedException, TimeoutException {
+ BuildInfoMetrics.create("SCM");
+
+ String output = waitForMetricsToPublish("ozone_build_info");
+
+ assertEquals(1, countOccurrences(output, "# TYPE ozone_build_info gauge"),
+ "Expected exactly one TYPE comment for ozone_build_info");
+ }
+
+ private String publishAndGet() throws IOException {
+ metricsSystem.publishMetricsNow();
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ OutputStreamWriter writer = new OutputStreamWriter(bos, UTF_8);
+ sink.writeMetrics(writer);
+ writer.flush();
+ return bos.toString(UTF_8.name());
+ }
+
+ private String waitForMetricsToPublish(String metric)
+ throws InterruptedException, TimeoutException {
+ String[] result = new String[1];
+ GenericTestUtils.waitFor(() -> {
+ try {
+ result[0] = publishAndGet();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return result[0].contains(metric);
+ }, 500, 30000);
+ return result[0];
+ }
+
+ private static int countOccurrences(String text, String substring) {
+ int count = 0;
+ int idx = 0;
+ while ((idx = text.indexOf(substring, idx)) != -1) {
+ count++;
+ idx += substring.length();
+ }
+ return count;
+ }
+}
diff --git a/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Ozone
- Rolling Upgrade.json
b/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Ozone - Rolling
Upgrade.json
new file mode 100644
index 00000000000..00704acbb9f
--- /dev/null
+++ b/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Ozone -
Rolling Upgrade.json
@@ -0,0 +1,1124 @@
+{
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": {
+ "type": "grafana",
+ "uid": "-- Grafana --"
+ },
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "graphTooltip": 0,
+ "id": 13,
+ "links": [],
+ "panels": [
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 17,
+ "panels": [],
+ "title": "Full Cluster Summary",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "description": "Number of distinct build versions present across all
instances in the cluster. This will be 2 when an upgrade is in progress.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": 0
+ },
+ {
+ "color": "yellow",
+ "value": 2
+ },
+ {
+ "color": "red",
+ "value": 3
+ }
+ ]
+ },
+ "unit": "suffix:Active Versions"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 8,
+ "x": 0,
+ "y": 1
+ },
+ "id": 15,
+ "options": {
+ "colorMode": "background",
+ "graphMode": "none",
+ "justifyMode": "center",
+ "orientation": "horizontal",
+ "percentChangeColorMode": "standard",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "value",
+ "wideLayout": true
+ },
+ "pluginVersion": "12.3.1",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr": "count(count by (version) (ozone_build_info))",
+ "instant": true,
+ "legendFormat": "",
+ "range": false,
+ "refId": "A"
+ }
+ ],
+ "title": "",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "description": "Cluster upgrade status. The upgrade is complete when all
instances are running the same version and do not require finalization.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [
+ {
+ "options": {
+ "0": {
+ "color": "orange",
+ "index": 0,
+ "text": "Upgrading"
+ },
+ "1": {
+ "color": "orange",
+ "index": 1,
+ "text": "Finalizing"
+ },
+ "2": {
+ "color": "yellow",
+ "index": 2,
+ "text": "Unfinalized"
+ },
+ "3": {
+ "color": "green",
+ "index": 3,
+ "text": "Complete"
+ }
+ },
+ "type": "value"
+ }
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "orange",
+ "value": 0
+ },
+ {
+ "color": "orange",
+ "value": 1
+ },
+ {
+ "color": "yellow",
+ "value": 2
+ },
+ {
+ "color": "green",
+ "value": 3
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 8,
+ "x": 8,
+ "y": 1
+ },
+ "id": 14,
+ "options": {
+ "colorMode": "background",
+ "graphMode": "none",
+ "justifyMode": "center",
+ "orientation": "horizontal",
+ "percentChangeColorMode": "standard",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "value",
+ "wideLayout": true
+ },
+ "pluginVersion": "12.3.1",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr": "(count(count by (version) (ozone_build_info)) == bool 1) *
(1 + (1 - max(om_metrics_finalization_in_progress)) * (1 +
(sum((component_version_manager_metrics_apparent_version != bool
component_version_manager_metrics_software_version) * on(instance) group_left()
(ozone_build_info{component!~\"recon\"})) == bool 0)))",
+ "instant": true,
+ "legendFormat": "",
+ "range": false,
+ "refId": "A"
+ }
+ ],
+ "title": "",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "description": "Number of instances currently hidden by the component
and instance selectors at the top of the dashboard. 0 means all nodes are
visible.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": 0
+ },
+ {
+ "color": "red",
+ "value": 1
+ }
+ ]
+ },
+ "unit": "suffix:Instances Hidden"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 8,
+ "x": 16,
+ "y": 1
+ },
+ "id": 16,
+ "options": {
+ "colorMode": "background",
+ "graphMode": "none",
+ "justifyMode": "center",
+ "orientation": "horizontal",
+ "percentChangeColorMode": "standard",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "value",
+ "wideLayout": true
+ },
+ "pluginVersion": "12.3.1",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr": "count(ozone_build_info) -
count(ozone_build_info{component=~\"$component\",instance=~\"$instance\"})",
+ "instant": true,
+ "legendFormat": "",
+ "range": false,
+ "refId": "A"
+ }
+ ],
+ "title": "",
+ "type": "stat"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 4
+ },
+ "id": 4,
+ "panels": [],
+ "title": "Versions",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "description": "Total number of selected instances running each version.
The chart fills with a single slice when the upgrade completes.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "fixedColor": "#354c6f",
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ }
+ },
+ "decimals": 0,
+ "displayName": "${__field.labels.version}",
+ "mappings": [],
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 9,
+ "x": 0,
+ "y": 5
+ },
+ "id": 2,
+ "options": {
+ "displayLabels": [
+ "name"
+ ],
+ "legend": {
+ "calcs": [],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true,
+ "values": [
+ "value",
+ "percent"
+ ]
+ },
+ "pieType": "pie",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "sort": "desc",
+ "tooltip": {
+ "hideZeros": false,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "pluginVersion": "12.3.1",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr": "count by (version)
(ozone_build_info{component=~\"$component\",instance=~\"$instance\"})",
+ "instant": true,
+ "legendFormat": "{{version}}",
+ "range": false,
+ "refId": "A"
+ }
+ ],
+ "title": "Instances Per Version",
+ "type": "piechart"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "description": "Build version of each selected instance. Use this to see
which instances still need to be upgraded.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "custom": {
+ "align": "left",
+ "cellOptions": {
+ "type": "auto"
+ },
+ "footer": {
+ "reducers": []
+ },
+ "inspect": false
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": 0
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 14,
+ "x": 9,
+ "y": 5
+ },
+ "id": 5,
+ "options": {
+ "cellHeight": "sm",
+ "enablePagination": true,
+ "footer": {
+ "countRows": false,
+ "enablePagination": true,
+ "fields": "",
+ "reducer": [
+ "sum"
+ ],
+ "show": false
+ },
+ "showHeader": true,
+ "sortBy": [
+ {
+ "desc": false,
+ "displayName": "Version"
+ }
+ ]
+ },
+ "pluginVersion": "12.3.1",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr": "ozone_build_info{instance=~\"$instance\"}",
+ "format": "table",
+ "instant": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Versions",
+ "transformations": [
+ {
+ "id": "organize",
+ "options": {
+ "excludeByName": {
+ "Time": true,
+ "Value": true,
+ "__name__": true,
+ "context": true,
+ "exported_component": true,
+ "hostname": true,
+ "job": true,
+ "revision": true
+ },
+ "indexByName": {
+ "component": 0,
+ "instance": 1,
+ "version": 2
+ },
+ "renameByName": {
+ "component": "Component",
+ "instance": "Instance",
+ "version": "Version"
+ }
+ }
+ }
+ ],
+ "type": "table"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "description": "Total number of selected instances running each build
version over time.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "Instances",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "barWidthFactor": 0.6,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "stepAfter",
+ "lineWidth": 2,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "showValues": false,
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": 0
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 23,
+ "x": 0,
+ "y": 14
+ },
+ "id": 6,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "hideZeros": false,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "pluginVersion": "12.3.1",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr": "count by (version)
(ozone_build_info{instance=~\"$instance\"})",
+ "legendFormat": "{{version}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Instances Per Version Over Time",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 23
+ },
+ "id": 9,
+ "panels": [],
+ "title": "Finalization Status",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "description": "Total number of selected instances which have finalized.
Recon and S3 gateway are excluded.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "unit": "short"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "finalized"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "green",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "unfinalized"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "semi-dark-yellow",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 9,
+ "x": 0,
+ "y": 24
+ },
+ "id": 3,
+ "options": {
+ "displayLabels": [
+ "name"
+ ],
+ "legend": {
+ "calcs": [],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true,
+ "values": [
+ "value",
+ "percent"
+ ]
+ },
+ "pieType": "pie",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "sort": "desc",
+ "tooltip": {
+ "hideZeros": false,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "pluginVersion": "12.3.1",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr":
"sum((component_version_manager_metrics_software_version{instance=~\"$instance\"}
== bool
component_version_manager_metrics_apparent_version{instance=~\"$instance\"}) *
on(instance) group_left() (ozone_build_info{component!~\"recon\"}))",
+ "instant": true,
+ "legendFormat": "finalized",
+ "range": false,
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr":
"count(component_version_manager_metrics_software_version{instance=~\"$instance\"}
* on(instance) group_left() (ozone_build_info{component!~\"recon\"})) -
sum((component_version_manager_metrics_software_version{instance=~\"$instance\"}
== bool
component_version_manager_metrics_apparent_version{instance=~\"$instance\"}) *
on(instance) group_left() (ozone_build_info{component!~\"recon\"}))",
+ "instant": true,
+ "legendFormat": "unfinalized",
+ "range": false,
+ "refId": "B"
+ }
+ ],
+ "title": "Finalized vs Total Instances",
+ "type": "piechart"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "description": "Finalization status of each selected instance. All
instances except S3 Gateway and Recon finalize automatically when a finalize
command is given.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "custom": {
+ "align": "left",
+ "cellOptions": {
+ "type": "auto"
+ },
+ "footer": {
+ "reducers": []
+ },
+ "inspect": false
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": 0
+ }
+ ]
+ }
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Finalized?"
+ },
+ "properties": [
+ {
+ "id": "custom.cellOptions",
+ "value": {
+ "type": "color-text"
+ }
+ },
+ {
+ "id": "mappings",
+ "value": [
+ {
+ "options": {
+ "0": {
+ "color": "red",
+ "index": 0,
+ "text": "false"
+ },
+ "1": {
+ "color": "green",
+ "index": 1,
+ "text": "true"
+ }
+ },
+ "type": "value"
+ }
+ ]
+ },
+ {
+ "id": "custom.width",
+ "value": 244
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Software Version"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 226
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Instance"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 492
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Apparent Version"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 439
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 14,
+ "x": 9,
+ "y": 24
+ },
+ "id": 10,
+ "options": {
+ "cellHeight": "sm",
+ "enablePagination": true,
+ "footer": {
+ "countRows": false,
+ "enablePagination": true,
+ "fields": "",
+ "reducer": [
+ "sum"
+ ],
+ "show": false
+ },
+ "showHeader": true,
+ "sortBy": [
+ {
+ "desc": true,
+ "displayName": "Finalized?"
+ }
+ ]
+ },
+ "pluginVersion": "12.3.1",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr":
"(component_version_manager_metrics_software_version{instance=~\"$instance\"}
== bool
component_version_manager_metrics_apparent_version{instance=~\"$instance\"}) *
on(instance) group_left() (ozone_build_info{component!~\"recon\"})",
+ "format": "table",
+ "instant": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Finalized Instances",
+ "transformations": [
+ {
+ "id": "organize",
+ "options": {
+ "excludeByName": {
+ "Time": true,
+ "__name__": true,
+ "context": true,
+ "exported_component": true,
+ "hostname": true,
+ "job": true,
+ "revision": true,
+ "version": true
+ },
+ "indexByName": {
+ "Value": 2,
+ "component": 0,
+ "instance": 1
+ },
+ "renameByName": {
+ "Value": "Finalized?",
+ "component": "Component",
+ "instance": "Instance"
+ }
+ }
+ }
+ ],
+ "type": "table"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "description": "Number of selected instances which have finalized over
time (green), stacked with the number still pending finalization (yellow). The
top of the stack is the total eligible instance count.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "Instances",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "barWidthFactor": 0.6,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "stepAfter",
+ "lineWidth": 2,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "showValues": false,
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": 0
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "finalized"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "green",
+ "mode": "fixed"
+ }
+ },
+ {
+ "id": "custom.fillOpacity",
+ "value": 25
+ },
+ {
+ "id": "custom.stacking",
+ "value": {
+ "group": "A",
+ "mode": "normal"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "remaining"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "yellow",
+ "mode": "fixed"
+ }
+ },
+ {
+ "id": "custom.fillOpacity",
+ "value": 25
+ },
+ {
+ "id": "custom.lineWidth",
+ "value": 0
+ },
+ {
+ "id": "custom.showPoints",
+ "value": "never"
+ },
+ {
+ "id": "custom.stacking",
+ "value": {
+ "group": "A",
+ "mode": "normal"
+ }
+ },
+ {
+ "id": "custom.hideFrom",
+ "value": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 23,
+ "x": 0,
+ "y": 32
+ },
+ "id": 11,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "hideZeros": false,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "pluginVersion": "12.3.1",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr":
"count(((component_version_manager_metrics_software_version{instance=~\"$instance\"}
== bool
component_version_manager_metrics_apparent_version{instance=~\"$instance\"}) *
on(instance) group_left() (ozone_build_info{component!~\"recon\"})) == 1) or
vector(0)",
+ "legendFormat": "finalized",
+ "range": true,
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr":
"count(component_version_manager_metrics_software_version{instance=~\"$instance\"}
* on(instance) group_left() (ozone_build_info{component!~\"recon\"})) -
(count(((component_version_manager_metrics_software_version{instance=~\"$instance\"}
== bool
component_version_manager_metrics_apparent_version{instance=~\"$instance\"}) *
on(instance) group_left() (ozone_build_info{component!~\"recon\"})) == 1) or
vector(0))",
+ "legendFormat": "remaining",
+ "range": true,
+ "refId": "C"
+ }
+ ],
+ "title": "Finalized vs Total Instances Over Time",
+ "type": "timeseries"
+ }
+ ],
+ "preload": false,
+ "refresh": "30s",
+ "schemaVersion": 42,
+ "tags": [
+ "ozone",
+ "upgrade"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": {
+ "type": "prometheus"
+ },
+ "definition": "label_values(ozone_build_info, component)",
+ "includeAll": true,
+ "label": "component",
+ "multi": true,
+ "name": "component",
+ "options": [],
+ "query": {
+ "query": "label_values(ozone_build_info, component)",
+ "refId": "StandardVariableQuery"
+ },
+ "refresh": 1,
+ "regex": "",
+ "sort": 1,
+ "type": "query"
+ },
+ {
+ "current": {
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": {
+ "type": "prometheus"
+ },
+ "definition":
"label_values(ozone_build_info{component=~\"$component\"}, instance)",
+ "includeAll": true,
+ "label": "instance",
+ "multi": true,
+ "name": "instance",
+ "options": [],
+ "query": {
+ "query": "label_values(ozone_build_info{component=~\"$component\"},
instance)",
+ "refId": "StandardVariableQuery"
+ },
+ "refresh": 1,
+ "regex": "",
+ "sort": 1,
+ "type": "query"
+ }
+ ]
+ },
+ "time": {
+ "from": "now-30m",
+ "to": "now"
+ },
+ "timepicker": {},
+ "timezone": "",
+ "title": "Ozone - Rolling Upgrade",
+ "uid": "ozone-rolling-upgrade",
+ "version": 1
+}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
index 7725f7835ac..1facc9e3dfb 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
@@ -86,6 +86,8 @@ public class OMMetrics implements OmMetadataReaderMetrics {
private @Metric MutableCounterLong numListSnapshotDiffJobs;
private @Metric MutableGaugeInt numSnapshotCacheSize;
+ @Metric("Set to 1 if OM is monitoring ongoing upgrade finalization, 0
otherwise")
+ private MutableGaugeInt finalizationInProgress;
private @Metric MutableCounterLong numGetFileStatus;
private @Metric MutableCounterLong numCreateDirectory;
private @Metric MutableCounterLong numCreateFile;
@@ -624,6 +626,14 @@ public void decNumSnapshotCacheSize() {
numSnapshotCacheSize.decr();
}
+ public void setFinalizationInProgress(boolean inProgress) {
+ finalizationInProgress.set(inProgress ? 1 : 0);
+ }
+
+ public int getFinalizationInProgress() {
+ return finalizationInProgress.value();
+ }
+
public void incNumCompleteMultipartUploadFails() {
numCompleteMultipartUploadFails.incr();
}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index 423a879e0dd..64953dea840 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -45,6 +45,7 @@
import static
org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SCM_BLOCK_SIZE_DEFAULT;
import static org.apache.hadoop.ozone.OzoneConsts.DB_TRANSIENT_MARKER;
import static org.apache.hadoop.ozone.OzoneConsts.DEFAULT_OM_UPDATE_ID;
+import static org.apache.hadoop.ozone.OzoneConsts.FINALIZATION_IN_PROGRESS_KEY;
import static org.apache.hadoop.ozone.OzoneConsts.OM_DB_NAME;
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
import static org.apache.hadoop.ozone.OzoneConsts.OM_METRICS_FILE;
@@ -964,6 +965,8 @@ private void instantiateServices(boolean withNewSnapshot)
throws IOException {
new OmMetadataManagerImpl(configuration, this);
this.metadataManager = metadataManagerImpl;
versionManager.validateDBVersion(metadataManager.getMetaTable());
+ metrics.setFinalizationInProgress(
+ metadataManager.getMetaTable().get(FINALIZATION_IN_PROGRESS_KEY) !=
null);
LOG.info("S3 Multi-Tenancy is {}",
isS3MultiTenancyEnabled ? "enabled" : "disabled");
if (isS3MultiTenancyEnabled) {
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMFinalizeUpgradeRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMFinalizeUpgradeRequest.java
index 0aab6e4cdc3..06c3a9bcaf5 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMFinalizeUpgradeRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMFinalizeUpgradeRequest.java
@@ -99,6 +99,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager
ozoneManager, Execut
// Clear the finalization_in_progress key from the cache
omMetadataManager.getMetaTable().addCacheEntry(
new CacheKey<>(OzoneConsts.FINALIZATION_IN_PROGRESS_KEY),
CacheValue.get(context.getIndex()));
+ ozoneManager.getMetrics().setFinalizationInProgress(false);
FinalizeUpgradeResponse omResponse =
FinalizeUpgradeResponse.newBuilder()
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMStartFinalizeUpgradeRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMStartFinalizeUpgradeRequest.java
index aa3849d935c..ef2e016fbbd 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMStartFinalizeUpgradeRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMStartFinalizeUpgradeRequest.java
@@ -80,6 +80,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager
ozoneManager, Execut
OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
omMetadataManager.getMetaTable().addCacheEntry(
new CacheKey<>(OzoneConsts.FINALIZATION_IN_PROGRESS_KEY),
CacheValue.get(context.getIndex(), "ignored"));
+ ozoneManager.getMetrics().setFinalizationInProgress(true);
OzoneManagerProtocolProtos.StartFinalizeUpgradeResponse omResponse =
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHttpServer.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHttpServer.java
index a9c1cf2e205..aac504c9cec 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHttpServer.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHttpServer.java
@@ -96,9 +96,7 @@ public static Collection<Object[]> policy() {
@MethodSource("policy")
public void testHttpPolicy(HttpConfig.Policy policy) throws Exception {
conf.set(OzoneConfigKeys.OZONE_HTTP_POLICY_KEY, policy.name());
- OzoneManagerHttpServer server = null;
- try {
- server = new OzoneManagerHttpServer(conf, null);
+ try (OzoneManagerHttpServer server = new OzoneManagerHttpServer(conf,
null)) {
DefaultMetricsSystem.initialize("TestOzoneManagerHttpServer");
server.start();
@@ -112,19 +110,13 @@ public void testHttpPolicy(HttpConfig.Policy policy)
throws Exception {
canAccess("https", server.getHttpsAddress())));
assertTrue(implies(policy.isHttpsEnabled(),
!canAccess("http", server.getHttpsAddress())));
- } finally {
- if (server != null) {
- server.stop();
- }
}
}
@Test
// Verify if jetty-dir will be created inside ozoneMetadataDirectory path
public void testJettyDirectoryCreation() throws Exception {
- OzoneManagerHttpServer server = null;
- try {
- server = new OzoneManagerHttpServer(conf, null);
+ try (OzoneManagerHttpServer server = new OzoneManagerHttpServer(conf,
null)) {
DefaultMetricsSystem.initialize("TestOzoneManagerHttpServer");
server.start();
// Checking if the /webserver directory does get created
@@ -135,10 +127,6 @@ public void testJettyDirectoryCreation() throws Exception {
String expectedJettyDirLocation =
ozoneMetadataDirectory.getAbsolutePath() + BaseHttpServer.SERVER_DIR;
assertEquals(expectedJettyDirLocation, server.getJettyBaseTmpDir());
- } finally {
- if (server != null) {
- server.stop();
- }
}
}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMFinalizeUpgradeRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMFinalizeUpgradeRequest.java
index 84337357751..2879a4e3d96 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMFinalizeUpgradeRequest.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMFinalizeUpgradeRequest.java
@@ -17,6 +17,7 @@
package org.apache.hadoop.ozone.om.request.upgrade;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -55,14 +56,19 @@ public void testFinalizationInProgressKeyRemoved() throws
IOException {
omMetadataManager.getMetaTable().put(OzoneConsts.FINALIZATION_IN_PROGRESS_KEY,
"ignored");
omMetadataManager.getMetaTable().addCacheEntry(
new CacheKey<>(OzoneConsts.FINALIZATION_IN_PROGRESS_KEY),
CacheValue.get(1, "ignored"));
+ omMetrics.setFinalizationInProgress(true);
String progressKey =
omMetadataManager.getMetaTable().get(OzoneConsts.FINALIZATION_IN_PROGRESS_KEY);
assertNotNull(progressKey);
+ assertEquals(1, omMetrics.getFinalizationInProgress(),
+ "metric should be 1 before finalizing");
submitRequest();
progressKey =
omMetadataManager.getMetaTable().get(OzoneConsts.FINALIZATION_IN_PROGRESS_KEY);
assertNull(progressKey);
+ assertEquals(0, omMetrics.getFinalizationInProgress(),
+ "metric should be 0 after finalizing");
}
private void submitRequest() throws IOException {
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMStartFinalizeUpgradeRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMStartFinalizeUpgradeRequest.java
index 44b206052c7..a71110a9759 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMStartFinalizeUpgradeRequest.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMStartFinalizeUpgradeRequest.java
@@ -68,11 +68,15 @@ public void
testValidateAndUpdateCacheAddsFinalizationInProgressKey() throws IOE
assertNull(omMetadataManager.getMetaTable().get(OzoneConsts.FINALIZATION_IN_PROGRESS_KEY),
"key should not exist before the request");
+ assertEquals(0, omMetrics.getFinalizationInProgress(),
+ "metric should be 0 before the request");
submitRequest();
assertNotNull(omMetadataManager.getMetaTable().get(OzoneConsts.FINALIZATION_IN_PROGRESS_KEY),
"key should be present in the cache after validateAndUpdateCache");
+ assertEquals(1, omMetrics.getFinalizationInProgress(),
+ "metric should be 1 after the request");
}
@Test
diff --git
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/Gateway.java
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/Gateway.java
index e2c5ce4d49a..1a4e690c34a 100644
---
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/Gateway.java
+++
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/Gateway.java
@@ -37,6 +37,7 @@
import org.apache.hadoop.hdds.utils.NettyMetrics;
import org.apache.hadoop.ozone.OzoneSecurityUtil;
import org.apache.hadoop.ozone.s3.metrics.S3GatewayMetrics;
+import org.apache.hadoop.ozone.s3.metrics.S3GatewayVersionMetrics;
import org.apache.hadoop.ozone.util.OzoneNetUtils;
import org.apache.hadoop.ozone.util.OzoneVersionInfo;
import org.apache.hadoop.ozone.util.ShutdownHookManager;
@@ -63,6 +64,7 @@ public class Gateway extends GenericCli implements
Callable<Void> {
/** Servlets and static content on separate port. */
private BaseHttpServer contentServer;
private S3GatewayMetrics metrics;
+ private S3GatewayVersionMetrics versionMetrics;
private NettyMetrics nettyMetrics;
private final JvmPauseMonitor jvmPauseMonitor = newJvmPauseMonitor("S3G");
@@ -84,6 +86,7 @@ public Void call() throws Exception {
httpServer = new
S3GatewayHttpServer(OzoneConfigurationHolder.configuration(), "s3gateway");
contentServer = new
S3GatewayWebAdminServer(OzoneConfigurationHolder.configuration(), "s3g-web");
metrics =
S3GatewayMetrics.create(OzoneConfigurationHolder.configuration());
+ versionMetrics = S3GatewayVersionMetrics.create();
nettyMetrics = NettyMetrics.create();
start();
@@ -115,6 +118,9 @@ public void stop() throws Exception {
IOUtils.closeQuietly(httpServer, contentServer);
jvmPauseMonitor.stop();
S3GatewayMetrics.unRegister();
+ if (versionMetrics != null) {
+ versionMetrics.unRegister();
+ }
if (nettyMetrics != null) {
nettyMetrics.unregister();
}
diff --git
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/metrics/S3GatewayVersionMetrics.java
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/metrics/S3GatewayVersionMetrics.java
new file mode 100644
index 00000000000..6e99c8b5797
--- /dev/null
+++
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/metrics/S3GatewayVersionMetrics.java
@@ -0,0 +1,76 @@
+/*
+ * 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.hadoop.ozone.s3.metrics;
+
+import org.apache.hadoop.metrics2.MetricsCollector;
+import org.apache.hadoop.metrics2.MetricsInfo;
+import org.apache.hadoop.metrics2.MetricsRecordBuilder;
+import org.apache.hadoop.metrics2.MetricsSource;
+import org.apache.hadoop.metrics2.annotation.Metrics;
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.apache.hadoop.metrics2.lib.Interns;
+import org.apache.hadoop.ozone.ClientVersion;
+import org.apache.hadoop.ozone.OzoneConsts;
+
+/**
+ * Exposes the current S3 Gateway client-protocol version as a Prometheus
gauge.
+ *
+ * <p>S3G does not use the layout-version framework (no
ComponentVersionManager),
+ * so this metric fills the equivalent role for the ZDU dashboard: an operator
+ * can query {@code s3_gateway_client_version} to see which client protocol
+ * version each S3G instance is running.</p>
+ *
+ * <pre>
+ * s3_gateway_client_version{} 3
+ * </pre>
+ */
+@Metrics(about = "S3 Gateway Version Metrics", context = OzoneConsts.OZONE)
+public final class S3GatewayVersionMetrics implements MetricsSource {
+
+ public static final String METRICS_SOURCE_NAME = "S3GatewayVersion";
+
+ private static final MetricsInfo CLIENT_VERSION = Interns.info(
+ "ClientVersion",
+ "Current S3 Gateway client-protocol version in serialized int form.");
+
+ S3GatewayVersionMetrics() {
+ }
+
+ public static S3GatewayVersionMetrics create() {
+ S3GatewayVersionMetrics metrics = (S3GatewayVersionMetrics)
DefaultMetricsSystem.instance()
+ .getSource(METRICS_SOURCE_NAME);
+ if (metrics == null) {
+ return DefaultMetricsSystem.instance().register(
+ METRICS_SOURCE_NAME,
+ "S3 Gateway client-protocol version metrics.",
+ new S3GatewayVersionMetrics());
+ }
+ return metrics;
+ }
+
+ public void unRegister() {
+ DefaultMetricsSystem.instance().unregisterSource(METRICS_SOURCE_NAME);
+ }
+
+ @Override
+ public void getMetrics(MetricsCollector collector, boolean all) {
+ // Record name "S3Gateway" + gauge "ClientVersion" →
s3_gateway_client_version
+ MetricsRecordBuilder builder = collector.addRecord("S3Gateway");
+ builder.addGauge(CLIENT_VERSION, ClientVersion.CURRENT.serialize());
+ }
+}
diff --git
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayVersionMetrics.java
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayVersionMetrics.java
new file mode 100644
index 00000000000..a48657ce284
--- /dev/null
+++
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayVersionMetrics.java
@@ -0,0 +1,41 @@
+/*
+ * 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.hadoop.ozone.s3.metrics;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.hadoop.metrics2.impl.MetricsCollectorImpl;
+import org.apache.hadoop.ozone.ClientVersion;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for {@link S3GatewayVersionMetrics}.
+ */
+public class TestS3GatewayVersionMetrics {
+
+ @Test
+ public void testClientVersionGaugeValue() {
+ S3GatewayVersionMetrics metrics = new S3GatewayVersionMetrics();
+ MetricsCollectorImpl collector = new MetricsCollectorImpl();
+ metrics.getMetrics(collector, true);
+
+ String records = collector.getRecords().toString();
+ assertThat(records).contains("ClientVersion");
+
assertThat(records).contains(String.valueOf(ClientVersion.CURRENT.serialize()));
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]