You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sd...@apache.org on 2022/10/06 08:32:03 UTC
[ignite-3] branch main updated: IGNITE-17355 CLI management of metrics (#1081)
This is an automated email from the ASF dual-hosted git repository.
sdanilov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new d8ead0ab84 IGNITE-17355 CLI management of metrics (#1081)
d8ead0ab84 is described below
commit d8ead0ab84c0daa68e666495314e4c1df3d0c809
Author: Vadim Pakhnushev <86...@users.noreply.github.com>
AuthorDate: Thu Oct 6 11:31:57 2022 +0300
IGNITE-17355 CLI management of metrics (#1081)
---
.../cli/call/metric/ItMetricCallsTest.java | 91 ++++++++++++++++++
.../ItClusterConfigCommandNotInitializedTest.java | 2 +-
.../commands/metric/ItNodeMetricCommandTest.java | 70 ++++++++++++++
.../internal/rest/ItGeneratedRestClientTest.java | 26 ++++-
.../call/cluster/topology/LogicalTopologyCall.java | 5 +-
.../cluster/topology/PhysicalTopologyCall.java | 5 +-
.../call/cluster/topology/TopologyCallOutput.java | 70 --------------
.../metric/NodeMetricEnableCall.java} | 34 +++----
.../node/metric/NodeMetricEnableCallInput.java | 105 +++++++++++++++++++++
.../metric/NodeMetricListCall.java} | 28 +++---
.../cli/commands/metric/MetricSourceMixin.java | 44 +++++++++
.../internal/cli/commands/node/NodeCommand.java | 7 +-
.../cli/commands/node/NodeReplCommand.java | 7 +-
.../commands/node/metric/NodeMetricCommand.java} | 21 ++---
.../node/metric/NodeMetricDisableCommand.java | 53 +++++++++++
.../node/metric/NodeMetricDisableReplCommand.java | 54 +++++++++++
.../node/metric/NodeMetricEnableCommand.java | 53 +++++++++++
.../node/metric/NodeMetricEnableReplCommand.java | 54 +++++++++++
.../node/metric/NodeMetricListCommand.java | 52 ++++++++++
.../node/metric/NodeMetricListReplCommand.java | 53 +++++++++++
.../node/metric/NodeMetricReplCommand.java} | 21 ++---
.../cli/decorators/MetricListDecorator.java | 45 +++++++++
.../cli/commands/UrlOptionsNegativeTest.java | 12 +++
.../cli/deprecated/IgniteCliInterfaceTest.java | 61 ++++++++++++
modules/metrics/build.gradle | 5 +
modules/metrics/pom.xml | 10 ++
.../ignite/internal/metrics/MetricManager.java | 10 ++
.../ignite/internal/metrics/MetricRegistry.java | 18 +++-
.../internal/metrics/rest/MetricRestFactory.java} | 34 ++++---
.../metrics/rest/NodeMetricController.java | 61 ++++++++++++
.../rest/exception/MetricNotFoundException.java} | 22 ++---
.../handler/MetricNotFoundExceptionHandler.java | 45 +++++++++
.../internal/rest/api/metric/MetricSourceDto.java | 69 ++++++++++++++
.../internal/rest/api/metric/NodeMetricApi.java | 72 ++++++++++++++
modules/rest/openapi/openapi.yaml | 85 +++++++++++++++++
.../apache/ignite/internal/rest/RestComponent.java | 2 +
.../org/apache/ignite/internal/app/IgniteImpl.java | 25 +++--
37 files changed, 1252 insertions(+), 179 deletions(-)
diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/call/metric/ItMetricCallsTest.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/call/metric/ItMetricCallsTest.java
new file mode 100644
index 0000000000..1037927cff
--- /dev/null
+++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/call/metric/ItMetricCallsTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.ignite.internal.cli.call.metric;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import jakarta.inject.Inject;
+import java.util.List;
+import org.apache.ignite.internal.cli.call.CallInitializedIntegrationTestBase;
+import org.apache.ignite.internal.cli.call.node.metric.NodeMetricEnableCall;
+import org.apache.ignite.internal.cli.call.node.metric.NodeMetricEnableCallInput;
+import org.apache.ignite.internal.cli.call.node.metric.NodeMetricListCall;
+import org.apache.ignite.internal.cli.core.call.CallOutput;
+import org.apache.ignite.internal.cli.core.call.StringCallInput;
+import org.apache.ignite.rest.client.model.MetricSource;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+/** Tests for {@link NodeMetricListCall} and {@link NodeMetricEnableCall}. */
+class ItMetricCallsTest extends CallInitializedIntegrationTestBase {
+
+ @Inject
+ NodeMetricListCall nodeMetricListCall;
+
+ @Inject
+ NodeMetricEnableCall nodeMetricEnableCall;
+
+ @Test
+ @DisplayName("Should display empty node metric list when cluster is up and running")
+ void nodeMetricList() {
+ // Given
+ var input = new StringCallInput(NODE_URL);
+
+ // When
+ CallOutput<List<MetricSource>> output = nodeMetricListCall.execute(input);
+
+ // Then
+ assertThat(output.hasError()).isFalse();
+ // And
+ assertThat(output.body()).isEmpty();
+ }
+
+ @Test
+ @DisplayName("Should display error message when enabling nonexistent metric source and is cluster up and running")
+ void nodeMetricEnable() {
+ // Given
+ var input = NodeMetricEnableCallInput.builder()
+ .endpointUrl(NODE_URL)
+ .srcName("no.such.metric")
+ .enable(true)
+ .build();
+
+ // When
+ CallOutput<String> output = nodeMetricEnableCall.execute(input);
+
+ // Then
+ assertThat(output.hasError()).isTrue();
+ }
+
+ @Test
+ @DisplayName("Should display error message when disabling nonexistent metric source and is cluster up and running")
+ void nodeMetricDisable() {
+ // Given
+ var input = NodeMetricEnableCallInput.builder()
+ .endpointUrl(NODE_URL)
+ .srcName("no.such.metric")
+ .enable(false)
+ .build();
+
+ // When
+ CallOutput<String> output = nodeMetricEnableCall.execute(input);
+
+ // Then
+ assertThat(output.hasError()).isTrue();
+ }
+}
diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/cluster/config/ItClusterConfigCommandNotInitializedTest.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/cluster/config/ItClusterConfigCommandNotInitializedTest.java
index 5e0e44cd7e..132666134d 100644
--- a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/cluster/config/ItClusterConfigCommandNotInitializedTest.java
+++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/cluster/config/ItClusterConfigCommandNotInitializedTest.java
@@ -24,7 +24,7 @@ import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
- * Tests for {@link ClusterConfigSubCommand} for the cluster that is not initialized.
+ * Tests for {@link ClusterConfigCommand} for the cluster that is not initialized.
*/
class ItClusterConfigCommandNotInitializedTest extends CliCommandTestNotInitializedIntegrationBase {
@Test
diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/metric/ItNodeMetricCommandTest.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/metric/ItNodeMetricCommandTest.java
new file mode 100644
index 0000000000..18d6aa8251
--- /dev/null
+++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/metric/ItNodeMetricCommandTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.ignite.internal.cli.commands.metric;
+
+import static org.junit.jupiter.api.Assertions.assertAll;
+
+import org.apache.ignite.internal.cli.commands.CliCommandTestInitializedIntegrationBase;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+/** Tests for node metric commands. */
+class ItNodeMetricCommandTest extends CliCommandTestInitializedIntegrationBase {
+ @Test
+ @DisplayName("Should display empty node metric list when valid node-url is given")
+ void nodeMetricList() {
+ // When list node metric with valid url
+ execute("node", "metric", "list", "--node-url", NODE_URL);
+
+ // Then
+ assertAll(
+ this::assertExitCodeIsZero,
+ this::assertErrOutputIsEmpty,
+ () -> assertOutputIs("Enabled metric sources:" + System.lineSeparator()
+ + "Disabled metric sources:" + System.lineSeparator())
+ );
+ }
+
+ @Test
+ @DisplayName("Should display error message when enabling nonexistent metric source and valid node-url is given")
+ void nodeMetricEnableNonexistent() {
+ // When list node metric with valid url
+ execute("node", "metric", "enable", "no.such.metric", "--node-url", NODE_URL);
+
+ // Then
+ assertAll(
+ () -> assertExitCodeIs(1),
+ () -> assertErrOutputContains("Metrics source with given name doesn't exist: no.such.metric"),
+ this::assertOutputIsEmpty
+ );
+ }
+
+ @Test
+ @DisplayName("Should display error message when disabling nonexistent metric source and valid node-url is given")
+ void nodeMetricDisableNonexistent() {
+ // When list node metric with valid url
+ execute("node", "metric", "disable", "no.such.metric", "--node-url", NODE_URL);
+
+ // Then
+ assertAll(
+ () -> assertExitCodeIs(1),
+ () -> assertErrOutputContains("Metrics source with given name doesn't exist: no.such.metric"),
+ this::assertOutputIsEmpty
+ );
+ }
+}
diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/rest/ItGeneratedRestClientTest.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/rest/ItGeneratedRestClientTest.java
index ba4961a06e..72a18a67e4 100644
--- a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/rest/ItGeneratedRestClientTest.java
+++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/rest/ItGeneratedRestClientTest.java
@@ -23,6 +23,7 @@ import static org.apache.ignite.internal.testframework.matchers.CompletableFutur
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
@@ -49,6 +50,7 @@ import org.apache.ignite.rest.client.api.ClusterConfigurationApi;
import org.apache.ignite.rest.client.api.ClusterManagementApi;
import org.apache.ignite.rest.client.api.NodeConfigurationApi;
import org.apache.ignite.rest.client.api.NodeManagementApi;
+import org.apache.ignite.rest.client.api.NodeMetricApi;
import org.apache.ignite.rest.client.api.TopologyApi;
import org.apache.ignite.rest.client.invoker.ApiClient;
import org.apache.ignite.rest.client.invoker.ApiException;
@@ -81,8 +83,6 @@ public class ItGeneratedRestClientTest {
@WorkDirectory
private Path workDir;
- private CompletableFuture<Ignite> ignite;
-
private ClusterConfigurationApi clusterConfigurationApi;
private NodeConfigurationApi nodeConfigurationApi;
@@ -93,6 +93,8 @@ public class ItGeneratedRestClientTest {
private TopologyApi topologyApi;
+ private NodeMetricApi nodeMetricApi;
+
private ObjectMapper objectMapper;
private String firstNodeName;
@@ -135,6 +137,7 @@ public class ItGeneratedRestClientTest {
clusterManagementApi = new ClusterManagementApi(client);
nodeManagementApi = new NodeManagementApi(client);
topologyApi = new TopologyApi(client);
+ nodeMetricApi = new NodeMetricApi(client);
objectMapper = new ObjectMapper();
}
@@ -322,6 +325,25 @@ public class ItGeneratedRestClientTest {
assertThat(nodeManagementApi.nodeVersion(), is(notNullValue()));
}
+ @Test
+ void nodeMetricList() throws ApiException {
+ assertThat(nodeMetricApi.listNodeMetrics(), empty());
+ }
+
+ @Test
+ void enableInvalidNodeMetric() throws JsonProcessingException {
+ var thrown = assertThrows(
+ ApiException.class,
+ () -> nodeMetricApi.enableNodeMetric("no.such.metric")
+ );
+
+ assertThat(thrown.getCode(), equalTo(404));
+
+ Problem problem = objectMapper.readValue(thrown.getResponseBody(), Problem.class);
+ assertThat(problem.getStatus(), equalTo(404));
+ assertThat(problem.getDetail(), containsString("Metrics source with given name doesn't exist: no.such.metric"));
+ }
+
private CompletableFuture<Ignite> startNodeAsync(TestInfo testInfo, int index) {
String nodeName = testNodeName(testInfo, BASE_PORT + index);
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/LogicalTopologyCall.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/LogicalTopologyCall.java
index 1daefe6b05..2d36557cfe 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/LogicalTopologyCall.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/LogicalTopologyCall.java
@@ -21,6 +21,7 @@ import jakarta.inject.Singleton;
import java.util.List;
import org.apache.ignite.internal.cli.core.call.Call;
import org.apache.ignite.internal.cli.core.call.CallOutput;
+import org.apache.ignite.internal.cli.core.call.DefaultCallOutput;
import org.apache.ignite.internal.cli.core.call.UrlCallInput;
import org.apache.ignite.internal.cli.core.exception.IgniteCliApiException;
import org.apache.ignite.rest.client.api.TopologyApi;
@@ -39,9 +40,9 @@ public class LogicalTopologyCall implements Call<UrlCallInput, List<ClusterNode>
public CallOutput<List<ClusterNode>> execute(UrlCallInput input) {
String clusterUrl = input.getUrl();
try {
- return TopologyCallOutput.success(fetchLogicalTopology(clusterUrl));
+ return DefaultCallOutput.success(fetchLogicalTopology(clusterUrl));
} catch (ApiException | IllegalArgumentException e) {
- return TopologyCallOutput.failure(new IgniteCliApiException(e, clusterUrl));
+ return DefaultCallOutput.failure(new IgniteCliApiException(e, clusterUrl));
}
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/PhysicalTopologyCall.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/PhysicalTopologyCall.java
index cd6529e55b..a5efa7c555 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/PhysicalTopologyCall.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/PhysicalTopologyCall.java
@@ -21,6 +21,7 @@ import jakarta.inject.Singleton;
import java.util.List;
import org.apache.ignite.internal.cli.core.call.Call;
import org.apache.ignite.internal.cli.core.call.CallOutput;
+import org.apache.ignite.internal.cli.core.call.DefaultCallOutput;
import org.apache.ignite.internal.cli.core.call.UrlCallInput;
import org.apache.ignite.internal.cli.core.exception.IgniteCliApiException;
import org.apache.ignite.rest.client.api.TopologyApi;
@@ -39,9 +40,9 @@ public class PhysicalTopologyCall implements Call<UrlCallInput, List<ClusterNode
public CallOutput<List<ClusterNode>> execute(UrlCallInput input) {
String clusterUrl = input.getUrl();
try {
- return TopologyCallOutput.success(fetchPhysicalTopology(clusterUrl));
+ return DefaultCallOutput.success(fetchPhysicalTopology(clusterUrl));
} catch (ApiException | IllegalArgumentException e) {
- return TopologyCallOutput.failure(new IgniteCliApiException(e, clusterUrl));
+ return DefaultCallOutput.failure(new IgniteCliApiException(e, clusterUrl));
}
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/TopologyCallOutput.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/TopologyCallOutput.java
deleted file mode 100644
index 40d1b4ff37..0000000000
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/TopologyCallOutput.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.ignite.internal.cli.call.cluster.topology;
-
-import java.util.List;
-import org.apache.ignite.internal.cli.core.call.CallOutput;
-import org.apache.ignite.internal.cli.core.exception.IgniteCliApiException;
-import org.apache.ignite.rest.client.model.ClusterNode;
-
-/**
- * Output fot the topology calls.
- */
-public class TopologyCallOutput implements CallOutput<List<ClusterNode>> {
- private final Throwable error;
-
- private final List<ClusterNode> topology;
-
- private TopologyCallOutput(List<ClusterNode> topology) {
- this.topology = topology;
- error = null;
- }
-
- private TopologyCallOutput(Exception error) {
- this.error = error;
- this.topology = null;
- }
-
- public static TopologyCallOutput success(List<ClusterNode> topology) {
- return new TopologyCallOutput(topology);
- }
-
- public static TopologyCallOutput failure(IgniteCliApiException e) {
- return new TopologyCallOutput(e);
- }
-
- @Override
- public List<ClusterNode> body() {
- return topology;
- }
-
- @Override
- public boolean hasError() {
- return error != null;
- }
-
- @Override
- public boolean isEmpty() {
- return topology != null && topology.isEmpty();
- }
-
- @Override
- public Throwable errorCause() {
- return error;
- }
-}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/LogicalTopologyCall.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/node/metric/NodeMetricEnableCall.java
similarity index 54%
copy from modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/LogicalTopologyCall.java
copy to modules/cli/src/main/java/org/apache/ignite/internal/cli/call/node/metric/NodeMetricEnableCall.java
index 1daefe6b05..cd22775217 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/LogicalTopologyCall.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/node/metric/NodeMetricEnableCall.java
@@ -15,37 +15,39 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.cli.call.cluster.topology;
+package org.apache.ignite.internal.cli.call.node.metric;
import jakarta.inject.Singleton;
-import java.util.List;
import org.apache.ignite.internal.cli.core.call.Call;
import org.apache.ignite.internal.cli.core.call.CallOutput;
-import org.apache.ignite.internal.cli.core.call.UrlCallInput;
+import org.apache.ignite.internal.cli.core.call.DefaultCallOutput;
import org.apache.ignite.internal.cli.core.exception.IgniteCliApiException;
-import org.apache.ignite.rest.client.api.TopologyApi;
+import org.apache.ignite.rest.client.api.NodeMetricApi;
import org.apache.ignite.rest.client.invoker.ApiException;
import org.apache.ignite.rest.client.invoker.Configuration;
-import org.apache.ignite.rest.client.model.ClusterNode;
-/**
- * Shows logical cluster topology.
- */
+/** Enables or disables metric source. */
@Singleton
-public class LogicalTopologyCall implements Call<UrlCallInput, List<ClusterNode>> {
-
+public class NodeMetricEnableCall implements Call<NodeMetricEnableCallInput, String> {
/** {@inheritDoc} */
@Override
- public CallOutput<List<ClusterNode>> execute(UrlCallInput input) {
- String clusterUrl = input.getUrl();
+ public CallOutput<String> execute(NodeMetricEnableCallInput input) {
+ NodeMetricApi api = createApiClient(input);
+
try {
- return TopologyCallOutput.success(fetchLogicalTopology(clusterUrl));
+ if (input.getEnable()) {
+ api.enableNodeMetric(input.getSrcName());
+ } else {
+ api.disableNodeMetric(input.getSrcName());
+ }
+ String message = input.getEnable() ? "enabled" : "disabled";
+ return DefaultCallOutput.success("Metric source was " + message + " successfully");
} catch (ApiException | IllegalArgumentException e) {
- return TopologyCallOutput.failure(new IgniteCliApiException(e, clusterUrl));
+ return DefaultCallOutput.failure(new IgniteCliApiException(e, input.getEndpointUrl()));
}
}
- private List<ClusterNode> fetchLogicalTopology(String url) throws ApiException {
- return new TopologyApi(Configuration.getDefaultApiClient().setBasePath(url)).logical();
+ private static NodeMetricApi createApiClient(NodeMetricEnableCallInput input) {
+ return new NodeMetricApi(Configuration.getDefaultApiClient().setBasePath(input.getEndpointUrl()));
}
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/node/metric/NodeMetricEnableCallInput.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/node/metric/NodeMetricEnableCallInput.java
new file mode 100644
index 0000000000..b31562415d
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/node/metric/NodeMetricEnableCallInput.java
@@ -0,0 +1,105 @@
+/*
+ * 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.ignite.internal.cli.call.node.metric;
+
+import org.apache.ignite.internal.cli.core.call.CallInput;
+
+/** Input for {@link NodeMetricEnableCall}. */
+public class NodeMetricEnableCallInput implements CallInput {
+ /** Metric source name. */
+ private final String srcName;
+
+ /** Enable or disable metric source. */
+ private final boolean enable;
+
+ /** endpoint URL. */
+ private final String endpointUrl;
+
+ private NodeMetricEnableCallInput(String srcName, boolean enable, String endpointUrl) {
+ this.srcName = srcName;
+ this.enable = enable;
+ this.endpointUrl = endpointUrl;
+ }
+
+ /**
+ * Builder method.
+ *
+ * @return Builder for {@link NodeMetricEnableCallInput}.
+ */
+ public static NodeMetricEnableCallInputBuilder builder() {
+ return new NodeMetricEnableCallInputBuilder();
+ }
+
+ /**
+ * Get configuration.
+ *
+ * @return Configuration to update.
+ */
+ public String getSrcName() {
+ return srcName;
+ }
+
+ /**
+ * Get enable flag.
+ *
+ * @return {@code true} if metric source needs to be enabled, {@code false} if it needs to be disabled.
+ */
+ public boolean getEnable() {
+ return enable;
+ }
+
+ /**
+ * Get endpoint URL.
+ *
+ * @return endpoint URL.
+ */
+ public String getEndpointUrl() {
+ return endpointUrl;
+ }
+
+ /**
+ * Builder for {@link NodeMetricEnableCallInput}.
+ */
+ public static class NodeMetricEnableCallInputBuilder {
+
+ private String srcName;
+
+ private boolean enable;
+
+ private String endpointUrl;
+
+ public NodeMetricEnableCallInputBuilder srcName(String srcName) {
+ this.srcName = srcName;
+ return this;
+ }
+
+ public NodeMetricEnableCallInputBuilder enable(boolean enable) {
+ this.enable = enable;
+ return this;
+ }
+
+ public NodeMetricEnableCallInputBuilder endpointUrl(String endpointUrl) {
+ this.endpointUrl = endpointUrl;
+ return this;
+ }
+
+ public NodeMetricEnableCallInput build() {
+ return new NodeMetricEnableCallInput(srcName, enable, endpointUrl);
+ }
+ }
+}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/LogicalTopologyCall.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/node/metric/NodeMetricListCall.java
similarity index 59%
copy from modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/LogicalTopologyCall.java
copy to modules/cli/src/main/java/org/apache/ignite/internal/cli/call/node/metric/NodeMetricListCall.java
index 1daefe6b05..20cba1ce34 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/topology/LogicalTopologyCall.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/node/metric/NodeMetricListCall.java
@@ -15,37 +15,35 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.cli.call.cluster.topology;
+package org.apache.ignite.internal.cli.call.node.metric;
import jakarta.inject.Singleton;
import java.util.List;
import org.apache.ignite.internal.cli.core.call.Call;
import org.apache.ignite.internal.cli.core.call.CallOutput;
-import org.apache.ignite.internal.cli.core.call.UrlCallInput;
+import org.apache.ignite.internal.cli.core.call.DefaultCallOutput;
+import org.apache.ignite.internal.cli.core.call.StringCallInput;
import org.apache.ignite.internal.cli.core.exception.IgniteCliApiException;
-import org.apache.ignite.rest.client.api.TopologyApi;
+import org.apache.ignite.rest.client.api.NodeMetricApi;
import org.apache.ignite.rest.client.invoker.ApiException;
import org.apache.ignite.rest.client.invoker.Configuration;
-import org.apache.ignite.rest.client.model.ClusterNode;
+import org.apache.ignite.rest.client.model.MetricSource;
-/**
- * Shows logical cluster topology.
- */
+/** Lists node metric sources. */
@Singleton
-public class LogicalTopologyCall implements Call<UrlCallInput, List<ClusterNode>> {
-
+public class NodeMetricListCall implements Call<StringCallInput, List<MetricSource>> {
/** {@inheritDoc} */
@Override
- public CallOutput<List<ClusterNode>> execute(UrlCallInput input) {
- String clusterUrl = input.getUrl();
+ public CallOutput<List<MetricSource>> execute(StringCallInput input) {
+
try {
- return TopologyCallOutput.success(fetchLogicalTopology(clusterUrl));
+ return DefaultCallOutput.success(listNodeMetrics(input));
} catch (ApiException | IllegalArgumentException e) {
- return TopologyCallOutput.failure(new IgniteCliApiException(e, clusterUrl));
+ return DefaultCallOutput.failure(new IgniteCliApiException(e, input.getString()));
}
}
- private List<ClusterNode> fetchLogicalTopology(String url) throws ApiException {
- return new TopologyApi(Configuration.getDefaultApiClient().setBasePath(url)).logical();
+ private static List<MetricSource> listNodeMetrics(StringCallInput input) throws ApiException {
+ return new NodeMetricApi(Configuration.getDefaultApiClient().setBasePath(input.getString())).listNodeMetrics();
}
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/metric/MetricSourceMixin.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/metric/MetricSourceMixin.java
new file mode 100644
index 0000000000..b4a367a414
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/metric/MetricSourceMixin.java
@@ -0,0 +1,44 @@
+/*
+ * 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.ignite.internal.cli.commands.metric;
+
+import org.apache.ignite.internal.cli.call.node.metric.NodeMetricEnableCallInput;
+import picocli.CommandLine.Parameters;
+
+/** Mixin class for metric source name, provides source name parameter and constructs call input. */
+public class MetricSourceMixin {
+ /** Name of the metric source name. */
+ @Parameters(index = "0", description = "Metric source name")
+ private String srcName;
+
+ public NodeMetricEnableCallInput buildEnableCallInput(String endpointUrl) {
+ return buildCallInput(endpointUrl, true);
+ }
+
+ public NodeMetricEnableCallInput buildDisableCallInput(String endpointUrl) {
+ return buildCallInput(endpointUrl, false);
+ }
+
+ private NodeMetricEnableCallInput buildCallInput(String endpointUrl, boolean enable) {
+ return NodeMetricEnableCallInput.builder()
+ .endpointUrl(endpointUrl)
+ .srcName(srcName)
+ .enable(enable)
+ .build();
+ }
+}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeCommand.java
index abbe1811c6..6aa9719bbf 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeCommand.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeCommand.java
@@ -19,16 +19,15 @@ package org.apache.ignite.internal.cli.commands.node;
import org.apache.ignite.cli.commands.node.version.NodeVersionCommand;
import org.apache.ignite.internal.cli.commands.node.config.NodeConfigCommand;
+import org.apache.ignite.internal.cli.commands.node.metric.NodeMetricCommand;
import org.apache.ignite.internal.cli.commands.node.status.NodeStatusCommand;
import org.apache.ignite.internal.cli.deprecated.spec.NodeCommandSpec;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
-/**
- * Node command.
- */
+/** Node command. */
@Command(name = "node",
- subcommands = {NodeConfigCommand.class, NodeStatusCommand.class, NodeVersionCommand.class},
+ subcommands = {NodeConfigCommand.class, NodeStatusCommand.class, NodeVersionCommand.class, NodeMetricCommand.class},
description = "Node operations")
public class NodeCommand {
@Mixin
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeReplCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeReplCommand.java
index 70f82aa242..0aa7d751ce 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeReplCommand.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeReplCommand.java
@@ -19,16 +19,15 @@ package org.apache.ignite.internal.cli.commands.node;
import org.apache.ignite.cli.commands.node.version.NodeVersionReplCommand;
import org.apache.ignite.internal.cli.commands.node.config.NodeConfigReplCommand;
+import org.apache.ignite.internal.cli.commands.node.metric.NodeMetricReplCommand;
import org.apache.ignite.internal.cli.commands.node.status.NodeStatusReplCommand;
import org.apache.ignite.internal.cli.deprecated.spec.NodeCommandSpec;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
-/**
- * Node command in REPL mode.
- */
+/** Node command in REPL mode. */
@Command(name = "node",
- subcommands = {NodeConfigReplCommand.class, NodeStatusReplCommand.class, NodeVersionReplCommand.class},
+ subcommands = {NodeConfigReplCommand.class, NodeStatusReplCommand.class, NodeVersionReplCommand.class, NodeMetricReplCommand.class},
description = "Node operations")
public class NodeReplCommand {
@Mixin
diff --git a/modules/metrics/build.gradle b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricCommand.java
similarity index 59%
copy from modules/metrics/build.gradle
copy to modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricCommand.java
index 7f5a8fa822..752dad0028 100644
--- a/modules/metrics/build.gradle
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricCommand.java
@@ -15,19 +15,14 @@
* limitations under the License.
*/
-apply from: "$rootDir/buildscripts/java-core.gradle"
-apply from: "$rootDir/buildscripts/java-junit5.gradle"
-apply from: "$rootDir/buildscripts/java-integration-test.gradle"
+package org.apache.ignite.internal.cli.commands.node.metric;
-dependencies {
- implementation project(':ignite-core')
- implementation project(':ignite-configuration')
- implementation project(':ignite-configuration-api')
- implementation libs.jetbrains.annotations
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import picocli.CommandLine.Command;
- testImplementation libs.hamcrest.core
- testImplementation libs.mockito.core
- testImplementation project(':ignite-core')
+/** Node metric command. */
+@Command(name = "metric",
+ subcommands = {NodeMetricEnableCommand.class, NodeMetricDisableCommand.class, NodeMetricListCommand.class},
+ description = "Node metric operations")
+public class NodeMetricCommand extends BaseCommand {
}
-
-description = 'ignite-metrics'
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricDisableCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricDisableCommand.java
new file mode 100644
index 0000000000..7b69bad6a6
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricDisableCommand.java
@@ -0,0 +1,53 @@
+/*
+ * 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.ignite.internal.cli.commands.node.metric;
+
+import jakarta.inject.Inject;
+import java.util.concurrent.Callable;
+import org.apache.ignite.internal.cli.call.node.metric.NodeMetricEnableCall;
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import org.apache.ignite.internal.cli.commands.metric.MetricSourceMixin;
+import org.apache.ignite.internal.cli.commands.node.NodeUrlProfileMixin;
+import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Mixin;
+
+/** Command that disables node metric source. */
+@Command(name = "disable", description = "Disables node metric source")
+public class NodeMetricDisableCommand extends BaseCommand implements Callable<Integer> {
+ /** Node URL option. */
+ @Mixin
+ private NodeUrlProfileMixin nodeUrl;
+
+ @Mixin
+ private MetricSourceMixin metricSource;
+
+ @Inject
+ private NodeMetricEnableCall call;
+
+ /** {@inheritDoc} */
+ @Override
+ public Integer call() {
+ return CallExecutionPipeline.builder(call)
+ .inputProvider(() -> metricSource.buildDisableCallInput(nodeUrl.getNodeUrl()))
+ .output(spec.commandLine().getOut())
+ .errOutput(spec.commandLine().getErr())
+ .build()
+ .runPipeline();
+ }
+}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricDisableReplCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricDisableReplCommand.java
new file mode 100644
index 0000000000..3a4c97735f
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricDisableReplCommand.java
@@ -0,0 +1,54 @@
+/*
+ * 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.ignite.internal.cli.commands.node.metric;
+
+import jakarta.inject.Inject;
+import org.apache.ignite.internal.cli.call.node.metric.NodeMetricEnableCall;
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import org.apache.ignite.internal.cli.commands.metric.MetricSourceMixin;
+import org.apache.ignite.internal.cli.commands.node.NodeUrlMixin;
+import org.apache.ignite.internal.cli.commands.questions.ConnectToClusterQuestion;
+import org.apache.ignite.internal.cli.core.flow.builder.Flows;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Mixin;
+
+/** Command that disables node metric source in REPL mode. */
+@Command(name = "disable", description = "Disables node metric source")
+public class NodeMetricDisableReplCommand extends BaseCommand implements Runnable {
+ /** Node URL option. */
+ @Mixin
+ private NodeUrlMixin nodeUrl;
+
+ @Mixin
+ private MetricSourceMixin metricSource;
+
+ @Inject
+ private NodeMetricEnableCall call;
+
+ @Inject
+ private ConnectToClusterQuestion question;
+
+ @Override
+ public void run() {
+ question.askQuestionIfNotConnected(nodeUrl.getNodeUrl())
+ .map(metricSource::buildDisableCallInput)
+ .then(Flows.fromCall(call))
+ .print()
+ .start();
+ }
+}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricEnableCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricEnableCommand.java
new file mode 100644
index 0000000000..5ab69a5bed
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricEnableCommand.java
@@ -0,0 +1,53 @@
+/*
+ * 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.ignite.internal.cli.commands.node.metric;
+
+import jakarta.inject.Inject;
+import java.util.concurrent.Callable;
+import org.apache.ignite.internal.cli.call.node.metric.NodeMetricEnableCall;
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import org.apache.ignite.internal.cli.commands.metric.MetricSourceMixin;
+import org.apache.ignite.internal.cli.commands.node.NodeUrlProfileMixin;
+import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Mixin;
+
+/** Command that enables node metric source. */
+@Command(name = "enable", description = "Enables node metric source")
+public class NodeMetricEnableCommand extends BaseCommand implements Callable<Integer> {
+ /** Node URL option. */
+ @Mixin
+ private NodeUrlProfileMixin nodeUrl;
+
+ @Mixin
+ private MetricSourceMixin metricSource;
+
+ @Inject
+ private NodeMetricEnableCall call;
+
+ /** {@inheritDoc} */
+ @Override
+ public Integer call() {
+ return CallExecutionPipeline.builder(call)
+ .inputProvider(() -> metricSource.buildEnableCallInput(nodeUrl.getNodeUrl()))
+ .output(spec.commandLine().getOut())
+ .errOutput(spec.commandLine().getErr())
+ .build()
+ .runPipeline();
+ }
+}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricEnableReplCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricEnableReplCommand.java
new file mode 100644
index 0000000000..09fd277774
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricEnableReplCommand.java
@@ -0,0 +1,54 @@
+/*
+ * 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.ignite.internal.cli.commands.node.metric;
+
+import jakarta.inject.Inject;
+import org.apache.ignite.internal.cli.call.node.metric.NodeMetricEnableCall;
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import org.apache.ignite.internal.cli.commands.metric.MetricSourceMixin;
+import org.apache.ignite.internal.cli.commands.node.NodeUrlMixin;
+import org.apache.ignite.internal.cli.commands.questions.ConnectToClusterQuestion;
+import org.apache.ignite.internal.cli.core.flow.builder.Flows;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Mixin;
+
+/** Command that enables node metric source in REPL mode. */
+@Command(name = "enable", description = "Enables node metric source")
+public class NodeMetricEnableReplCommand extends BaseCommand implements Runnable {
+ /** Node URL option. */
+ @Mixin
+ private NodeUrlMixin nodeUrl;
+
+ @Mixin
+ private MetricSourceMixin metricSource;
+
+ @Inject
+ private NodeMetricEnableCall call;
+
+ @Inject
+ private ConnectToClusterQuestion question;
+
+ @Override
+ public void run() {
+ question.askQuestionIfNotConnected(nodeUrl.getNodeUrl())
+ .map(metricSource::buildEnableCallInput)
+ .then(Flows.fromCall(call))
+ .print()
+ .start();
+ }
+}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricListCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricListCommand.java
new file mode 100644
index 0000000000..278c26a781
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricListCommand.java
@@ -0,0 +1,52 @@
+/*
+ * 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.ignite.internal.cli.commands.node.metric;
+
+import jakarta.inject.Inject;
+import java.util.concurrent.Callable;
+import org.apache.ignite.internal.cli.call.node.metric.NodeMetricListCall;
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import org.apache.ignite.internal.cli.commands.node.NodeUrlProfileMixin;
+import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
+import org.apache.ignite.internal.cli.core.call.StringCallInput;
+import org.apache.ignite.internal.cli.decorators.MetricListDecorator;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Mixin;
+
+/** Command that lists node metric sources. */
+@Command(name = "list", description = "Lists node metric sources")
+public class NodeMetricListCommand extends BaseCommand implements Callable<Integer> {
+ /** Node URL option. */
+ @Mixin
+ private NodeUrlProfileMixin nodeUrl;
+
+ @Inject
+ private NodeMetricListCall call;
+
+ /** {@inheritDoc} */
+ @Override
+ public Integer call() {
+ return CallExecutionPipeline.builder(call)
+ .inputProvider(() -> new StringCallInput(nodeUrl.getNodeUrl()))
+ .output(spec.commandLine().getOut())
+ .errOutput(spec.commandLine().getErr())
+ .decorator(new MetricListDecorator())
+ .build()
+ .runPipeline();
+ }
+}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricListReplCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricListReplCommand.java
new file mode 100644
index 0000000000..0ee87407d2
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricListReplCommand.java
@@ -0,0 +1,53 @@
+/*
+ * 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.ignite.internal.cli.commands.node.metric;
+
+import jakarta.inject.Inject;
+import org.apache.ignite.internal.cli.call.node.metric.NodeMetricListCall;
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import org.apache.ignite.internal.cli.commands.node.NodeUrlMixin;
+import org.apache.ignite.internal.cli.commands.questions.ConnectToClusterQuestion;
+import org.apache.ignite.internal.cli.core.call.StringCallInput;
+import org.apache.ignite.internal.cli.core.flow.builder.Flows;
+import org.apache.ignite.internal.cli.decorators.MetricListDecorator;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Mixin;
+
+/** Command that lists node metric sources in REPL mode. */
+@Command(name = "list", description = "Lists node metric sources")
+public class NodeMetricListReplCommand extends BaseCommand implements Runnable {
+ /** Node URL option. */
+ @Mixin
+ private NodeUrlMixin nodeUrl;
+
+ @Inject
+ private NodeMetricListCall call;
+
+ @Inject
+ private ConnectToClusterQuestion question;
+
+ /** {@inheritDoc} */
+ @Override
+ public void run() {
+ question.askQuestionIfNotConnected(nodeUrl.getNodeUrl())
+ .map(StringCallInput::new)
+ .then(Flows.fromCall(call))
+ .print(new MetricListDecorator())
+ .start();
+ }
+}
diff --git a/modules/metrics/build.gradle b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricReplCommand.java
similarity index 59%
copy from modules/metrics/build.gradle
copy to modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricReplCommand.java
index 7f5a8fa822..2a2154b7b4 100644
--- a/modules/metrics/build.gradle
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/metric/NodeMetricReplCommand.java
@@ -15,19 +15,14 @@
* limitations under the License.
*/
-apply from: "$rootDir/buildscripts/java-core.gradle"
-apply from: "$rootDir/buildscripts/java-junit5.gradle"
-apply from: "$rootDir/buildscripts/java-integration-test.gradle"
+package org.apache.ignite.internal.cli.commands.node.metric;
-dependencies {
- implementation project(':ignite-core')
- implementation project(':ignite-configuration')
- implementation project(':ignite-configuration-api')
- implementation libs.jetbrains.annotations
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import picocli.CommandLine.Command;
- testImplementation libs.hamcrest.core
- testImplementation libs.mockito.core
- testImplementation project(':ignite-core')
+/** Node metric command in REPL. */
+@Command(name = "metric",
+ subcommands = {NodeMetricEnableReplCommand.class, NodeMetricDisableReplCommand.class, NodeMetricListReplCommand.class},
+ description = "Node metric operations")
+public class NodeMetricReplCommand extends BaseCommand {
}
-
-description = 'ignite-metrics'
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/decorators/MetricListDecorator.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/decorators/MetricListDecorator.java
new file mode 100644
index 0000000000..581022f38c
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/decorators/MetricListDecorator.java
@@ -0,0 +1,45 @@
+/*
+ * 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.ignite.internal.cli.decorators;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.cli.core.decorator.Decorator;
+import org.apache.ignite.internal.cli.core.decorator.TerminalOutput;
+import org.apache.ignite.rest.client.model.MetricSource;
+
+/** Decorator for printing list of {@link MetricSource}. */
+public class MetricListDecorator implements Decorator<List<MetricSource>, TerminalOutput> {
+ @Override
+ public TerminalOutput decorate(List<MetricSource> data) {
+ return () -> {
+ String enabled = data.stream()
+ .filter(MetricSource::getEnabled)
+ .map(MetricSource::getName)
+ .collect(Collectors.joining(System.lineSeparator()));
+ String disabled = data.stream()
+ .filter(metricSource -> !metricSource.getEnabled())
+ .map(MetricSource::getName)
+ .collect(Collectors.joining(System.lineSeparator()));
+ return Stream.of("Enabled metric sources:", enabled, "Disabled metric sources:", disabled)
+ .filter(s -> !s.isEmpty())
+ .collect(Collectors.joining(System.lineSeparator()));
+ };
+ }
+}
diff --git a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
index 215687b84a..d06340e546 100644
--- a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
+++ b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
@@ -44,6 +44,12 @@ import org.apache.ignite.internal.cli.commands.node.config.NodeConfigShowCommand
import org.apache.ignite.internal.cli.commands.node.config.NodeConfigShowReplCommand;
import org.apache.ignite.internal.cli.commands.node.config.NodeConfigUpdateCommand;
import org.apache.ignite.internal.cli.commands.node.config.NodeConfigUpdateReplCommand;
+import org.apache.ignite.internal.cli.commands.node.metric.NodeMetricDisableCommand;
+import org.apache.ignite.internal.cli.commands.node.metric.NodeMetricDisableReplCommand;
+import org.apache.ignite.internal.cli.commands.node.metric.NodeMetricEnableCommand;
+import org.apache.ignite.internal.cli.commands.node.metric.NodeMetricEnableReplCommand;
+import org.apache.ignite.internal.cli.commands.node.metric.NodeMetricListCommand;
+import org.apache.ignite.internal.cli.commands.node.metric.NodeMetricListReplCommand;
import org.apache.ignite.internal.cli.commands.node.status.NodeStatusCommand;
import org.apache.ignite.internal.cli.commands.node.status.NodeStatusReplCommand;
import org.apache.ignite.internal.cli.commands.topology.LogicalTopologyCommand;
@@ -110,6 +116,9 @@ public class UrlOptionsNegativeTest {
arguments(ClusterConfigShowCommand.class, CLUSTER_URL_OPTION, List.of()),
arguments(ClusterConfigUpdateCommand.class, CLUSTER_URL_OPTION, List.of("{key: value}")),
arguments(ClusterStatusCommand.class, CLUSTER_URL_OPTION, List.of()),
+ arguments(NodeMetricEnableCommand.class, NODE_URL_OPTION, List.of("srcName")),
+ arguments(NodeMetricDisableCommand.class, NODE_URL_OPTION, List.of("srcName")),
+ arguments(NodeMetricListCommand.class, NODE_URL_OPTION, List.of()),
arguments(LogicalTopologyCommand.class, CLUSTER_URL_OPTION, List.of()),
arguments(PhysicalTopologyCommand.class, CLUSTER_URL_OPTION, List.of()),
arguments(ClusterInitCommand.class, CLUSTER_URL_OPTION, List.of("--cluster-name=cluster", "--meta-storage-node=test"))
@@ -126,6 +135,9 @@ public class UrlOptionsNegativeTest {
arguments(ClusterConfigShowReplCommand.class, CLUSTER_URL_OPTION, List.of()),
arguments(ClusterConfigUpdateReplCommand.class, CLUSTER_URL_OPTION, List.of("{key: value}")),
arguments(ClusterStatusReplCommand.class, CLUSTER_URL_OPTION, List.of()),
+ arguments(NodeMetricEnableReplCommand.class, NODE_URL_OPTION, List.of("srcName")),
+ arguments(NodeMetricDisableReplCommand.class, NODE_URL_OPTION, List.of("srcName")),
+ arguments(NodeMetricListReplCommand.class, NODE_URL_OPTION, List.of()),
arguments(LogicalTopologyReplCommand.class, CLUSTER_URL_OPTION, List.of()),
arguments(PhysicalTopologyReplCommand.class, CLUSTER_URL_OPTION, List.of()),
arguments(ClusterInitReplCommand.class, CLUSTER_URL_OPTION, List.of("--cluster-name=cluster", "--meta-storage-node=test")),
diff --git a/modules/cli/src/test/java/org/apache/ignite/internal/cli/deprecated/IgniteCliInterfaceTest.java b/modules/cli/src/test/java/org/apache/ignite/internal/cli/deprecated/IgniteCliInterfaceTest.java
index aa86b22bcb..76cec8d5b0 100644
--- a/modules/cli/src/test/java/org/apache/ignite/internal/cli/deprecated/IgniteCliInterfaceTest.java
+++ b/modules/cli/src/test/java/org/apache/ignite/internal/cli/deprecated/IgniteCliInterfaceTest.java
@@ -508,6 +508,67 @@ public class IgniteCliInterfaceTest extends AbstractCliTest {
assertThatStderrIsEmpty();
}
}
+
+ @Nested
+ @DisplayName("metric")
+ class Metric {
+ @Test
+ @DisplayName("metric enable srcName")
+ void enable() {
+ clientAndServer
+ .when(request()
+ .withMethod("POST")
+ .withPath("/management/v1/metric/node/enable")
+ .withBody("srcName")
+ )
+ .respond(response(null));
+
+ int exitCode = execute("node metric enable --node-url " + mockUrl + " srcName");
+
+ assertThatExitCodeMeansSuccess(exitCode);
+
+ assertOutputEqual("Metric source was enabled successfully");
+ assertThatStderrIsEmpty();
+ }
+
+ @Test
+ @DisplayName("metric disable srcName")
+ void disable() {
+ clientAndServer
+ .when(request()
+ .withMethod("POST")
+ .withPath("/management/v1/metric/node/disable")
+ .withBody("srcName")
+ )
+ .respond(response(null));
+
+ int exitCode = execute("node metric disable --node-url " + mockUrl + " srcName");
+
+ assertThatExitCodeMeansSuccess(exitCode);
+
+ assertOutputEqual("Metric source was disabled successfully");
+ assertThatStderrIsEmpty();
+ }
+
+ @Test
+ @DisplayName("metric list")
+ void list() {
+ String responseBody = "[{\"name\":\"enabledMetric\",\"enabled\":true},{\"name\":\"disabledMetric\",\"enabled\":false}]";
+ clientAndServer
+ .when(request()
+ .withMethod("GET")
+ .withPath("/management/v1/metric/node")
+ )
+ .respond(response(responseBody));
+
+ int exitCode = execute("node metric list --node-url " + mockUrl);
+
+ assertThatExitCodeMeansSuccess(exitCode);
+
+ assertOutputEqual("Enabled metric sources:\nenabledMetric\nDisabled metric sources:\ndisabledMetric\n");
+ assertThatStderrIsEmpty();
+ }
+ }
}
/**
diff --git a/modules/metrics/build.gradle b/modules/metrics/build.gradle
index 7f5a8fa822..b48e1594de 100644
--- a/modules/metrics/build.gradle
+++ b/modules/metrics/build.gradle
@@ -20,10 +20,15 @@ apply from: "$rootDir/buildscripts/java-junit5.gradle"
apply from: "$rootDir/buildscripts/java-integration-test.gradle"
dependencies {
+ annotationProcessor project(":ignite-configuration-annotation-processor")
+ annotationProcessor libs.micronaut.inject.annotation.processor
+
implementation project(':ignite-core')
implementation project(':ignite-configuration')
implementation project(':ignite-configuration-api')
+ implementation project(':ignite-rest-api')
implementation libs.jetbrains.annotations
+ implementation libs.micronaut.http.core
testImplementation libs.hamcrest.core
testImplementation libs.mockito.core
diff --git a/modules/metrics/pom.xml b/modules/metrics/pom.xml
index dfc7327191..ad35a6c216 100644
--- a/modules/metrics/pom.xml
+++ b/modules/metrics/pom.xml
@@ -48,6 +48,11 @@
<artifactId>ignite-configuration-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-rest-api</artifactId>
+ </dependency>
+
<!-- 3rd party dependencies -->
<dependency>
<groupId>org.jetbrains</groupId>
@@ -113,6 +118,11 @@
<artifactId>ignite-configuration-annotation-processor</artifactId>
<version>${project.version}</version>
</path>
+ <path>
+ <groupId>io.micronaut</groupId>
+ <artifactId>micronaut-inject-java</artifactId>
+ <version>${micronaut.version}</version>
+ </path>
</annotationProcessorPaths>
</configuration>
</plugin>
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java
index b4f2ca0e0e..01b603b283 100644
--- a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal.metrics;
+import java.util.Collection;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.ServiceLoader.Provider;
@@ -199,6 +200,15 @@ public class MetricManager implements IgniteComponent {
return registry.metricSnapshot();
}
+ /**
+ * Gets a collection of metric sources.
+ *
+ * @return collection of metric sources
+ */
+ public Collection<MetricSource> metricSources() {
+ return registry.metricSources();
+ }
+
private <T extends ExporterView> void checkAndStartExporter(
String exporterName,
T exporterConfiguration) {
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricRegistry.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricRegistry.java
index 3acbf3d0db..3d6679fc2d 100644
--- a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricRegistry.java
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricRegistry.java
@@ -21,7 +21,9 @@ import static java.util.Collections.emptyMap;
import static java.util.Collections.unmodifiableMap;
import static java.util.Objects.requireNonNull;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.locks.ReentrantLock;
@@ -193,7 +195,7 @@ public class MetricRegistry {
MetricSource src = sources.get(srcName);
if (src == null) {
- throw new IllegalStateException("Metrics source with given name doesn't exists: " + srcName);
+ throw new IllegalStateException("Metrics source with given name doesn't exist: " + srcName);
}
if (!src.enabled()) {
@@ -290,4 +292,18 @@ public class MetricRegistry {
public IgniteBiTuple<Map<String, MetricSet>, Long> metricSnapshot() {
return metricSnapshot;
}
+
+ /**
+ * Gets a collection of registered metric sources.
+ *
+ * @return Metric sources.
+ */
+ public Collection<MetricSource> metricSources() {
+ lock.lock();
+ try {
+ return List.copyOf(sources.values());
+ } finally {
+ lock.unlock();
+ }
+ }
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeCommand.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/MetricRestFactory.java
similarity index 54%
copy from modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeCommand.java
copy to modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/MetricRestFactory.java
index abbe1811c6..9710de23b7 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/node/NodeCommand.java
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/MetricRestFactory.java
@@ -15,22 +15,28 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.cli.commands.node;
+package org.apache.ignite.internal.metrics.rest;
-import org.apache.ignite.cli.commands.node.version.NodeVersionCommand;
-import org.apache.ignite.internal.cli.commands.node.config.NodeConfigCommand;
-import org.apache.ignite.internal.cli.commands.node.status.NodeStatusCommand;
-import org.apache.ignite.internal.cli.deprecated.spec.NodeCommandSpec;
-import picocli.CommandLine.Command;
-import picocli.CommandLine.Mixin;
+import io.micronaut.context.annotation.Bean;
+import io.micronaut.context.annotation.Factory;
+import jakarta.inject.Singleton;
+import org.apache.ignite.internal.metrics.MetricManager;
+import org.apache.ignite.internal.rest.RestFactory;
/**
- * Node command.
+ * Factory that creates beans that are needed for {@link NodeMetricController}.
*/
-@Command(name = "node",
- subcommands = {NodeConfigCommand.class, NodeStatusCommand.class, NodeVersionCommand.class},
- description = "Node operations")
-public class NodeCommand {
- @Mixin
- NodeCommandSpec nodeCommandSpec;
+@Factory
+public class MetricRestFactory implements RestFactory {
+ private final MetricManager metricManager;
+
+ public MetricRestFactory(MetricManager metricManager) {
+ this.metricManager = metricManager;
+ }
+
+ @Bean
+ @Singleton
+ public MetricManager metricManager() {
+ return metricManager;
+ }
}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/NodeMetricController.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/NodeMetricController.java
new file mode 100644
index 0000000000..30271d9256
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/NodeMetricController.java
@@ -0,0 +1,61 @@
+/*
+ * 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.ignite.internal.metrics.rest;
+
+import io.micronaut.http.annotation.Controller;
+import java.util.Collection;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.metrics.MetricManager;
+import org.apache.ignite.internal.metrics.rest.exception.MetricNotFoundException;
+import org.apache.ignite.internal.rest.api.metric.MetricSourceDto;
+import org.apache.ignite.internal.rest.api.metric.NodeMetricApi;
+
+/** Node metric controller. */
+@Controller("/management/v1/metric/node")
+public class NodeMetricController implements NodeMetricApi {
+ private final MetricManager metricManager;
+
+ public NodeMetricController(MetricManager metricManager) {
+ this.metricManager = metricManager;
+ }
+
+ @Override
+ public void enable(String srcName) {
+ try {
+ metricManager.enable(srcName);
+ } catch (IllegalStateException e) {
+ throw new MetricNotFoundException(e);
+ }
+ }
+
+ @Override
+ public void disable(String srcName) {
+ try {
+ metricManager.disable(srcName);
+ } catch (IllegalStateException e) {
+ throw new MetricNotFoundException(e);
+ }
+ }
+
+ @Override
+ public Collection<MetricSourceDto> list() {
+ return metricManager.metricSources().stream()
+ .map(source -> new MetricSourceDto(source.name(), source.enabled()))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/modules/metrics/build.gradle b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/exception/MetricNotFoundException.java
similarity index 59%
copy from modules/metrics/build.gradle
copy to modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/exception/MetricNotFoundException.java
index 7f5a8fa822..e6e2300514 100644
--- a/modules/metrics/build.gradle
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/exception/MetricNotFoundException.java
@@ -15,19 +15,13 @@
* limitations under the License.
*/
-apply from: "$rootDir/buildscripts/java-core.gradle"
-apply from: "$rootDir/buildscripts/java-junit5.gradle"
-apply from: "$rootDir/buildscripts/java-integration-test.gradle"
+package org.apache.ignite.internal.metrics.rest.exception;
-dependencies {
- implementation project(':ignite-core')
- implementation project(':ignite-configuration')
- implementation project(':ignite-configuration-api')
- implementation libs.jetbrains.annotations
-
- testImplementation libs.hamcrest.core
- testImplementation libs.mockito.core
- testImplementation project(':ignite-core')
+/**
+ * Exception that is thrown when requested metric is not found in the registry.
+ */
+public class MetricNotFoundException extends RuntimeException {
+ public MetricNotFoundException(Throwable cause) {
+ super(cause);
+ }
}
-
-description = 'ignite-metrics'
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/exception/handler/MetricNotFoundExceptionHandler.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/exception/handler/MetricNotFoundExceptionHandler.java
new file mode 100644
index 0000000000..d37e00edd8
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/rest/exception/handler/MetricNotFoundExceptionHandler.java
@@ -0,0 +1,45 @@
+/*
+ * 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.ignite.internal.metrics.rest.exception.handler;
+
+import io.micronaut.context.annotation.Requires;
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.server.exceptions.ExceptionHandler;
+import jakarta.inject.Singleton;
+import org.apache.ignite.internal.metrics.rest.exception.MetricNotFoundException;
+import org.apache.ignite.internal.rest.api.Problem;
+import org.apache.ignite.internal.rest.constants.HttpCode;
+import org.apache.ignite.internal.rest.problem.HttpProblemResponse;
+
+/**
+ * Handles {@link MetricNotFoundException} and represents it as a rest response.
+ */
+@Singleton
+@Requires(classes = {MetricNotFoundException.class, ExceptionHandler.class})
+public class MetricNotFoundExceptionHandler implements
+ ExceptionHandler<MetricNotFoundException, HttpResponse<? extends Problem>> {
+
+ @Override
+ public HttpResponse<? extends Problem> handle(HttpRequest request, MetricNotFoundException exception) {
+ return HttpProblemResponse.from(
+ Problem.fromHttpCode(HttpCode.NOT_FOUND)
+ .detail(exception.getCause().getMessage())
+ );
+ }
+}
diff --git a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/metric/MetricSourceDto.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/metric/MetricSourceDto.java
new file mode 100644
index 0000000000..1cda8844b4
--- /dev/null
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/metric/MetricSourceDto.java
@@ -0,0 +1,69 @@
+/*
+ * 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.ignite.internal.rest.api.metric;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonGetter;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+/**
+ * REST representation of MetricSource.
+ */
+@Schema(name = "MetricSource")
+public class MetricSourceDto {
+ /** Name of the metric source. */
+ private final String name;
+
+ /** Enabled. */
+ private final boolean enabled;
+
+ /**
+ * Constructor.
+ *
+ * @param name metric source name
+ * @param enabled flags showing whether this metric source is enabled or not
+ */
+ @JsonCreator
+ public MetricSourceDto(
+ @JsonProperty("name") String name,
+ @JsonProperty("enabled") boolean enabled) {
+ this.name = name;
+ this.enabled = enabled;
+ }
+
+ /**
+ * Returns the metric source name.
+ *
+ * @return metric source name
+ */
+ @JsonGetter("name")
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Returns the status of the metric source.
+ *
+ * @return {@code true} if metrics are enabled, otherwise - {@code false}
+ */
+ @JsonGetter("enabled")
+ public boolean enabled() {
+ return enabled;
+ }
+}
diff --git a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/metric/NodeMetricApi.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/metric/NodeMetricApi.java
new file mode 100644
index 0000000000..900affadaa
--- /dev/null
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/metric/NodeMetricApi.java
@@ -0,0 +1,72 @@
+/*
+ * 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.ignite.internal.rest.api.metric;
+
+import io.micronaut.http.annotation.Body;
+import io.micronaut.http.annotation.Consumes;
+import io.micronaut.http.annotation.Controller;
+import io.micronaut.http.annotation.Get;
+import io.micronaut.http.annotation.Post;
+import io.micronaut.http.annotation.Produces;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import java.util.Collection;
+import org.apache.ignite.internal.rest.api.Problem;
+import org.apache.ignite.internal.rest.constants.MediaType;
+
+/** Node metric endpoint. */
+@Controller("/management/v1/metric/node")
+@Tag(name = "nodeMetric")
+public interface NodeMetricApi {
+
+ /** Enable metric source. */
+ @Operation(operationId = "enableNodeMetric")
+ @ApiResponse(responseCode = "200", description = "Metric source enabled")
+ @ApiResponse(responseCode = "500", description = "Internal error",
+ content = @Content(mediaType = MediaType.PROBLEM_JSON, schema = @Schema(implementation = Problem.class)))
+ @ApiResponse(responseCode = "404", description = "Metric source not found",
+ content = @Content(mediaType = MediaType.PROBLEM_JSON, schema = @Schema(implementation = Problem.class)))
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.PROBLEM_JSON)
+ @Post("enable")
+ void enable(@Body String srcName);
+
+ /** Disable metric source. */
+ @Operation(operationId = "disableNodeMetric")
+ @ApiResponse(responseCode = "200", description = "Metric source disabled")
+ @ApiResponse(responseCode = "500", description = "Internal error",
+ content = @Content(mediaType = MediaType.PROBLEM_JSON, schema = @Schema(implementation = Problem.class)))
+ @ApiResponse(responseCode = "404", description = "Metric source not found",
+ content = @Content(mediaType = MediaType.PROBLEM_JSON, schema = @Schema(implementation = Problem.class)))
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.PROBLEM_JSON)
+ @Post("disable")
+ void disable(@Body String srcName);
+
+ /** List metric sources. */
+ @Operation(operationId = "listNodeMetrics")
+ @ApiResponse(responseCode = "200", description = "Metric sources returned")
+ @ApiResponse(responseCode = "500", description = "Internal error",
+ content = @Content(mediaType = MediaType.PROBLEM_JSON, schema = @Schema(implementation = Problem.class)))
+ @Produces(MediaType.APPLICATION_JSON)
+ @Get()
+ Collection<MetricSourceDto> list();
+}
diff --git a/modules/rest/openapi/openapi.yaml b/modules/rest/openapi/openapi.yaml
index 70848c2896..f2f496b777 100644
--- a/modules/rest/openapi/openapi.yaml
+++ b/modules/rest/openapi/openapi.yaml
@@ -305,6 +305,81 @@ paths:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
+ /management/v1/metric/node:
+ get:
+ tags:
+ - nodeMetric
+ operationId: listNodeMetrics
+ parameters: []
+ responses:
+ "200":
+ description: Metric sources returned
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/MetricSource'
+ "500":
+ description: Internal error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/Problem'
+ /management/v1/metric/node/disable:
+ post:
+ tags:
+ - nodeMetric
+ operationId: disableNodeMetric
+ parameters: []
+ requestBody:
+ content:
+ text/plain:
+ schema:
+ type: string
+ required: true
+ responses:
+ "200":
+ description: Metric source disabled
+ "500":
+ description: Internal error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/Problem'
+ "404":
+ description: Metric source not found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/Problem'
+ /management/v1/metric/node/enable:
+ post:
+ tags:
+ - nodeMetric
+ operationId: enableNodeMetric
+ parameters: []
+ requestBody:
+ content:
+ text/plain:
+ schema:
+ type: string
+ required: true
+ responses:
+ "200":
+ description: Metric source enabled
+ "500":
+ description: Internal error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/Problem'
+ "404":
+ description: Metric source not found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/Problem'
/management/v1/node/state:
get:
tags:
@@ -415,6 +490,16 @@ components:
type: string
reason:
type: string
+ MetricSource:
+ required:
+ - enabled
+ - name
+ type: object
+ properties:
+ name:
+ type: string
+ enabled:
+ type: boolean
NetworkAddress:
required:
- consistentId
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
index df854616d8..6ab45ff11f 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
+++ b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
@@ -38,6 +38,7 @@ import org.apache.ignite.internal.rest.api.cluster.ClusterManagementApi;
import org.apache.ignite.internal.rest.api.cluster.TopologyApi;
import org.apache.ignite.internal.rest.api.configuration.ClusterConfigurationApi;
import org.apache.ignite.internal.rest.api.configuration.NodeConfigurationApi;
+import org.apache.ignite.internal.rest.api.metric.NodeMetricApi;
import org.apache.ignite.internal.rest.api.node.NodeManagementApi;
import org.apache.ignite.lang.IgniteInternalException;
import org.jetbrains.annotations.Nullable;
@@ -58,6 +59,7 @@ import org.jetbrains.annotations.Nullable;
NodeConfigurationApi.class,
ClusterManagementApi.class,
NodeManagementApi.class,
+ NodeMetricApi.class,
TopologyApi.class
})
public class RestComponent implements IgniteComponent {
diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
index e96e576913..0af27b5607 100644
--- a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
+++ b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
@@ -63,6 +63,7 @@ import org.apache.ignite.internal.metastorage.MetaStorageManager;
import org.apache.ignite.internal.metastorage.server.persistence.RocksDbKeyValueStorage;
import org.apache.ignite.internal.metrics.MetricManager;
import org.apache.ignite.internal.metrics.configuration.MetricConfiguration;
+import org.apache.ignite.internal.metrics.rest.MetricRestFactory;
import org.apache.ignite.internal.raft.Loza;
import org.apache.ignite.internal.raft.configuration.RaftConfiguration;
import org.apache.ignite.internal.raft.storage.impl.VolatileLogStorageFactoryCreator;
@@ -328,14 +329,7 @@ public class IgniteImpl implements Ignite {
metricManager.configure(clusterCfgMgr.configurationRegistry().getConfiguration(MetricConfiguration.KEY));
- RestFactory presentationsFactory = new PresentationsFactory(nodeCfgMgr, clusterCfgMgr);
- RestFactory clusterManagementRestFactory = new ClusterManagementRestFactory(clusterSvc, cmgMgr);
- RestFactory nodeManagementRestFactory = new NodeManagementRestFactory(lifecycleManager, () -> name);
- RestConfiguration restConfiguration = nodeCfgMgr.configurationRegistry().getConfiguration(RestConfiguration.KEY);
- restComponent = new RestComponent(
- List.of(presentationsFactory, clusterManagementRestFactory, nodeManagementRestFactory),
- restConfiguration
- );
+ restComponent = createRestComponent(name);
baselineMgr = new BaselineManager(
clusterCfgMgr,
@@ -416,6 +410,21 @@ public class IgniteImpl implements Ignite {
);
}
+ private RestComponent createRestComponent(String name) {
+ RestFactory presentationsFactory = new PresentationsFactory(nodeCfgMgr, clusterCfgMgr);
+ RestFactory clusterManagementRestFactory = new ClusterManagementRestFactory(clusterSvc, cmgMgr);
+ RestFactory nodeManagementRestFactory = new NodeManagementRestFactory(lifecycleManager, () -> name);
+ RestFactory nodeMetricRestFactory = new MetricRestFactory(metricManager);
+ RestConfiguration restConfiguration = nodeCfgMgr.configurationRegistry().getConfiguration(RestConfiguration.KEY);
+ return new RestComponent(
+ List.of(presentationsFactory,
+ clusterManagementRestFactory,
+ nodeManagementRestFactory,
+ nodeMetricRestFactory),
+ restConfiguration
+ );
+ }
+
private static ConfigurationModules loadConfigurationModules(ClassLoader classLoader) {
var modulesProvider = new ServiceLoaderModulesProvider();
List<ConfigurationModule> modules = modulesProvider.modules(classLoader);