This is an automated email from the ASF dual-hosted git repository.
apkhmv 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 b87aef7902 IGNITE-18943 Disable the set of endpoints for
non-initialized cluster (#1812)
b87aef7902 is described below
commit b87aef79020daff0a3110546a46866f6fd376270
Author: Aleksandr Pakhomov <[email protected]>
AuthorDate: Wed Mar 22 15:06:47 2023 +0400
IGNITE-18943 Disable the set of endpoints for non-initialized cluster
(#1812)
Co-authored-by: Vadim Pakhnushev <[email protected]>
---
.../cli/call/cluster/status/ClusterStatusCall.java | 2 +-
.../internal/cli/call/unit/DeployUnitCall.java | 4 +
.../internal/cli/call/unit/ListUnitCall.java | 2 +-
.../internal/cli/call/unit/UndeployUnitCall.java | 3 +-
.../internal/cli/call/unit/UnitStatusCall.java | 2 +-
.../node/metric/NodeMetricDisableCommand.java | 2 +
.../node/metric/NodeMetricDisableReplCommand.java | 2 +
.../node/metric/NodeMetricEnableCommand.java | 2 +
.../node/metric/NodeMetricEnableReplCommand.java | 2 +
.../node/metric/NodeMetricListCommand.java | 2 +
.../node/metric/NodeMetricListReplCommand.java | 2 +
.../cli/commands/unit/UnitDeployCommand.java | 2 +
.../cli/commands/unit/UnitListCommand.java | 2 +
.../cli/commands/unit/UnitStatusCommand.java | 2 +
.../cli/commands/unit/UnitUndeployCommand.java | 2 +
.../ClusterNotInitializedExceptionHandler.java | 2 +-
.../management/ClusterManagementGroupManager.java | 2 +-
.../ItNodeOnlyEndpointsFilterInitializedTest.java | 74 +++++++++++++++
...tNodeOnlyEndpointsFilterNotInitializedTest.java | 105 +++++++++++++++++++++
.../apache/ignite/internal/rest/RestComponent.java | 12 +--
.../authentication/NodeOnlyEndpointsFilter.java | 89 +++++++++++++++++
.../rest/ItNotInitializedClusterRestTest.java | 24 ++---
22 files changed, 317 insertions(+), 24 deletions(-)
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/status/ClusterStatusCall.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/status/ClusterStatusCall.java
index dcb0b64f9a..bb726633f4 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/status/ClusterStatusCall.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/cluster/status/ClusterStatusCall.java
@@ -58,7 +58,7 @@ public class ClusterStatusCall implements Call<UrlCallInput,
ClusterStatus> {
.metadataStorageNodes(clusterState.getMsNodes())
.cmgNodes(clusterState.getCmgNodes());
} catch (ApiException e) {
- if (e.getCode() == 404) { // NOT_FOUND means the cluster is not
initialized yet
+ if (e.getCode() == 409) { // CONFLICT means the cluster is not
initialized yet
clusterStatusBuilder.initialized(false).nodeCount(fetchNumberOfAllNodes(input));
} else {
return DefaultCallOutput.failure(new IgniteCliApiException(e,
clusterUrl));
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/DeployUnitCall.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/DeployUnitCall.java
index 02537ddf5f..7093accc12 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/DeployUnitCall.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/DeployUnitCall.java
@@ -89,6 +89,10 @@ public class DeployUnitCall implements
AsyncCall<DeployUnitCallInput, String> {
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
if (apiException.getCode() == 409) {
+ // special case when cluster is not initialized
+ if (apiException.getResponseBody().contains("Cluster is not
initialized")) {
+ return DefaultCallOutput.failure(new
IgniteCliApiException(exception, input.clusterUrl()));
+ }
return DefaultCallOutput.failure(new
UnitAlreadyExistsException(input.id(), input.version()));
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/ListUnitCall.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/ListUnitCall.java
index 8d7b4f4465..8a51311660 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/ListUnitCall.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/ListUnitCall.java
@@ -53,7 +53,7 @@ public class ListUnitCall implements Call<UrlCallInput,
List<UnitStatusRecord>>
.collect(Collectors.toList())
);
} catch (ApiException e) {
- throw new IgniteCliApiException(e, input.getUrl());
+ return DefaultCallOutput.failure(new IgniteCliApiException(e,
input.getUrl()));
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UndeployUnitCall.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UndeployUnitCall.java
index 87f8c8f1c8..e6a532caf0 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UndeployUnitCall.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UndeployUnitCall.java
@@ -22,6 +22,7 @@ import org.apache.ignite.internal.cli.core.ApiClientFactory;
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.exception.IgniteCliApiException;
import org.apache.ignite.internal.cli.core.exception.UnitNotFoundException;
import org.apache.ignite.internal.cli.core.repl.registry.UnitsRegistry;
import org.apache.ignite.internal.cli.core.style.component.MessageUiComponent;
@@ -57,7 +58,7 @@ public class UndeployUnitCall implements
Call<UndeployUnitCallInput, String> {
return DefaultCallOutput.failure(new
UnitNotFoundException(input.id(), input.version()));
}
- return DefaultCallOutput.failure(e);
+ return DefaultCallOutput.failure(new IgniteCliApiException(e,
input.clusterUrl()));
}
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UnitStatusCall.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UnitStatusCall.java
index 075da4db38..64cc308eca 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UnitStatusCall.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UnitStatusCall.java
@@ -48,7 +48,7 @@ public class UnitStatusCall implements
Call<UnitStatusCallInput, UnitStatusRecor
return DefaultCallOutput.failure(new
UnitNotFoundException(input.id()));
}
- throw new IgniteCliApiException(e, input.clusterUrl());
+ return DefaultCallOutput.failure(new IgniteCliApiException(e,
input.clusterUrl()));
}
}
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
index fdefe92bef..fdaad9a48d 100644
---
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
@@ -24,6 +24,7 @@ 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
org.apache.ignite.internal.cli.core.exception.handler.ClusterNotInitializedExceptionHandler;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
@@ -48,6 +49,7 @@ public class NodeMetricDisableCommand extends BaseCommand
implements Callable<In
.output(spec.commandLine().getOut())
.errOutput(spec.commandLine().getErr())
.verbose(verbose)
+ .exceptionHandler(new
ClusterNotInitializedExceptionHandler("Cannot disable metrics", "cluster init"))
.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
index c549fe4747..39c0e38852 100644
---
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
@@ -23,6 +23,7 @@ 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.exception.handler.ClusterNotInitializedExceptionHandler;
import org.apache.ignite.internal.cli.core.flow.builder.Flows;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
@@ -48,6 +49,7 @@ public class NodeMetricDisableReplCommand extends BaseCommand
implements Runnabl
question.askQuestionIfNotConnected(nodeUrl.getNodeUrl())
.map(metricSource::buildDisableCallInput)
.then(Flows.fromCall(call))
+ .exceptionHandler(new
ClusterNotInitializedExceptionHandler("Cannot disable metrics", "cluster init"))
.verbose(verbose)
.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
index efd67828d8..f4f2bd6772 100644
---
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
@@ -24,6 +24,7 @@ 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
org.apache.ignite.internal.cli.core.exception.handler.ClusterNotInitializedExceptionHandler;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
@@ -48,6 +49,7 @@ public class NodeMetricEnableCommand extends BaseCommand
implements Callable<Int
.output(spec.commandLine().getOut())
.errOutput(spec.commandLine().getErr())
.verbose(verbose)
+ .exceptionHandler(new
ClusterNotInitializedExceptionHandler("Cannot enable metrics", "cluster init"))
.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
index 290d2f929f..be7d604898 100644
---
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
@@ -23,6 +23,7 @@ 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.exception.handler.ClusterNotInitializedExceptionHandler;
import org.apache.ignite.internal.cli.core.flow.builder.Flows;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
@@ -48,6 +49,7 @@ public class NodeMetricEnableReplCommand extends BaseCommand
implements Runnable
question.askQuestionIfNotConnected(nodeUrl.getNodeUrl())
.map(metricSource::buildEnableCallInput)
.then(Flows.fromCall(call))
+ .exceptionHandler(new
ClusterNotInitializedExceptionHandler("Cannot enable metrics", "cluster init"))
.verbose(verbose)
.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
index adfe1ce727..f273a65619 100644
---
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
@@ -24,6 +24,7 @@ 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.core.exception.handler.ClusterNotInitializedExceptionHandler;
import org.apache.ignite.internal.cli.decorators.MetricListDecorator;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
@@ -47,6 +48,7 @@ public class NodeMetricListCommand extends BaseCommand
implements Callable<Integ
.errOutput(spec.commandLine().getErr())
.decorator(new MetricListDecorator())
.verbose(verbose)
+ .exceptionHandler(new
ClusterNotInitializedExceptionHandler("Cannot list metrics", "cluster init"))
.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
index 0ee87407d2..0c32af3f63 100644
---
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
@@ -23,6 +23,7 @@ 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.exception.handler.ClusterNotInitializedExceptionHandler;
import org.apache.ignite.internal.cli.core.flow.builder.Flows;
import org.apache.ignite.internal.cli.decorators.MetricListDecorator;
import picocli.CommandLine.Command;
@@ -47,6 +48,7 @@ public class NodeMetricListReplCommand extends BaseCommand
implements Runnable {
question.askQuestionIfNotConnected(nodeUrl.getNodeUrl())
.map(StringCallInput::new)
.then(Flows.fromCall(call))
+ .exceptionHandler(new
ClusterNotInitializedExceptionHandler("Cannot list metrics", "cluster init"))
.print(new MetricListDecorator())
.start();
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitDeployCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitDeployCommand.java
index 16d5b664ba..6745dbd44c 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitDeployCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitDeployCommand.java
@@ -33,6 +33,7 @@ import
org.apache.ignite.internal.cli.call.unit.DeployUnitCallInput;
import org.apache.ignite.internal.cli.commands.BaseCommand;
import org.apache.ignite.internal.cli.commands.cluster.ClusterUrlProfileMixin;
import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
+import
org.apache.ignite.internal.cli.core.exception.handler.ClusterNotInitializedExceptionHandler;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;
@@ -72,6 +73,7 @@ public class UnitDeployCommand extends BaseCommand implements
Callable<Integer>
.output(spec.commandLine().getOut())
.errOutput(spec.commandLine().getErr())
.verbose(verbose)
+ .exceptionHandler(new
ClusterNotInitializedExceptionHandler("Cannot deploy unit", "cluster init"))
.build().runPipeline();
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitListCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitListCommand.java
index 788867544a..8234cb6167 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitListCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitListCommand.java
@@ -25,6 +25,7 @@ import org.apache.ignite.internal.cli.commands.BaseCommand;
import org.apache.ignite.internal.cli.commands.cluster.ClusterUrlProfileMixin;
import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
import org.apache.ignite.internal.cli.core.call.UrlCallInput;
+import
org.apache.ignite.internal.cli.core.exception.handler.ClusterNotInitializedExceptionHandler;
import org.apache.ignite.internal.cli.decorators.UnitListDecorator;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
@@ -47,6 +48,7 @@ public class UnitListCommand extends BaseCommand implements
Callable<Integer> {
.errOutput(spec.commandLine().getErr())
.verbose(verbose)
.decorator(new UnitListDecorator())
+ .exceptionHandler(new
ClusterNotInitializedExceptionHandler("Cannot list units", "cluster init"))
.build().runPipeline();
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitStatusCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitStatusCommand.java
index e6e31d70a9..457df8f7f3 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitStatusCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitStatusCommand.java
@@ -25,6 +25,7 @@ import
org.apache.ignite.internal.cli.call.unit.UnitStatusCallInput;
import org.apache.ignite.internal.cli.commands.BaseCommand;
import org.apache.ignite.internal.cli.commands.cluster.ClusterUrlProfileMixin;
import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
+import
org.apache.ignite.internal.cli.core.exception.handler.ClusterNotInitializedExceptionHandler;
import org.apache.ignite.internal.cli.decorators.UnitStatusDecorator;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
@@ -56,6 +57,7 @@ public class UnitStatusCommand extends BaseCommand implements
Callable<Integer>
.errOutput(spec.commandLine().getErr())
.verbose(verbose)
.decorator(new UnitStatusDecorator())
+ .exceptionHandler(new
ClusterNotInitializedExceptionHandler("Cannot get unit status", "cluster init"))
.build().runPipeline();
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitUndeployCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitUndeployCommand.java
index c2a1f8d616..6cfd3e734d 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitUndeployCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/unit/UnitUndeployCommand.java
@@ -29,6 +29,7 @@ import
org.apache.ignite.internal.cli.call.unit.UndeployUnitCallInput;
import org.apache.ignite.internal.cli.commands.BaseCommand;
import org.apache.ignite.internal.cli.commands.cluster.ClusterUrlProfileMixin;
import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
+import
org.apache.ignite.internal.cli.core.exception.handler.ClusterNotInitializedExceptionHandler;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;
@@ -63,6 +64,7 @@ public class UnitUndeployCommand extends BaseCommand
implements Callable<Integer
.output(spec.commandLine().getOut())
.errOutput(spec.commandLine().getErr())
.verbose(verbose)
+ .exceptionHandler(new
ClusterNotInitializedExceptionHandler("Cannot undeploy unit", "cluster init"))
.build().runPipeline();
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/exception/handler/ClusterNotInitializedExceptionHandler.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/exception/handler/ClusterNotInitializedExceptionHandler.java
index 459a9f15a8..7cbde65b61 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/exception/handler/ClusterNotInitializedExceptionHandler.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/exception/handler/ClusterNotInitializedExceptionHandler.java
@@ -46,7 +46,7 @@ public class ClusterNotInitializedExceptionHandler extends
IgniteCliApiException
public int handle(ExceptionWriter err, IgniteCliApiException e) {
if (e.getCause() instanceof ApiException) {
ApiException apiException = (ApiException) e.getCause();
- if (apiException.getCode() == 404) {
+ if (apiException.getCode() == 409) { // CONFLICT means not
initialized
err.write(
ErrorUiComponent.builder()
.header(header)
diff --git
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/ClusterManagementGroupManager.java
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/ClusterManagementGroupManager.java
index 84ca9c6521..d56aed7592 100644
---
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/ClusterManagementGroupManager.java
+++
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/ClusterManagementGroupManager.java
@@ -404,7 +404,7 @@ public class ClusterManagementGroupManager implements
IgniteComponent {
LOG.info("No REST auth configuration found in the Raft
storage");
return completedFuture(null);
} else {
- //TODO
https://issues.apache.org/jira/browse/IGNITE-18943
+ //TODO
https://issues.apache.org/jira/browse/IGNITE-19077
LOG.info("REST auth configuration found in the Raft
storage, going to apply it");
Authentication restAuthToApply =
state.restAuthToApply();
return
distributedConfigurationUpdater.updateRestAuthConfiguration(restAuthToApply)
diff --git
a/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/ItNodeOnlyEndpointsFilterInitializedTest.java
b/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/ItNodeOnlyEndpointsFilterInitializedTest.java
new file mode 100644
index 0000000000..4da84b98c5
--- /dev/null
+++
b/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/ItNodeOnlyEndpointsFilterInitializedTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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;
+
+import static
org.apache.ignite.internal.testframework.IgniteTestUtils.testNodeName;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.client.HttpClient;
+import io.micronaut.http.client.annotation.Client;
+import jakarta.inject.Inject;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.testframework.IntegrationTestBase;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/** Tests that after cluster is initialized, all endpoints are available. */
+public class ItNodeOnlyEndpointsFilterInitializedTest extends
IntegrationTestBase {
+
+ @Inject
+ @Client(NODE_URL + "/management/v1")
+ HttpClient client;
+
+ private static Stream<Arguments> endpoints() {
+ return Stream.of(
+ Arguments.of("deployment/units"),
+ Arguments.of("node/state"),
+ Arguments.of("configuration/cluster"),
+ Arguments.of("configuration/node"),
+ Arguments.of("configuration/node/rest"),
+ Arguments.of("cluster/topology/logical"),
+ Arguments.of("cluster/topology/physical")
+ );
+ }
+
+ @BeforeAll
+ public void setup(TestInfo testInfo) {
+ startNodes(testInfo);
+ String metaStorageNodeName = testNodeName(testInfo, 0);
+ initializeCluster(metaStorageNodeName);
+ }
+
+ @AfterAll
+ public void cleanup(TestInfo testInfo) throws Exception {
+ stopNodes(testInfo);
+ }
+
+ @ParameterizedTest
+ @MethodSource("endpoints")
+ void clusterEndpointsEnabled(String path) {
+ assertDoesNotThrow(
+ () -> client.toBlocking().retrieve(HttpRequest.GET(path))
+ );
+ }
+}
diff --git
a/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/ItNodeOnlyEndpointsFilterNotInitializedTest.java
b/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/ItNodeOnlyEndpointsFilterNotInitializedTest.java
new file mode 100644
index 0000000000..6e78409b72
--- /dev/null
+++
b/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/ItNodeOnlyEndpointsFilterNotInitializedTest.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.rest;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.client.HttpClient;
+import io.micronaut.http.client.annotation.Client;
+import io.micronaut.http.client.exceptions.HttpClientResponseException;
+import jakarta.inject.Inject;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.rest.api.Problem;
+import org.apache.ignite.internal.testframework.IntegrationTestBase;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/** Tests that before cluster is initialized, only a subset of endpoints are
available. */
+public class ItNodeOnlyEndpointsFilterNotInitializedTest extends
IntegrationTestBase {
+
+ private ObjectMapper mapper = new ObjectMapper();
+
+ @Inject
+ @Client(NODE_URL + "/management/v1")
+ HttpClient client;
+
+ private static Stream<Arguments> disabledEndpoints() {
+ return Stream.of(
+ Arguments.of("deployment/units"),
+ Arguments.of("configuration/cluster"),
+ Arguments.of("cluster/topology/logical")
+ );
+ }
+
+ private static Stream<Arguments> enabledEndpoints() {
+ return Stream.of(
+ Arguments.of("node/state"),
+ Arguments.of("configuration/node"),
+ Arguments.of("configuration/node/rest"),
+ Arguments.of("cluster/topology/physical")
+ );
+ }
+
+ @BeforeAll
+ public void setup(TestInfo testInfo) {
+ // Given non-initialized cluster.
+ startNodes(testInfo);
+ }
+
+ @AfterAll
+ public void cleanup(TestInfo testInfo) throws Exception {
+ stopNodes(testInfo);
+ }
+
+ @ParameterizedTest
+ @MethodSource("disabledEndpoints")
+ void clusterEndpointsDisabledWhenNotInitialized(String path) throws
JsonProcessingException {
+ HttpClientResponseException ex = assertThrows(
+ HttpClientResponseException.class,
+ () -> client.toBlocking().retrieve(HttpRequest.GET(path),
String.class)
+ );
+
+ assertThat(ex.getStatus().getCode(), is(409));
+ Problem problem = readProblem(ex);
+ assertThat(problem.status(), is(409));
+ assertThat(problem.detail(), is("Cluster is not initialized. Call
/management/v1/cluster/init in order to initialize cluster."));
+ }
+
+ private Problem readProblem(HttpClientResponseException ex) throws
JsonProcessingException {
+ return mapper.readValue(ex.getResponse().getBody(String.class).get(),
Problem.class);
+ }
+
+ @ParameterizedTest
+ @MethodSource("enabledEndpoints")
+ void nodeConfigAndClusterInitAreEnabled(String path) {
+ // But node config and cluster init endpoints are enabled
+ assertDoesNotThrow(
+ () -> client.toBlocking().retrieve(HttpRequest.GET(path))
+ );
+ }
+}
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 518bb06ffb..a7a29def2f 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
@@ -196,13 +196,15 @@ public class RestComponent implements IgniteComponent {
RestSslView restSslView = restConfiguration.ssl().value();
boolean sslEnabled = restSslView.enabled();
+ Map<String, Object> result = new HashMap<>();
+ result.put("micronaut.server.port", port);
+ result.put("ignite.endpoints.filter-non-initialized", "true");
+
if (sslEnabled) {
KeyStoreView keyStore = restSslView.keyStore();
boolean dualProtocol = restConfiguration.dualProtocol().value();
- Map<String, Object> result = new HashMap<>();
// Micronaut is not going to handle requests on that port, but
it's required
- result.put("micronaut.server.port", port);
result.put("micronaut.server.dual-protocol", dualProtocol);
result.put("micronaut.server.ssl.port", sslPort);
if (!restSslView.ciphers().isBlank()) {
@@ -224,11 +226,9 @@ public class RestComponent implements IgniteComponent {
result.put("micronaut.server.ssl.trust-store.path", "file:" +
trustStore.path());
result.put("micronaut.server.ssl.trust-store.password",
trustStore.password());
result.put("micronaut.server.ssl.trust-store.type",
trustStore.type());
-
- return result;
- } else {
- return Map.of("micronaut.server.port", port);
}
+
+ return result;
}
private Map<String, Object> authProperties() {
diff --git
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/authentication/NodeOnlyEndpointsFilter.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/authentication/NodeOnlyEndpointsFilter.java
new file mode 100644
index 0000000000..47c3ba722a
--- /dev/null
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/authentication/NodeOnlyEndpointsFilter.java
@@ -0,0 +1,89 @@
+/*
+ * 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.authentication;
+
+import io.micronaut.context.annotation.Requires;
+import io.micronaut.core.async.publisher.Publishers;
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.MutableHttpResponse;
+import io.micronaut.http.annotation.Filter;
+import io.micronaut.http.filter.HttpServerFilter;
+import io.micronaut.http.filter.ServerFilterChain;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import
org.apache.ignite.internal.cluster.management.ClusterManagementGroupManager;
+import org.apache.ignite.internal.cluster.management.ClusterState;
+import org.apache.ignite.internal.rest.api.Problem;
+import org.apache.ignite.internal.rest.constants.HttpCode;
+import org.apache.ignite.internal.rest.problem.HttpProblemResponse;
+import org.apache.ignite.lang.ErrorGroups.Common;
+import org.apache.ignite.lang.IgniteException;
+import org.reactivestreams.Publisher;
+
+/** Filters out endpoints that are not allowed to be accessed before cluster
is initialized. */
+@Filter(Filter.MATCH_ALL_PATTERN)
+@Requires(property = "ignite.endpoints.filter-non-initialized", value =
"true", defaultValue = "false")
+// TODO: https://issues.apache.org/jira/browse/IGNITE-19077
+public class NodeOnlyEndpointsFilter implements HttpServerFilter {
+ private static final String[] ENABLED_ENDPOINTS = {
+ "/management/v1/configuration/node",
+ "/management/v1/cluster/init",
+ "/management/v1/cluster/topology/physical",
+ "/management/v1/node"
+ };
+
+ private final ClusterManagementGroupManager cmgMgr;
+
+ public NodeOnlyEndpointsFilter(ClusterManagementGroupManager cmgMgr) {
+ this.cmgMgr = cmgMgr;
+ }
+
+ private static boolean pathDisabledForNotInitializedCluster(String path) {
+ for (String enabledPath : ENABLED_ENDPOINTS) {
+ if (path.startsWith(enabledPath)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request,
ServerFilterChain chain) {
+ try {
+ if (clusterNotInitialized() &&
pathDisabledForNotInitializedCluster(request.getPath())) {
+ return Publishers.just(HttpProblemResponse.from(
+ Problem.fromHttpCode(HttpCode.CONFLICT)
+ .detail("Cluster is not initialized. Call
/management/v1/cluster/init in order to initialize cluster.")
+ .build()
+ ));
+ }
+ } catch (InterruptedException | ExecutionException | TimeoutException
e) {
+ throw new IgniteException(Common.UNEXPECTED_ERR, e);
+ }
+
+ return chain.proceed(request);
+ }
+
+ private boolean clusterNotInitialized() throws InterruptedException,
ExecutionException, TimeoutException {
+ CompletableFuture<ClusterState> stateFuture = cmgMgr.clusterState();
+ return stateFuture == null || stateFuture.get(1, TimeUnit.SECONDS) ==
null;
+ }
+}
+
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItNotInitializedClusterRestTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItNotInitializedClusterRestTest.java
index 2acb14435a..c25a484add 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItNotInitializedClusterRestTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItNotInitializedClusterRestTest.java
@@ -104,10 +104,10 @@ public class ItNotInitializedClusterRestTest extends
AbstractRestTestBase {
// Expect cluster configuration is not available
Problem problem = objectMapper.readValue(response.body(),
Problem.class);
assertAll(
- () -> assertThat(problem.status(), is(404)),
- () -> assertThat(problem.title(), is("Not Found")),
+ () -> assertThat(problem.status(), is(409)),
+ () -> assertThat(problem.title(), is("Conflict")),
() -> assertThat(problem.detail(),
- is("Cluster not initialized. Call
/management/v1/cluster/init in order to initialize cluster"))
+ is("Cluster is not initialized. Call
/management/v1/cluster/init in order to initialize cluster."))
);
}
@@ -123,10 +123,10 @@ public class ItNotInitializedClusterRestTest extends
AbstractRestTestBase {
// Expect cluster configuration could not be updated
Problem problem = objectMapper.readValue(response.body(),
Problem.class);
assertAll(
- () -> assertThat(problem.status(), is(404)),
- () -> assertThat(problem.title(), is("Not Found")),
+ () -> assertThat(problem.status(), is(409)),
+ () -> assertThat(problem.title(), is("Conflict")),
() -> assertThat(problem.detail(),
- is("Cluster not initialized. Call
/management/v1/cluster/init in order to initialize cluster"))
+ is("Cluster is not initialized. Call
/management/v1/cluster/init in order to initialize cluster."))
);
}
@@ -139,10 +139,10 @@ public class ItNotInitializedClusterRestTest extends
AbstractRestTestBase {
// Then
Problem problem = objectMapper.readValue(response.body(),
Problem.class);
assertAll(
- () -> assertThat(problem.status(), is(404)),
- () -> assertThat(problem.title(), is("Not Found")),
+ () -> assertThat(problem.status(), is(409)),
+ () -> assertThat(problem.title(), is("Conflict")),
() -> assertThat(problem.detail(),
- is("Cluster not initialized. Call
/management/v1/cluster/init in order to initialize cluster"))
+ is("Cluster is not initialized. Call
/management/v1/cluster/init in order to initialize cluster."))
);
}
@@ -188,10 +188,10 @@ public class ItNotInitializedClusterRestTest extends
AbstractRestTestBase {
// Then
Problem problem = objectMapper.readValue(response.body(),
Problem.class);
assertAll(
- () -> assertThat(problem.status(), is(404)),
- () -> assertThat(problem.title(), is("Not Found")),
+ () -> assertThat(problem.status(), is(409)),
+ () -> assertThat(problem.title(), is("Conflict")),
() -> assertThat(problem.detail(),
- is("Cluster not initialized. Call
/management/v1/cluster/init in order to initialize cluster"))
+ is("Cluster is not initialized. Call
/management/v1/cluster/init in order to initialize cluster."))
);
}