This is an automated email from the ASF dual-hosted git repository.
mpetrov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 05fa9b6f468 IGNITE-26987 Fix control.sh --kill compute command
authorization and authorization error propagation (#12525)
05fa9b6f468 is described below
commit 05fa9b6f468c94908056e1fd57a0a6c9ec4b8013
Author: Andrey Nadyktov <[email protected]>
AuthorDate: Fri Dec 5 13:45:40 2025 +0300
IGNITE-26987 Fix control.sh --kill compute command authorization and
authorization error propagation (#12525)
---
.../SecurityCommandHandlerPermissionsTest.java | 145 +++++++++++++++++++--
.../apache/ignite/internal/ComputeMXBeanImpl.java | 2 +-
.../management/kill/ComputeCancelSessionTask.java | 17 ++-
3 files changed, 145 insertions(+), 19 deletions(-)
diff --git
a/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/SecurityCommandHandlerPermissionsTest.java
b/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/SecurityCommandHandlerPermissionsTest.java
index b3a242c22c4..d10e6635a84 100644
---
a/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/SecurityCommandHandlerPermissionsTest.java
+++
b/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/SecurityCommandHandlerPermissionsTest.java
@@ -22,31 +22,52 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.compute.ComputeJob;
+import org.apache.ignite.compute.ComputeJobResult;
+import org.apache.ignite.compute.ComputeTaskAdapter;
+import org.apache.ignite.compute.ComputeTaskFuture;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.internal.client.thin.ServicesTest;
+import org.apache.ignite.internal.managers.systemview.GridSystemViewManager;
import org.apache.ignite.internal.processors.security.impl.TestSecurityData;
import
org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider;
import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.lang.IgniteFutureCancelledException;
import org.apache.ignite.lang.IgniteProductVersion;
import org.apache.ignite.plugin.security.SecurityPermission;
import org.apache.ignite.plugin.security.SecurityPermissionSet;
import org.apache.ignite.plugin.security.SecurityPermissionSetBuilder;
import org.apache.ignite.services.ServiceConfiguration;
import org.apache.ignite.services.ServiceDescriptor;
+import org.apache.ignite.spi.systemview.view.ComputeTaskView;
import org.apache.ignite.util.GridCommandHandlerAbstractTest;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.junit.Test;
import org.junit.runners.Parameterized;
import static java.util.Arrays.asList;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_BUILD_VER;
import static
org.apache.ignite.internal.commandline.ArgumentParser.CMD_PASSWORD;
import static org.apache.ignite.internal.commandline.ArgumentParser.CMD_USER;
import static
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
import static
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_UNEXPECTED_ERROR;
+import static
org.apache.ignite.internal.processors.job.GridJobProcessor.JOBS_VIEW;
+import static
org.apache.ignite.internal.processors.task.GridTaskProcessor.TASKS_VIEW;
import static org.apache.ignite.internal.util.IgniteUtils.resolveIgnitePath;
import static
org.apache.ignite.plugin.security.SecurityPermission.ADMIN_ROLLING_UPGRADE;
import static
org.apache.ignite.plugin.security.SecurityPermission.CACHE_CREATE;
@@ -54,9 +75,11 @@ import static
org.apache.ignite.plugin.security.SecurityPermission.CACHE_DESTROY
import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_READ;
import static
org.apache.ignite.plugin.security.SecurityPermission.CACHE_REMOVE;
import static
org.apache.ignite.plugin.security.SecurityPermission.SERVICE_CANCEL;
+import static org.apache.ignite.plugin.security.SecurityPermission.TASK_CANCEL;
import static
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALL_PERMISSIONS;
import static
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.NO_PERMISSIONS;
import static
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.systemPermissions;
+import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
/** */
public class SecurityCommandHandlerPermissionsTest extends
GridCommandHandlerAbstractTest {
@@ -82,6 +105,8 @@ public class SecurityCommandHandlerPermissionsTest extends
GridCommandHandlerAbs
persistenceEnable(false);
injectTestSystemOut();
+
+ TestJob.CANCELLED_JOB_CNT.set(0);
}
/** {@inheritDoc} */
@@ -155,22 +180,22 @@ public class SecurityCommandHandlerPermissionsTest
extends GridCommandHandlerAbs
List<String> cmdArgs = asList("--rolling-upgrade", "enable",
targetVerStr);
- assertEquals(EXIT_CODE_UNEXPECTED_ERROR,
execute(enrichWithConnectionArguments(cmdArgs, TEST_NO_PERMISSIONS_LOGIN)));
+ assertEquals(EXIT_CODE_UNEXPECTED_ERROR, executeOnBehalf(cmdArgs,
TEST_NO_PERMISSIONS_LOGIN));
assertFalse(ign.context().rollingUpgrade().enabled());
- assertEquals(EXIT_CODE_OK,
execute(enrichWithConnectionArguments(cmdArgs, TEST_LOGIN)));
+ assertEquals(EXIT_CODE_OK, executeOnBehalf(cmdArgs, TEST_LOGIN));
assertTrue(ign.context().rollingUpgrade().enabled());
assertEquals(IgniteProductVersion.fromString(targetVerStr),
ign.context().rollingUpgrade().versions().get2());
cmdArgs = asList("--rolling-upgrade", "disable");
- assertEquals(EXIT_CODE_UNEXPECTED_ERROR,
execute(enrichWithConnectionArguments(cmdArgs, TEST_NO_PERMISSIONS_LOGIN)));
+ assertEquals(EXIT_CODE_UNEXPECTED_ERROR, executeOnBehalf(cmdArgs,
TEST_NO_PERMISSIONS_LOGIN));
assertTrue(ign.context().rollingUpgrade().enabled());
- assertEquals(EXIT_CODE_OK,
execute(enrichWithConnectionArguments(cmdArgs, TEST_LOGIN)));
+ assertEquals(EXIT_CODE_OK, executeOnBehalf(cmdArgs, TEST_LOGIN));
assertFalse(ign.context().rollingUpgrade().enabled());
}
@@ -198,15 +223,66 @@ public class SecurityCommandHandlerPermissionsTest
extends GridCommandHandlerAbs
Collection<ServiceDescriptor> svcs =
ignite.services().serviceDescriptors();
- assertEquals(EXIT_CODE_UNEXPECTED_ERROR,
execute(enrichWithConnectionArguments(cmdArgs, TEST_NO_PERMISSIONS_LOGIN)));
+ assertEquals(EXIT_CODE_UNEXPECTED_ERROR, executeOnBehalf(cmdArgs,
TEST_NO_PERMISSIONS_LOGIN));
assertEquals(1, svcs.size());
- assertEquals(EXIT_CODE_OK,
execute(enrichWithConnectionArguments(cmdArgs, TEST_LOGIN)));
+ assertEquals(EXIT_CODE_OK, executeOnBehalf(cmdArgs, TEST_LOGIN));
svcs = ignite.services().serviceDescriptors();
assertEquals(0, svcs.size());
}
+ /** */
+ @Test
+ public void testTaskCancel() throws Exception {
+ IgniteEx ignite = startGrid(
+ 0,
+ userData(TEST_NO_PERMISSIONS_LOGIN, NO_PERMISSIONS),
+ userData(TEST_LOGIN, SecurityPermissionSetBuilder.create()
+ .defaultAllowAll(false)
+ .appendTaskPermissions(TestTask.class.getName(), TASK_CANCEL)
+ .build())
+ );
+
+ ComputeTaskFuture<ComputeJobResult> fut =
ignite.compute().executeAsync(new TestTask(), null);
+
+ GridSystemViewManager viewMgr = ignite.context().systemView();
+
+ assertTrue(waitForCondition(() -> viewMgr.view(TASKS_VIEW).size() >=
1, getTestTimeout()));
+ assertTrue(waitForCondition(() -> viewMgr.view(JOBS_VIEW).size() >= 1,
getTestTimeout()));
+
+ Iterator<ComputeTaskView> iter =
viewMgr.<ComputeTaskView>view(TASKS_VIEW).iterator();
+
+ String sesId = iter.next().sessionId().toString();
+
+ assertFalse(iter.hasNext());
+
+ Collection<String> cmdArgs = asList("--kill", "compute", sesId);
+
+ assertEquals(EXIT_CODE_UNEXPECTED_ERROR, executeOnBehalf(cmdArgs,
TEST_NO_PERMISSIONS_LOGIN));
+
+ assertFalse(fut.isDone());
+
+ assertEquals(0, TestJob.CANCELLED_JOB_CNT.get());
+
+ assertTrue(waitForCondition(() -> viewMgr.view(TASKS_VIEW).size() >=
1, getTestTimeout()));
+ assertTrue(waitForCondition(() -> viewMgr.view(JOBS_VIEW).size() >= 1,
getTestTimeout()));
+
+ assertEquals(EXIT_CODE_OK, executeOnBehalf(cmdArgs, TEST_LOGIN));
+
+ try {
+ assertTrue(fut.get(getTestTimeout(), MILLISECONDS).isCancelled());
+ }
+ catch (Exception e) {
+ assertTrue(X.hasCause(e, IgniteFutureCancelledException.class));
+ }
+
+ assertTrue(waitForCondition(() -> viewMgr.view(TASKS_VIEW).size() ==
0, getTestTimeout()));
+ assertTrue(waitForCondition(() -> viewMgr.view(JOBS_VIEW).size() == 0,
getTestTimeout()));
+
+ assertEquals(1, TestJob.CANCELLED_JOB_CNT.get());
+ }
+
/** */
protected IgniteEx startGrid(int idx, TestSecurityData... userData) throws
Exception {
String login = getTestIgniteInstanceName(idx);
@@ -228,13 +304,13 @@ public class SecurityCommandHandlerPermissionsTest
extends GridCommandHandlerAbs
ignite.createCache(DEFAULT_CACHE_NAME);
- assertEquals(EXIT_CODE_UNEXPECTED_ERROR,
execute(enrichWithConnectionArguments(cmdArgs, TEST_NO_PERMISSIONS_LOGIN)));
+ assertEquals(EXIT_CODE_UNEXPECTED_ERROR, executeOnBehalf(cmdArgs,
TEST_NO_PERMISSIONS_LOGIN));
- // We are losing command failure cause for --cache clear commnad. See
IGNITE-21023 for more details.
+ // We are losing command failure cause for --cache clear command. See
IGNITE-21023 for more details.
if (!cmdArgs.containsAll(Arrays.asList("--cache", "clear")))
assertTrue(testOut.toString().contains("Authorization failed"));
- assertEquals(EXIT_CODE_OK,
execute(enrichWithConnectionArguments(cmdArgs, TEST_LOGIN)));
+ assertEquals(EXIT_CODE_OK, executeOnBehalf(cmdArgs, TEST_LOGIN));
}
/** */
@@ -276,4 +352,55 @@ public class SecurityCommandHandlerPermissionsTest extends
GridCommandHandlerAbs
new Permissions()
);
}
+
+ /** */
+ private int executeOnBehalf(Collection<String> cmdArgs, String login) {
+ return execute(enrichWithConnectionArguments(cmdArgs, login));
+ }
+
+ /** */
+ private static class TestTask extends ComputeTaskAdapter<Object,
ComputeJobResult> {
+ /** {@inheritDoc} */
+ @Override public @NotNull Map<? extends ComputeJob, ClusterNode> map(
+ List<ClusterNode> subgrid,
+ @Nullable Object arg
+ ) throws IgniteException {
+ return subgrid.stream().filter(g ->
!g.isClient()).collect(Collectors.toMap(ignored -> new TestJob(), srv -> srv));
+ }
+
+ /** {@inheritDoc} */
+ @Override public @Nullable ComputeJobResult
reduce(List<ComputeJobResult> results) throws IgniteException {
+ assertTrue(results.size() == 1);
+
+ return results.get(0);
+ }
+ }
+
+ /** */
+ private static class TestJob implements ComputeJob {
+ /** */
+ private final CountDownLatch jobBlockedLatch = new CountDownLatch(1);
+
+ /** */
+ private static final AtomicInteger CANCELLED_JOB_CNT = new
AtomicInteger();
+
+ /** {@inheritDoc} */
+ @Override public void cancel() {
+ jobBlockedLatch.countDown();
+
+ CANCELLED_JOB_CNT.incrementAndGet();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object execute() throws IgniteException {
+ try {
+ assertTrue(jobBlockedLatch.await(5_000, MILLISECONDS));
+ }
+ catch (InterruptedException e) {
+ throw new IgniteException(e);
+ }
+
+ return null;
+ }
+ }
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/ComputeMXBeanImpl.java
b/modules/core/src/main/java/org/apache/ignite/internal/ComputeMXBeanImpl.java
index aa556c7f39a..7256ab2cafb 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/ComputeMXBeanImpl.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/ComputeMXBeanImpl.java
@@ -52,7 +52,7 @@ public class ComputeMXBeanImpl implements ComputeMXBean {
}
/**
- * Kills compute task by the session idenitifier.
+ * Kills compute task by the session identifier.
*
* @param sesId Session id.
*/
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/kill/ComputeCancelSessionTask.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/kill/ComputeCancelSessionTask.java
index 2ffc7be8138..03ef27182e7 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/kill/ComputeCancelSessionTask.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/kill/ComputeCancelSessionTask.java
@@ -17,14 +17,14 @@
package org.apache.ignite.internal.management.kill;
-import java.util.List;
-import org.apache.ignite.compute.ComputeJobResult;
import org.apache.ignite.internal.ComputeMXBeanImpl;
import org.apache.ignite.internal.processors.task.GridInternal;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.visor.VisorJob;
import org.apache.ignite.internal.visor.VisorOneNodeTask;
-import org.jetbrains.annotations.Nullable;
+import org.apache.ignite.plugin.security.SecurityPermissionSet;
+
+import static
org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.NO_PERMISSIONS;
/**
* Cancels given tasks sessions on all cluster nodes.
@@ -39,12 +39,6 @@ public class ComputeCancelSessionTask extends
VisorOneNodeTask<KillComputeComman
return new ComputeCancelSessionJob(arg, debug);
}
- /** {@inheritDoc} */
- @Nullable @Override protected Void reduce0(List<ComputeJobResult> results)
{
- // No-op, just awaiting all jobs done.
- return null;
- }
-
/**
* Job that cancel tasks.
*/
@@ -67,6 +61,11 @@ public class ComputeCancelSessionTask extends
VisorOneNodeTask<KillComputeComman
return null;
}
+ /** {@inheritDoc} */
+ @Override public SecurityPermissionSet requiredPermissions() {
+ return NO_PERMISSIONS;
+ }
+
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(ComputeCancelSessionJob.class, this);