This is an automated email from the ASF dual-hosted git repository.

apolovtsev 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 e2628892e43 IGNITE-27990 Make cluster name editable (#7669)
e2628892e43 is described below

commit e2628892e4319760e8e50d49326aa479a00dd2d9
Author: Aditya Mukhopadhyay <[email protected]>
AuthorDate: Fri Feb 27 16:23:50 2026 +0530

    IGNITE-27990 Make cluster name editable (#7669)
---
 .../management/raft/ItCmgRaftServiceTest.java      | 28 +++++++++++++++
 .../management/ClusterManagementGroupManager.java  | 17 +++++++++
 .../network/messages/CmgMessageGroup.java          |  6 ++++
 .../management/raft/CmgRaftGroupListener.java      | 28 +++++++++++++++
 .../cluster/management/raft/CmgRaftService.java    | 13 +++++++
 .../raft/commands/ChangeClusterNameCommand.java    | 30 ++++++++++++++++
 .../management/raft/CmgRaftGroupListenerTest.java  | 41 ++++++++++++++++++++--
 .../commands/CmgCommandsCompatibilityTest.java     | 15 ++++++++
 .../rest/api/cluster/ClusterManagementApi.java     | 16 +++++++++
 .../ignite/internal/rest/AbstractRestTestBase.java |  2 +-
 .../cluster/ItClusterManagementControllerTest.java | 35 ++++++++++++++++++
 .../rest/cluster/ClusterManagementController.java  | 25 +++++++++++++
 12 files changed, 253 insertions(+), 3 deletions(-)

diff --git 
a/modules/cluster-management/src/integrationTest/java/org/apache/ignite/internal/cluster/management/raft/ItCmgRaftServiceTest.java
 
b/modules/cluster-management/src/integrationTest/java/org/apache/ignite/internal/cluster/management/raft/ItCmgRaftServiceTest.java
index b344f1386f9..e4c0d086467 100644
--- 
a/modules/cluster-management/src/integrationTest/java/org/apache/ignite/internal/cluster/management/raft/ItCmgRaftServiceTest.java
+++ 
b/modules/cluster-management/src/integrationTest/java/org/apache/ignite/internal/cluster/management/raft/ItCmgRaftServiceTest.java
@@ -361,6 +361,34 @@ public class ItCmgRaftServiceTest extends 
BaseIgniteAbstractTest {
         assertThat(cluster.get(1).raftService.nodeNames(), 
containsInAnyOrder(topology));
     }
 
+    /**
+     * Tests saving and reading a cluster name.
+     */
+    @Test
+    void testClusterName() {
+        Node node1 = cluster.get(0);
+        Node node2 = cluster.get(1);
+
+        assertThat(node1.raftService.readClusterState(), 
willCompleteSuccessfully());
+        assertThat(node2.raftService.readClusterState(), 
willCompleteSuccessfully());
+
+        ClusterTag clusterTag = ClusterTag.randomClusterTag(msgFactory, 
"cluster");
+        ClusterState state = msgFactory.clusterState()
+                .cmgNodes(Set.copyOf(List.of("foo")))
+                .metaStorageNodes(Set.copyOf(List.of("bar")))
+                .version(IgniteProductVersion.CURRENT_VERSION.toString())
+                .clusterTag(clusterTag)
+                .build();
+
+        assertThat(node1.raftService.initClusterState(state), 
willCompleteSuccessfully());
+
+        assertThat(node1.raftService.changeClusterName("cluster2"), 
willCompleteSuccessfully());
+
+        ClusterTag clusterTag2 = ClusterTag.clusterTag(msgFactory, "cluster2", 
clusterTag.clusterId());
+        
assertThat(node1.raftService.readClusterState().thenApply(ClusterState::clusterTag),
 willBe(clusterTag2));
+        
assertThat(node2.raftService.readClusterState().thenApply(ClusterState::clusterTag),
 willBe(clusterTag2));
+    }
+
     /**
      * Tests saving and reading a {@link ClusterState}.
      */
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 71dafbe4098..8943cc9fc3f 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
@@ -29,6 +29,7 @@ import static 
org.apache.ignite.internal.util.ExceptionUtils.hasCause;
 import static org.apache.ignite.internal.util.ExceptionUtils.unwrapCause;
 import static org.apache.ignite.internal.util.IgniteUtils.failOrConsume;
 import static org.apache.ignite.lang.ErrorGroups.Common.NODE_STOPPING_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Rest.CLUSTER_NOT_INIT_ERR;
 
 import java.util.Collection;
 import java.util.List;
@@ -103,6 +104,7 @@ import org.apache.ignite.internal.util.ExceptionUtils;
 import org.apache.ignite.internal.util.IgniteSpinBusyLock;
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.apache.ignite.internal.vault.VaultManager;
+import org.apache.ignite.lang.IgniteException;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.TestOnly;
 
@@ -559,6 +561,21 @@ public class ClusterManagementGroupManager extends 
AbstractEventProducer<Cluster
         return serviceFuture == null ? nullCompletedFuture() : 
serviceFuture.thenCompose(CmgRaftService::readClusterState);
     }
 
+    /**
+     * Renames the cluster with the provided name.
+     *
+     * @param newName the new name for the cluster.
+     * @return Completable future that will be completed when cluster is 
initialized.
+     */
+    public CompletableFuture<Void> renameCluster(String newName) {
+        CompletableFuture<CmgRaftService> serviceFuture = raftService;
+
+        return serviceFuture == null
+                ? failedFuture(new IgniteException(CLUSTER_NOT_INIT_ERR,
+                "Cluster has not yet been initialized or the node is in the 
process of being stopped."))
+                : serviceFuture.thenCompose(cmgRaftService -> 
cmgRaftService.changeClusterName(newName));
+    }
+
     /**
      * Extracts the local state (if any) and starts the CMG.
      *
diff --git 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CmgMessageGroup.java
 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CmgMessageGroup.java
index 286f497417d..3d3caa19278 100644
--- 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CmgMessageGroup.java
+++ 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CmgMessageGroup.java
@@ -20,6 +20,7 @@ package 
org.apache.ignite.internal.cluster.management.network.messages;
 import org.apache.ignite.internal.cluster.management.ClusterState;
 import org.apache.ignite.internal.cluster.management.ClusterTag;
 import org.apache.ignite.internal.cluster.management.MetaStorageInfo;
+import 
org.apache.ignite.internal.cluster.management.raft.commands.ChangeClusterNameCommand;
 import 
org.apache.ignite.internal.cluster.management.raft.commands.ChangeMetaStorageInfoCommand;
 import 
org.apache.ignite.internal.cluster.management.raft.commands.ClusterNodeMessage;
 import 
org.apache.ignite.internal.cluster.management.raft.commands.InitCmgStateCommand;
@@ -146,6 +147,11 @@ public class CmgMessageGroup {
          */
         int CLUSTER_TAG = 62;
 
+        /**
+         * Message type for {@link ChangeClusterNameCommand}.
+         */
+        int CHANGE_CLUSTER_NAME = 63;
+
         /**
          * Do not delete this code for compatibility.
          */
diff --git 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftGroupListener.java
 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftGroupListener.java
index b9b96d93082..93b0453faa4 100644
--- 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftGroupListener.java
+++ 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftGroupListener.java
@@ -35,8 +35,10 @@ import java.util.function.LongConsumer;
 import java.util.stream.Collectors;
 import org.apache.ignite.internal.cluster.management.ClusterIdStore;
 import org.apache.ignite.internal.cluster.management.ClusterState;
+import org.apache.ignite.internal.cluster.management.ClusterTag;
 import org.apache.ignite.internal.cluster.management.MetaStorageInfo;
 import 
org.apache.ignite.internal.cluster.management.network.messages.CmgMessagesFactory;
+import 
org.apache.ignite.internal.cluster.management.raft.commands.ChangeClusterNameCommand;
 import 
org.apache.ignite.internal.cluster.management.raft.commands.ChangeMetaStorageInfoCommand;
 import 
org.apache.ignite.internal.cluster.management.raft.commands.ClusterNodeMessage;
 import 
org.apache.ignite.internal.cluster.management.raft.commands.InitCmgStateCommand;
@@ -216,6 +218,10 @@ public class CmgRaftGroupListener implements 
RaftGroupListener {
                 } else if (command instanceof ChangeMetaStorageInfoCommand) {
                     changeMetastorageNodes((ChangeMetaStorageInfoCommand) 
command);
 
+                    clo.result(null);
+                } else if (command instanceof ChangeClusterNameCommand) {
+                    changeClusterName((ChangeClusterNameCommand) command);
+
                     clo.result(null);
                 }
             } catch (Throwable e) {
@@ -323,6 +329,28 @@ public class CmgRaftGroupListener implements 
RaftGroupListener {
         }
     }
 
+    private void changeClusterName(ChangeClusterNameCommand command) {
+        ClusterState existingState = storageManager.getClusterState();
+
+        assert existingState != null : "Cluster state was not initialized when 
got " + command;
+
+        ClusterTag newTag = cmgMessagesFactory.clusterTag()
+                .clusterName(command.clusterName())
+                .clusterId(existingState.clusterTag().clusterId())
+                .build();
+
+        ClusterState newState = cmgMessagesFactory.clusterState()
+                .cmgNodes(Set.copyOf(existingState.cmgNodes()))
+                .metaStorageNodes(Set.copyOf(existingState.metaStorageNodes()))
+                .version(existingState.version())
+                .clusterTag(newTag)
+                
.initialClusterConfiguration(existingState.initialClusterConfiguration())
+                .formerClusterIds(existingState.formerClusterIds())
+                .build();
+
+        storageManager.putClusterState(newState);
+    }
+
     private void changeMetastorageNodes(ChangeMetaStorageInfoCommand command) {
         ClusterState existingState = storageManager.getClusterState();
 
diff --git 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftService.java
 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftService.java
index a9e37b70a75..acd0c1e042d 100644
--- 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftService.java
+++ 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftService.java
@@ -33,6 +33,7 @@ import 
org.apache.ignite.internal.cluster.management.InvalidNodeConfigurationExc
 import org.apache.ignite.internal.cluster.management.MetaStorageInfo;
 import org.apache.ignite.internal.cluster.management.NodeAttributes;
 import 
org.apache.ignite.internal.cluster.management.network.messages.CmgMessagesFactory;
+import 
org.apache.ignite.internal.cluster.management.raft.commands.ChangeClusterNameCommand;
 import 
org.apache.ignite.internal.cluster.management.raft.commands.ChangeMetaStorageInfoCommand;
 import 
org.apache.ignite.internal.cluster.management.raft.commands.ClusterNodeMessage;
 import 
org.apache.ignite.internal.cluster.management.raft.commands.JoinReadyCommand;
@@ -346,6 +347,18 @@ public class CmgRaftService implements ManuallyCloseable {
         }
     }
 
+    /**
+     * Changes cluster name.
+     *
+     * @return Future that completes when the change is finished.
+     */
+    public CompletableFuture<Void> changeClusterName(String clusterName) {
+        ChangeClusterNameCommand command = 
msgFactory.changeClusterNameCommand()
+                .clusterName(clusterName)
+                .build();
+        return raftService.run(command);
+    }
+
     /**
      * Changes Metastorage nodes.
      *
diff --git 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/commands/ChangeClusterNameCommand.java
 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/commands/ChangeClusterNameCommand.java
new file mode 100644
index 00000000000..f87b60170c7
--- /dev/null
+++ 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/commands/ChangeClusterNameCommand.java
@@ -0,0 +1,30 @@
+/*
+ * 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.cluster.management.raft.commands;
+
+import 
org.apache.ignite.internal.cluster.management.network.messages.CmgMessageGroup;
+import org.apache.ignite.internal.network.annotations.Transferable;
+import org.apache.ignite.internal.raft.WriteCommand;
+
+/**
+ * Message for updating the cluster name.
+ */
+@Transferable(CmgMessageGroup.Commands.CHANGE_CLUSTER_NAME)
+public interface ChangeClusterNameCommand extends WriteCommand {
+    String clusterName();
+}
diff --git 
a/modules/cluster-management/src/test/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftGroupListenerTest.java
 
b/modules/cluster-management/src/test/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftGroupListenerTest.java
index f075367efc1..eac2a79649e 100644
--- 
a/modules/cluster-management/src/test/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftGroupListenerTest.java
+++ 
b/modules/cluster-management/src/test/java/org/apache/ignite/internal/cluster/management/raft/CmgRaftGroupListenerTest.java
@@ -25,6 +25,7 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -178,9 +179,35 @@ public class CmgRaftGroupListenerTest extends 
BaseIgniteAbstractTest {
         verify(logicalTopology).fireTopologyLeap();
     }
 
+    @Test
+    void changeClusterNameChangesClusterName() {
+        initCmg();
+        changeClusterName();
+
+        ClusterState updatedState = 
listener.storageManager().getClusterState();
+        assertNotNull(updatedState);
+
+        ClusterTag expectedTag = msgFactory.clusterTag()
+                .clusterName("cluster2")
+                .clusterId(state.clusterTag().clusterId())
+                .build();
+
+        ClusterState expectedState = msgFactory.clusterState()
+                .cmgNodes(Set.copyOf(state.cmgNodes()))
+                .metaStorageNodes(Set.copyOf(state.metaStorageNodes()))
+                .version(state.version())
+                .clusterTag(expectedTag)
+                
.initialClusterConfiguration(state.initialClusterConfiguration())
+                .formerClusterIds(state.formerClusterIds())
+                .build();
+
+        assertThat(updatedState, is(expectedState));
+    }
+
     @Test
     void changeMetastorageInfoChangesMsInfo() {
-        initCmgAndChangeMgInfo();
+        initCmg();
+        changeMgInfo();
 
         ClusterState updatedState = 
listener.storageManager().getClusterState();
         assertThat(updatedState, is(notNullValue()));
@@ -195,14 +222,24 @@ public class CmgRaftGroupListenerTest extends 
BaseIgniteAbstractTest {
         
assertThat(listener.storageManager().getMetastorageRepairingConfigIndex(), 
is(123L));
     }
 
-    private void initCmgAndChangeMgInfo() {
+    private void initCmg() {
         listener.onWrite(iterator(
                 msgFactory.initCmgStateCommand()
                         .clusterState(state)
                         .node(node)
                         .build()
         ));
+    }
+
+    private void changeClusterName() {
+        listener.onWrite(iterator(
+                msgFactory.changeClusterNameCommand()
+                        .clusterName("cluster2")
+                        .build()
+        ));
+    }
 
+    private void changeMgInfo() {
         listener.onWrite(iterator(
                 msgFactory.changeMetaStorageInfoCommand()
                         .metaStorageNodes(Set.of("new-ms-1", "new-ms-2"))
diff --git 
a/modules/cluster-management/src/test/java/org/apache/ignite/internal/cluster/management/raft/commands/CmgCommandsCompatibilityTest.java
 
b/modules/cluster-management/src/test/java/org/apache/ignite/internal/cluster/management/raft/commands/CmgCommandsCompatibilityTest.java
index e6eca66bce7..7c0bef8f683 100644
--- 
a/modules/cluster-management/src/test/java/org/apache/ignite/internal/cluster/management/raft/commands/CmgCommandsCompatibilityTest.java
+++ 
b/modules/cluster-management/src/test/java/org/apache/ignite/internal/cluster/management/raft/commands/CmgCommandsCompatibilityTest.java
@@ -49,6 +49,7 @@ public class CmgCommandsCompatibilityTest extends 
BaseCommandsCompatibilityTest
     protected Collection<Command> commandsToSerialize() {
         return List.of(
                 createChangeMetaStorageInfoCommand(),
+                createChangeClusterNameCommand(),
                 createInitCmgStateCommand(),
                 createJoinReadyCommand(),
                 createJoinRequestCommand(),
@@ -60,6 +61,14 @@ public class CmgCommandsCompatibilityTest extends 
BaseCommandsCompatibilityTest
         );
     }
 
+    @Test
+    @TestForCommand(ChangeClusterNameCommand.class)
+    void testChangeClusterNameCommand() {
+        ChangeClusterNameCommand command = 
decodeCommand("CEANY2x1c3Rlck5hbWUy");
+
+        assertEquals("clusterName2", command.clusterName());
+    }
+
     @Test
     @TestForCommand(ChangeMetaStorageInfoCommand.class)
     void testChangeMetaStorageInfoCommand() {
@@ -213,6 +222,12 @@ public class CmgCommandsCompatibilityTest extends 
BaseCommandsCompatibilityTest
                 .build();
     }
 
+    private ChangeClusterNameCommand createChangeClusterNameCommand() {
+        return factory.changeClusterNameCommand()
+                .clusterName("clusterName2")
+                .build();
+    }
+
     private ChangeMetaStorageInfoCommand createChangeMetaStorageInfoCommand() {
         return factory.changeMetaStorageInfoCommand()
                 .metaStorageNodes(Set.of("msNode1", "msNode2"))
diff --git 
a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/cluster/ClusterManagementApi.java
 
b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/cluster/ClusterManagementApi.java
index 8ab84e363bc..25c547e32dc 100644
--- 
a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/cluster/ClusterManagementApi.java
+++ 
b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/cluster/ClusterManagementApi.java
@@ -66,4 +66,20 @@ public interface ClusterManagementApi {
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.PROBLEM_JSON)
     CompletableFuture<Void> init(@Body InitCommand initCommand);
+
+    /**
+     * Renames the cluster.
+     *
+     * @param newName the new name of the cluster.
+     * @return Completable future that will be completed when the cluster is 
renamed.
+     */
+    @Post("rename")
+    @Operation(operationId = "rename", summary = "Rename cluster", description 
= "Assigns a new name to the cluster.")
+    @ApiResponse(responseCode = "200", description = "Cluster renamed.",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON, schema 
= @Schema(implementation = ClusterTag.class)))
+    @ApiResponse(responseCode = "500", description = "Internal error.",
+            content = @Content(mediaType = MediaType.PROBLEM_JSON, schema = 
@Schema(implementation = Problem.class)))
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces({MediaType.APPLICATION_JSON, MediaType.PROBLEM_JSON})
+    CompletableFuture<ClusterTag> rename(@Body String newName);
 }
diff --git 
a/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/AbstractRestTestBase.java
 
b/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/AbstractRestTestBase.java
index 50859c83e7e..8577a27d9e6 100644
--- 
a/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/AbstractRestTestBase.java
+++ 
b/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/AbstractRestTestBase.java
@@ -35,7 +35,7 @@ import org.junit.jupiter.api.TestInfo;
  */
 public abstract class AbstractRestTestBase extends 
ClusterPerTestIntegrationTest {
     /** HTTP host and port url part. */
-    private static final String HTTP_HOST_PORT = "http://localhost:10300";;
+    protected static final String HTTP_HOST_PORT = "http://localhost:10300";;
 
     protected ObjectMapper objectMapper = new ObjectMapper();
 
diff --git 
a/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/cluster/ItClusterManagementControllerTest.java
 
b/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/cluster/ItClusterManagementControllerTest.java
index 1041a3c04df..511f6568d96 100644
--- 
a/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/cluster/ItClusterManagementControllerTest.java
+++ 
b/modules/rest/src/integrationTest/java/org/apache/ignite/internal/rest/cluster/ItClusterManagementControllerTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.rest.cluster;
 
+import static org.apache.ignite.internal.rest.constants.MediaType.TEXT_PLAIN;
 import static 
org.apache.ignite.internal.rest.matcher.ProblemHttpResponseMatcher.isProblemResponse;
 import static 
org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -25,9 +26,13 @@ import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.is;
 
 import io.micronaut.http.HttpStatus;
+import java.net.URI;
+import java.net.http.HttpRequest;
+import java.net.http.HttpRequest.BodyPublishers;
 import java.net.http.HttpResponse;
 import org.apache.ignite.internal.rest.AbstractRestTestBase;
 import org.apache.ignite.internal.rest.api.cluster.ClusterState;
+import org.apache.ignite.internal.rest.api.cluster.ClusterTag;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -119,4 +124,34 @@ public class ItClusterManagementControllerTest extends 
AbstractRestTestBase {
                 .withDetail(containsString("Init CMG request denied, reason: 
CMG node names do not match."))
         );
     }
+
+    @Test
+    void testClusterRename() throws Exception {
+        String initRequestBody = "{\n"
+                + "    \"metaStorageNodes\": [\n"
+                + "        \"" + cluster.nodeName(0) + "\"\n"
+                + "    ],\n"
+                + "    \"cmgNodes\": [\n"
+                + "        \"" + cluster.nodeName(0) + "\"\n"
+                + "    ],\n"
+                + "    \"clusterName\": \"cluster\"\n"
+                + "}";
+        HttpResponse<String> initResponse = 
send(post("/management/v1/cluster/init", initRequestBody));
+        assertThat(initResponse.statusCode(), is(HttpStatus.OK.getCode()));
+        assertThat(cluster.server(0).waitForInitAsync(), 
willCompleteSuccessfully());
+
+        HttpResponse<String> stateResponse = 
send(get("/management/v1/cluster/state"));
+        ClusterState state = objectMapper.readValue(stateResponse.body(), 
ClusterState.class);
+
+        HttpRequest renameRequest = 
HttpRequest.newBuilder(URI.create(HTTP_HOST_PORT + 
"/management/v1/cluster/rename"))
+                .header("content-type", TEXT_PLAIN)
+                .POST(BodyPublishers.ofString("cluster2"))
+                .build();
+        HttpResponse<String> renameResponse = send(renameRequest);
+        assertThat(renameResponse.statusCode(), is(HttpStatus.OK.getCode()));
+
+        ClusterTag clusterTag2 = objectMapper.readValue(renameResponse.body(), 
ClusterTag.class);
+        assertThat(clusterTag2.clusterName(), is("cluster2"));
+        assertThat(clusterTag2.clusterId(), 
is(state.clusterTag().clusterId()));
+    }
 }
diff --git 
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/cluster/ClusterManagementController.java
 
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/cluster/ClusterManagementController.java
index 009bbcb5370..ecc1cc81c07 100644
--- 
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/cluster/ClusterManagementController.java
+++ 
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/cluster/ClusterManagementController.java
@@ -99,6 +99,31 @@ public class ClusterManagementController implements 
ClusterManagementApi, Resour
                 });
     }
 
+    @Override
+    public CompletableFuture<ClusterTag> rename(String newName) {
+        LOG.info("Received rename command with new name = '{}'", newName);
+
+        return clusterManagementGroupManager.renameCluster(newName)
+                .thenCompose(unused -> 
clusterManagementGroupManager.clusterState())
+                .thenApply(ClusterManagementController::mapClusterTag)
+                .exceptionally(ex -> {
+                    throw mapException(ex);
+                });
+    }
+
+    private static ClusterTag mapClusterTag(@Nullable 
org.apache.ignite.internal.cluster.management.ClusterState clusterState) {
+        if (clusterState == null) {
+            throw new IgniteException(
+                    CLUSTER_NOT_INIT_ERR,
+                    "Cluster has not yet been initialized or the node is in 
the process of being stopped."
+            );
+        }
+
+        var clusterTag = clusterState.clusterTag();
+
+        return new ClusterTag(clusterTag.clusterName(), 
clusterTag.clusterId());
+    }
+
     private static ClusterState mapClusterState(@Nullable 
org.apache.ignite.internal.cluster.management.ClusterState clusterState) {
         if (clusterState == null) {
             throw new IgniteException(

Reply via email to