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

sanpwc 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 3d7949b6a3d [IGNITE-26459] Add ability to explicitly trigger dataNodes 
recalculation via CLI command (#7120)
3d7949b6a3d is described below

commit 3d7949b6a3d22b37f6e79152b7f4f46b10333bac
Author: Egor <[email protected]>
AuthorDate: Wed Dec 3 18:12:05 2025 +0400

    [IGNITE-26459] Add ability to explicitly trigger dataNodes recalculation 
via CLI command (#7120)
    
    Co-authored-by: Egor Kuts <[email protected]>
---
 .../ItRecalculateDataNodesCommandTest.java         | 26 +++++++
 .../ItRecalculateDataNodesReplCommandTest.java     | 26 +++++++
 .../zone/datanodes/ItRecalculateDataNodesTest.java | 87 ++++++++++++++++++++++
 .../management/zone/RecalculateDataNodesCall.java  | 54 ++++++++++++++
 .../zone/RecalculateDataNodesCallInput.java        | 56 ++++++++++++++
 .../ignite/internal/cli/commands/Options.java      |  5 ++
 .../internal/cli/commands/TopLevelCliCommand.java  |  2 +
 .../cli/commands/TopLevelCliReplCommand.java       |  2 +
 .../internal/cli/commands/zone/ZoneCommand.java    | 33 ++++++++
 .../cli/commands/zone/ZoneReplCommand.java         | 33 ++++++++
 .../commands/zone/datanodes/DataNodesCommand.java  | 32 ++++++++
 .../zone/datanodes/DataNodesReplCommand.java       | 32 ++++++++
 .../datanodes/RecalculateDataNodesCommand.java     | 52 +++++++++++++
 .../zone/datanodes/RecalculateDataNodesMixin.java  | 39 ++++++++++
 .../datanodes/RecalculateDataNodesReplCommand.java | 60 +++++++++++++++
 15 files changed, 539 insertions(+)

diff --git 
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/zone/datanodes/ItRecalculateDataNodesCommandTest.java
 
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/zone/datanodes/ItRecalculateDataNodesCommandTest.java
new file mode 100644
index 00000000000..80af525af88
--- /dev/null
+++ 
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/zone/datanodes/ItRecalculateDataNodesCommandTest.java
@@ -0,0 +1,26 @@
+/*
+ * 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.zone.datanodes;
+
+/** Test class for {@link RecalculateDataNodesCommand}. */
+public class ItRecalculateDataNodesCommandTest extends 
ItRecalculateDataNodesTest {
+    @Override
+    protected Class<?> getCommandClass() {
+        return RecalculateDataNodesCommand.class;
+    }
+}
diff --git 
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/zone/datanodes/ItRecalculateDataNodesReplCommandTest.java
 
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/zone/datanodes/ItRecalculateDataNodesReplCommandTest.java
new file mode 100644
index 00000000000..8e98c280a45
--- /dev/null
+++ 
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/zone/datanodes/ItRecalculateDataNodesReplCommandTest.java
@@ -0,0 +1,26 @@
+/*
+ * 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.zone.datanodes;
+
+/** Test class for {@link RecalculateDataNodesReplCommand}. */
+public class ItRecalculateDataNodesReplCommandTest extends 
ItRecalculateDataNodesTest {
+    @Override
+    protected Class<?> getCommandClass() {
+        return RecalculateDataNodesReplCommand.class;
+    }
+}
diff --git 
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/zone/datanodes/ItRecalculateDataNodesTest.java
 
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/zone/datanodes/ItRecalculateDataNodesTest.java
new file mode 100644
index 00000000000..33b712cd07f
--- /dev/null
+++ 
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/zone/datanodes/ItRecalculateDataNodesTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.zone.datanodes;
+
+import static 
org.apache.ignite.internal.TestDefaultProfilesNames.DEFAULT_AIPERSIST_PROFILE_NAME;
+import static 
org.apache.ignite.internal.cli.commands.Options.Constants.CLUSTER_URL_OPTION;
+
+import org.apache.ignite.internal.cli.CliIntegrationTest;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/** Base test class for recalculate data nodes commands. */
+public abstract class ItRecalculateDataNodesTest extends CliIntegrationTest {
+    private static final String ZONE1 = "test_zone_1";
+    private static final String ZONE2 = "test_zone_2";
+
+    @BeforeAll
+    public void createZones() {
+        sql(String.format("CREATE ZONE \"%s\" storage profiles['%s']", ZONE1, 
DEFAULT_AIPERSIST_PROFILE_NAME));
+        sql(String.format("CREATE ZONE \"%s\" storage profiles['%s']", ZONE2, 
DEFAULT_AIPERSIST_PROFILE_NAME));
+    }
+
+    @Test
+    public void testRecalculateAllZones() {
+        execute(CLUSTER_URL_OPTION, NODE_URL);
+
+        assertErrOutputIsEmpty();
+        assertOutputContains("Done");
+    }
+
+    @Test
+    public void testRecalculateSpecifiedZones() {
+        execute(CLUSTER_URL_OPTION, NODE_URL,
+                "--zone-names", ZONE1 + "," + ZONE2);
+
+        assertErrOutputIsEmpty();
+        assertOutputContains("Done");
+    }
+
+    @Test
+    public void testRecalculateSingleZone() {
+        execute(CLUSTER_URL_OPTION, NODE_URL,
+                "--zone-names", ZONE1);
+
+        assertErrOutputIsEmpty();
+        assertOutputContains("Done");
+    }
+
+    @Test
+    public void testRecalculateNonExistentZone() {
+        String unknownZone = "unknown_zone";
+
+        execute(CLUSTER_URL_OPTION, NODE_URL,
+                "--zone-names", unknownZone);
+
+        assertErrOutputContains("Distribution zones were not found");
+        assertErrOutputContains(unknownZone);
+        assertOutputIsEmpty();
+    }
+
+    @Test
+    public void testRecalculateMixedZones() {
+        String unknownZone = "unknown_zone";
+
+        execute(CLUSTER_URL_OPTION, NODE_URL,
+                "--zone-names", ZONE1 + "," + unknownZone);
+
+        assertErrOutputContains("Distribution zones were not found");
+        assertErrOutputContains(unknownZone);
+        assertOutputIsEmpty();
+    }
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/management/zone/RecalculateDataNodesCall.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/management/zone/RecalculateDataNodesCall.java
new file mode 100644
index 00000000000..05633abe0d8
--- /dev/null
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/management/zone/RecalculateDataNodesCall.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.call.management.zone;
+
+import jakarta.inject.Singleton;
+import java.util.Collections;
+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.rest.ApiClientFactory;
+import org.apache.ignite.internal.cli.core.style.component.MessageUiComponent;
+import org.apache.ignite.internal.cli.core.style.element.UiElements;
+import org.apache.ignite.rest.client.api.DataNodesApi;
+import org.apache.ignite.rest.client.invoker.ApiException;
+
+/** Call to recalculate data nodes for distribution zones. */
+@Singleton
+public class RecalculateDataNodesCall implements 
Call<RecalculateDataNodesCallInput, String> {
+
+    private final ApiClientFactory clientFactory;
+
+    RecalculateDataNodesCall(ApiClientFactory clientFactory) {
+        this.clientFactory = clientFactory;
+    }
+
+    @Override
+    public CallOutput<String> execute(RecalculateDataNodesCallInput input) {
+        try {
+            DataNodesApi api = new 
DataNodesApi(clientFactory.getClient(input.clusterUrl()));
+            // If no zone names specified, pass an empty list (which means 
recalculate all zones).
+            api.resetDataNodesForZones(input.zoneNames() == null ? 
Collections.emptyList() : input.zoneNames());
+
+            return 
DefaultCallOutput.success(MessageUiComponent.from(UiElements.done()).render());
+        } catch (ApiException e) {
+            return DefaultCallOutput.failure(new IgniteCliApiException(e, 
input.clusterUrl()));
+        }
+    }
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/management/zone/RecalculateDataNodesCallInput.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/management/zone/RecalculateDataNodesCallInput.java
new file mode 100644
index 00000000000..d067ad68861
--- /dev/null
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/management/zone/RecalculateDataNodesCallInput.java
@@ -0,0 +1,56 @@
+/*
+ * 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.management.zone;
+
+import java.util.List;
+import 
org.apache.ignite.internal.cli.commands.zone.datanodes.RecalculateDataNodesMixin;
+import org.apache.ignite.internal.cli.core.call.CallInput;
+
+/**
+ * Input for {@link RecalculateDataNodesCall}.
+ */
+public class RecalculateDataNodesCallInput implements CallInput {
+    private final List<String> zoneNames;
+    private final String clusterUrl;
+
+    private RecalculateDataNodesCallInput(List<String> zoneNames, String 
clusterUrl) {
+        this.zoneNames = zoneNames;
+        this.clusterUrl = clusterUrl;
+    }
+
+    /**
+     * Creates input from mixin and cluster URL.
+     *
+     * @param mixin Mixin with command options.
+     * @param clusterUrl Cluster URL.
+     * @return Call input.
+     */
+    public static RecalculateDataNodesCallInput of(RecalculateDataNodesMixin 
mixin, String clusterUrl) {
+        return new RecalculateDataNodesCallInput(mixin.zoneNames(), 
clusterUrl);
+    }
+
+    /** Returns zone names to recalculate data nodes for. */
+    public List<String> zoneNames() {
+        return zoneNames;
+    }
+
+    /** Returns cluster URL. */
+    public String clusterUrl() {
+        return clusterUrl;
+    }
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/Options.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/Options.java
index a64ebf215fc..f93e8e3b58d 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/Options.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/Options.java
@@ -335,5 +335,10 @@ public enum Options {
 
         /** Config update file option description. */
         public static final String CONFIG_UPDATE_FILE_OPTION_DESC = "Path to 
file with config update commands to execute";
+
+        public static final String RECALCULATE_ZONE_NAMES_OPTION = 
"--zone-names";
+
+        public static final String RECALCULATE_ZONE_NAMES_OPTION_DESC = 
"Comma-separated list of zone names to recalculate data nodes for. "
+                + "If not specified, recalculates for all zones.";
     }
 }
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliCommand.java
index 764eae83cfe..f53b51ba944 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliCommand.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliCommand.java
@@ -28,6 +28,7 @@ import 
org.apache.ignite.internal.cli.commands.connect.ConnectCommand;
 import org.apache.ignite.internal.cli.commands.node.NodeCommand;
 import org.apache.ignite.internal.cli.commands.recovery.RecoveryCommand;
 import org.apache.ignite.internal.cli.commands.sql.SqlCommand;
+import org.apache.ignite.internal.cli.commands.zone.ZoneCommand;
 import picocli.CommandLine;
 import picocli.CommandLine.Command;
 import picocli.CommandLine.Option;
@@ -48,6 +49,7 @@ import picocli.CommandLine.Option;
                 ConnectCommand.class,
                 NodeCommand.class,
                 ClusterCommand.class,
+                ZoneCommand.class,
                 RecoveryCommand.class
         })
 public class TopLevelCliCommand extends BaseCommand {
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
index 0f52531fb08..ce1692c21eb 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
@@ -36,6 +36,7 @@ import 
org.apache.ignite.internal.cli.commands.node.NodeReplCommand;
 import org.apache.ignite.internal.cli.commands.recovery.RecoveryReplCommand;
 import org.apache.ignite.internal.cli.commands.sql.SqlReplCommand;
 import org.apache.ignite.internal.cli.commands.version.VersionCommand;
+import org.apache.ignite.internal.cli.commands.zone.ZoneReplCommand;
 import picocli.CommandLine;
 import picocli.CommandLine.Command;
 import picocli.shell.jline3.PicocliCommands;
@@ -56,6 +57,7 @@ import picocli.shell.jline3.PicocliCommands;
                 DisconnectCommand.class,
                 NodeReplCommand.class,
                 ClusterReplCommand.class,
+                ZoneReplCommand.class,
                 RecoveryReplCommand.class
         },
 
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/ZoneCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/ZoneCommand.java
new file mode 100644
index 00000000000..ddc84d39a2c
--- /dev/null
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/ZoneCommand.java
@@ -0,0 +1,33 @@
+/*
+ * 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.zone;
+
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import org.apache.ignite.internal.cli.commands.zone.datanodes.DataNodesCommand;
+import picocli.CommandLine.Command;
+
+/**
+ * Zone management command.
+ */
+@Command(name = "zone",
+        subcommands = {
+                DataNodesCommand.class
+        },
+        description = "Manages distribution zones")
+public class ZoneCommand extends BaseCommand {
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/ZoneReplCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/ZoneReplCommand.java
new file mode 100644
index 00000000000..a66817b9270
--- /dev/null
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/ZoneReplCommand.java
@@ -0,0 +1,33 @@
+/*
+ * 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.zone;
+
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import 
org.apache.ignite.internal.cli.commands.zone.datanodes.DataNodesReplCommand;
+import picocli.CommandLine.Command;
+
+/**
+ * Zone management REPL command.
+ */
+@Command(name = "zone",
+        subcommands = {
+                DataNodesReplCommand.class
+        },
+        description = "Manages distribution zones")
+public class ZoneReplCommand extends BaseCommand {
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/DataNodesCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/DataNodesCommand.java
new file mode 100644
index 00000000000..8e1da37b105
--- /dev/null
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/DataNodesCommand.java
@@ -0,0 +1,32 @@
+/*
+ * 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.zone.datanodes;
+
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import picocli.CommandLine.Command;
+
+/**
+ * Data nodes management command.
+ */
+@Command(name = "datanodes",
+        subcommands = {
+                RecalculateDataNodesCommand.class
+        },
+        description = "Manages data nodes for distribution zones")
+public class DataNodesCommand extends BaseCommand {
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/DataNodesReplCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/DataNodesReplCommand.java
new file mode 100644
index 00000000000..64de0618c7e
--- /dev/null
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/DataNodesReplCommand.java
@@ -0,0 +1,32 @@
+/*
+ * 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.zone.datanodes;
+
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import picocli.CommandLine.Command;
+
+/**
+ * Data nodes management REPL command.
+ */
+@Command(name = "datanodes",
+        subcommands = {
+                RecalculateDataNodesReplCommand.class
+        },
+        description = "Manages data nodes for distribution zones")
+public class DataNodesReplCommand extends BaseCommand {
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/RecalculateDataNodesCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/RecalculateDataNodesCommand.java
new file mode 100644
index 00000000000..369d2b45ff5
--- /dev/null
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/RecalculateDataNodesCommand.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.zone.datanodes;
+
+import jakarta.inject.Inject;
+import java.util.concurrent.Callable;
+import 
org.apache.ignite.internal.cli.call.management.zone.RecalculateDataNodesCall;
+import 
org.apache.ignite.internal.cli.call.management.zone.RecalculateDataNodesCallInput;
+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;
+
+/** Command to recalculate data nodes for distribution zones. */
+@Command(name = "recalculate", description = "Recalculates data nodes for 
distribution zones")
+public class RecalculateDataNodesCommand extends BaseCommand implements 
Callable<Integer> {
+
+    /** Cluster endpoint URL option. */
+    @Mixin
+    private ClusterUrlProfileMixin clusterUrl;
+
+    @Mixin
+    private RecalculateDataNodesMixin options;
+
+    @Inject
+    private RecalculateDataNodesCall call;
+
+    @Override
+    public Integer call() {
+        return runPipeline(CallExecutionPipeline.builder(call)
+                .inputProvider(() -> RecalculateDataNodesCallInput.of(options, 
clusterUrl.getClusterUrl()))
+                
.exceptionHandler(ClusterNotInitializedExceptionHandler.createHandler("Cannot 
recalculate data nodes"))
+        );
+    }
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/RecalculateDataNodesMixin.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/RecalculateDataNodesMixin.java
new file mode 100644
index 00000000000..dd4e4493d7b
--- /dev/null
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/RecalculateDataNodesMixin.java
@@ -0,0 +1,39 @@
+/*
+ * 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.zone.datanodes;
+
+import static 
org.apache.ignite.internal.cli.commands.Options.Constants.RECALCULATE_ZONE_NAMES_OPTION;
+import static 
org.apache.ignite.internal.cli.commands.Options.Constants.RECALCULATE_ZONE_NAMES_OPTION_DESC;
+
+import java.util.List;
+import picocli.CommandLine.Option;
+
+/** Arguments for recalculate data nodes command. */
+public class RecalculateDataNodesMixin {
+    @Option(
+            names = RECALCULATE_ZONE_NAMES_OPTION,
+            description = RECALCULATE_ZONE_NAMES_OPTION_DESC,
+            split = ","
+    )
+    private List<String> zoneNames;
+
+    /** Returns names of zones to recalculate data nodes for. */
+    public List<String> zoneNames() {
+        return zoneNames;
+    }
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/RecalculateDataNodesReplCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/RecalculateDataNodesReplCommand.java
new file mode 100644
index 00000000000..44bb692d2ba
--- /dev/null
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/zone/datanodes/RecalculateDataNodesReplCommand.java
@@ -0,0 +1,60 @@
+/*
+ * 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.zone.datanodes;
+
+import jakarta.inject.Inject;
+import 
org.apache.ignite.internal.cli.call.management.zone.RecalculateDataNodesCall;
+import 
org.apache.ignite.internal.cli.call.management.zone.RecalculateDataNodesCallInput;
+import org.apache.ignite.internal.cli.commands.BaseCommand;
+import org.apache.ignite.internal.cli.commands.cluster.ClusterUrlMixin;
+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;
+
+/** REPL command to recalculate data nodes for distribution zones. */
+@Command(name = "recalculate", description = "Recalculates data nodes for 
distribution zones")
+public class RecalculateDataNodesReplCommand extends BaseCommand implements 
Runnable {
+
+    @Mixin
+    private ClusterUrlMixin clusterUrl;
+
+    @Mixin
+    private RecalculateDataNodesMixin options;
+
+    @Inject
+    private RecalculateDataNodesCall call;
+
+    @Inject
+    private ConnectToClusterQuestion question;
+
+    @Override
+    public void run() {
+        runFlow(question.askQuestionIfNotConnected(clusterUrl.getClusterUrl())
+                .map(this::recalculateDataNodesCallInput)
+                .then(Flows.fromCall(call))
+                
.exceptionHandler(ClusterNotInitializedExceptionHandler.createReplHandler("Cannot
 recalculate data nodes"))
+                .print()
+        );
+    }
+
+    private RecalculateDataNodesCallInput recalculateDataNodesCallInput(String 
clusterUrl) {
+        return RecalculateDataNodesCallInput.of(options, clusterUrl);
+    }
+}

Reply via email to