Skip to content

Commit 05fa9b6

Browse files
authored
IGNITE-26987 Fix control.sh --kill compute command authorization and authorization error propagation (#12525)
1 parent 944931e commit 05fa9b6

File tree

3 files changed

+145
-19
lines changed

3 files changed

+145
-19
lines changed

modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/SecurityCommandHandlerPermissionsTest.java

Lines changed: 136 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,41 +22,64 @@
2222
import java.util.Arrays;
2323
import java.util.Collection;
2424
import java.util.Collections;
25+
import java.util.Iterator;
2526
import java.util.List;
27+
import java.util.Map;
2628
import java.util.UUID;
29+
import java.util.concurrent.CountDownLatch;
30+
import java.util.concurrent.atomic.AtomicInteger;
31+
import java.util.stream.Collectors;
32+
2733
import org.apache.ignite.Ignite;
34+
import org.apache.ignite.IgniteException;
35+
import org.apache.ignite.cluster.ClusterNode;
36+
import org.apache.ignite.compute.ComputeJob;
37+
import org.apache.ignite.compute.ComputeJobResult;
38+
import org.apache.ignite.compute.ComputeTaskAdapter;
39+
import org.apache.ignite.compute.ComputeTaskFuture;
2840
import org.apache.ignite.configuration.IgniteConfiguration;
2941
import org.apache.ignite.internal.IgniteEx;
3042
import org.apache.ignite.internal.client.thin.ServicesTest;
43+
import org.apache.ignite.internal.managers.systemview.GridSystemViewManager;
3144
import org.apache.ignite.internal.processors.security.impl.TestSecurityData;
3245
import org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider;
3346
import org.apache.ignite.internal.util.typedef.F;
47+
import org.apache.ignite.internal.util.typedef.X;
48+
import org.apache.ignite.lang.IgniteFutureCancelledException;
3449
import org.apache.ignite.lang.IgniteProductVersion;
3550
import org.apache.ignite.plugin.security.SecurityPermission;
3651
import org.apache.ignite.plugin.security.SecurityPermissionSet;
3752
import org.apache.ignite.plugin.security.SecurityPermissionSetBuilder;
3853
import org.apache.ignite.services.ServiceConfiguration;
3954
import org.apache.ignite.services.ServiceDescriptor;
55+
import org.apache.ignite.spi.systemview.view.ComputeTaskView;
4056
import org.apache.ignite.util.GridCommandHandlerAbstractTest;
57+
import org.jetbrains.annotations.NotNull;
58+
import org.jetbrains.annotations.Nullable;
4159
import org.junit.Test;
4260
import org.junit.runners.Parameterized;
4361

4462
import static java.util.Arrays.asList;
63+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
4564
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_BUILD_VER;
4665
import static org.apache.ignite.internal.commandline.ArgumentParser.CMD_PASSWORD;
4766
import static org.apache.ignite.internal.commandline.ArgumentParser.CMD_USER;
4867
import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
4968
import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_UNEXPECTED_ERROR;
69+
import static org.apache.ignite.internal.processors.job.GridJobProcessor.JOBS_VIEW;
70+
import static org.apache.ignite.internal.processors.task.GridTaskProcessor.TASKS_VIEW;
5071
import static org.apache.ignite.internal.util.IgniteUtils.resolveIgnitePath;
5172
import static org.apache.ignite.plugin.security.SecurityPermission.ADMIN_ROLLING_UPGRADE;
5273
import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_CREATE;
5374
import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_DESTROY;
5475
import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_READ;
5576
import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_REMOVE;
5677
import static org.apache.ignite.plugin.security.SecurityPermission.SERVICE_CANCEL;
78+
import static org.apache.ignite.plugin.security.SecurityPermission.TASK_CANCEL;
5779
import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALL_PERMISSIONS;
5880
import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.NO_PERMISSIONS;
5981
import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.systemPermissions;
82+
import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
6083

6184
/** */
6285
public class SecurityCommandHandlerPermissionsTest extends GridCommandHandlerAbstractTest {
@@ -82,6 +105,8 @@ public static List<String> commandHandlers() {
82105
persistenceEnable(false);
83106

84107
injectTestSystemOut();
108+
109+
TestJob.CANCELLED_JOB_CNT.set(0);
85110
}
86111

87112
/** {@inheritDoc} */
@@ -155,22 +180,22 @@ public void testRollingUpgrade() throws Exception {
155180

156181
List<String> cmdArgs = asList("--rolling-upgrade", "enable", targetVerStr);
157182

158-
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, execute(enrichWithConnectionArguments(cmdArgs, TEST_NO_PERMISSIONS_LOGIN)));
183+
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, executeOnBehalf(cmdArgs, TEST_NO_PERMISSIONS_LOGIN));
159184

160185
assertFalse(ign.context().rollingUpgrade().enabled());
161186

162-
assertEquals(EXIT_CODE_OK, execute(enrichWithConnectionArguments(cmdArgs, TEST_LOGIN)));
187+
assertEquals(EXIT_CODE_OK, executeOnBehalf(cmdArgs, TEST_LOGIN));
163188

164189
assertTrue(ign.context().rollingUpgrade().enabled());
165190
assertEquals(IgniteProductVersion.fromString(targetVerStr), ign.context().rollingUpgrade().versions().get2());
166191

167192
cmdArgs = asList("--rolling-upgrade", "disable");
168193

169-
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, execute(enrichWithConnectionArguments(cmdArgs, TEST_NO_PERMISSIONS_LOGIN)));
194+
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, executeOnBehalf(cmdArgs, TEST_NO_PERMISSIONS_LOGIN));
170195

171196
assertTrue(ign.context().rollingUpgrade().enabled());
172197

173-
assertEquals(EXIT_CODE_OK, execute(enrichWithConnectionArguments(cmdArgs, TEST_LOGIN)));
198+
assertEquals(EXIT_CODE_OK, executeOnBehalf(cmdArgs, TEST_LOGIN));
174199

175200
assertFalse(ign.context().rollingUpgrade().enabled());
176201
}
@@ -198,15 +223,66 @@ public void testServiceCancel() throws Exception {
198223

199224
Collection<ServiceDescriptor> svcs = ignite.services().serviceDescriptors();
200225

201-
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, execute(enrichWithConnectionArguments(cmdArgs, TEST_NO_PERMISSIONS_LOGIN)));
226+
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, executeOnBehalf(cmdArgs, TEST_NO_PERMISSIONS_LOGIN));
202227
assertEquals(1, svcs.size());
203228

204-
assertEquals(EXIT_CODE_OK, execute(enrichWithConnectionArguments(cmdArgs, TEST_LOGIN)));
229+
assertEquals(EXIT_CODE_OK, executeOnBehalf(cmdArgs, TEST_LOGIN));
205230

206231
svcs = ignite.services().serviceDescriptors();
207232
assertEquals(0, svcs.size());
208233
}
209234

235+
/** */
236+
@Test
237+
public void testTaskCancel() throws Exception {
238+
IgniteEx ignite = startGrid(
239+
0,
240+
userData(TEST_NO_PERMISSIONS_LOGIN, NO_PERMISSIONS),
241+
userData(TEST_LOGIN, SecurityPermissionSetBuilder.create()
242+
.defaultAllowAll(false)
243+
.appendTaskPermissions(TestTask.class.getName(), TASK_CANCEL)
244+
.build())
245+
);
246+
247+
ComputeTaskFuture<ComputeJobResult> fut = ignite.compute().executeAsync(new TestTask(), null);
248+
249+
GridSystemViewManager viewMgr = ignite.context().systemView();
250+
251+
assertTrue(waitForCondition(() -> viewMgr.view(TASKS_VIEW).size() >= 1, getTestTimeout()));
252+
assertTrue(waitForCondition(() -> viewMgr.view(JOBS_VIEW).size() >= 1, getTestTimeout()));
253+
254+
Iterator<ComputeTaskView> iter = viewMgr.<ComputeTaskView>view(TASKS_VIEW).iterator();
255+
256+
String sesId = iter.next().sessionId().toString();
257+
258+
assertFalse(iter.hasNext());
259+
260+
Collection<String> cmdArgs = asList("--kill", "compute", sesId);
261+
262+
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, executeOnBehalf(cmdArgs, TEST_NO_PERMISSIONS_LOGIN));
263+
264+
assertFalse(fut.isDone());
265+
266+
assertEquals(0, TestJob.CANCELLED_JOB_CNT.get());
267+
268+
assertTrue(waitForCondition(() -> viewMgr.view(TASKS_VIEW).size() >= 1, getTestTimeout()));
269+
assertTrue(waitForCondition(() -> viewMgr.view(JOBS_VIEW).size() >= 1, getTestTimeout()));
270+
271+
assertEquals(EXIT_CODE_OK, executeOnBehalf(cmdArgs, TEST_LOGIN));
272+
273+
try {
274+
assertTrue(fut.get(getTestTimeout(), MILLISECONDS).isCancelled());
275+
}
276+
catch (Exception e) {
277+
assertTrue(X.hasCause(e, IgniteFutureCancelledException.class));
278+
}
279+
280+
assertTrue(waitForCondition(() -> viewMgr.view(TASKS_VIEW).size() == 0, getTestTimeout()));
281+
assertTrue(waitForCondition(() -> viewMgr.view(JOBS_VIEW).size() == 0, getTestTimeout()));
282+
283+
assertEquals(1, TestJob.CANCELLED_JOB_CNT.get());
284+
}
285+
210286
/** */
211287
protected IgniteEx startGrid(int idx, TestSecurityData... userData) throws Exception {
212288
String login = getTestIgniteInstanceName(idx);
@@ -228,13 +304,13 @@ private void checkCommandPermissions(Collection<String> cmdArgs, SecurityPermiss
228304

229305
ignite.createCache(DEFAULT_CACHE_NAME);
230306

231-
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, execute(enrichWithConnectionArguments(cmdArgs, TEST_NO_PERMISSIONS_LOGIN)));
307+
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, executeOnBehalf(cmdArgs, TEST_NO_PERMISSIONS_LOGIN));
232308

233-
// We are losing command failure cause for --cache clear commnad. See IGNITE-21023 for more details.
309+
// We are losing command failure cause for --cache clear command. See IGNITE-21023 for more details.
234310
if (!cmdArgs.containsAll(Arrays.asList("--cache", "clear")))
235311
assertTrue(testOut.toString().contains("Authorization failed"));
236312

237-
assertEquals(EXIT_CODE_OK, execute(enrichWithConnectionArguments(cmdArgs, TEST_LOGIN)));
313+
assertEquals(EXIT_CODE_OK, executeOnBehalf(cmdArgs, TEST_LOGIN));
238314
}
239315

240316
/** */
@@ -276,4 +352,55 @@ private TestSecurityData userData(String login, SecurityPermissionSet perms) {
276352
new Permissions()
277353
);
278354
}
355+
356+
/** */
357+
private int executeOnBehalf(Collection<String> cmdArgs, String login) {
358+
return execute(enrichWithConnectionArguments(cmdArgs, login));
359+
}
360+
361+
/** */
362+
private static class TestTask extends ComputeTaskAdapter<Object, ComputeJobResult> {
363+
/** {@inheritDoc} */
364+
@Override public @NotNull Map<? extends ComputeJob, ClusterNode> map(
365+
List<ClusterNode> subgrid,
366+
@Nullable Object arg
367+
) throws IgniteException {
368+
return subgrid.stream().filter(g -> !g.isClient()).collect(Collectors.toMap(ignored -> new TestJob(), srv -> srv));
369+
}
370+
371+
/** {@inheritDoc} */
372+
@Override public @Nullable ComputeJobResult reduce(List<ComputeJobResult> results) throws IgniteException {
373+
assertTrue(results.size() == 1);
374+
375+
return results.get(0);
376+
}
377+
}
378+
379+
/** */
380+
private static class TestJob implements ComputeJob {
381+
/** */
382+
private final CountDownLatch jobBlockedLatch = new CountDownLatch(1);
383+
384+
/** */
385+
private static final AtomicInteger CANCELLED_JOB_CNT = new AtomicInteger();
386+
387+
/** {@inheritDoc} */
388+
@Override public void cancel() {
389+
jobBlockedLatch.countDown();
390+
391+
CANCELLED_JOB_CNT.incrementAndGet();
392+
}
393+
394+
/** {@inheritDoc} */
395+
@Override public Object execute() throws IgniteException {
396+
try {
397+
assertTrue(jobBlockedLatch.await(5_000, MILLISECONDS));
398+
}
399+
catch (InterruptedException e) {
400+
throw new IgniteException(e);
401+
}
402+
403+
return null;
404+
}
405+
}
279406
}

modules/core/src/main/java/org/apache/ignite/internal/ComputeMXBeanImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public ComputeMXBeanImpl(GridKernalContext ctx) {
5252
}
5353

5454
/**
55-
* Kills compute task by the session idenitifier.
55+
* Kills compute task by the session identifier.
5656
*
5757
* @param sesId Session id.
5858
*/

modules/core/src/main/java/org/apache/ignite/internal/management/kill/ComputeCancelSessionTask.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717

1818
package org.apache.ignite.internal.management.kill;
1919

20-
import java.util.List;
21-
import org.apache.ignite.compute.ComputeJobResult;
2220
import org.apache.ignite.internal.ComputeMXBeanImpl;
2321
import org.apache.ignite.internal.processors.task.GridInternal;
2422
import org.apache.ignite.internal.util.typedef.internal.S;
2523
import org.apache.ignite.internal.visor.VisorJob;
2624
import org.apache.ignite.internal.visor.VisorOneNodeTask;
27-
import org.jetbrains.annotations.Nullable;
25+
import org.apache.ignite.plugin.security.SecurityPermissionSet;
26+
27+
import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.NO_PERMISSIONS;
2828

2929
/**
3030
* Cancels given tasks sessions on all cluster nodes.
@@ -39,12 +39,6 @@ public class ComputeCancelSessionTask extends VisorOneNodeTask<KillComputeComman
3939
return new ComputeCancelSessionJob(arg, debug);
4040
}
4141

42-
/** {@inheritDoc} */
43-
@Nullable @Override protected Void reduce0(List<ComputeJobResult> results) {
44-
// No-op, just awaiting all jobs done.
45-
return null;
46-
}
47-
4842
/**
4943
* Job that cancel tasks.
5044
*/
@@ -67,6 +61,11 @@ private ComputeCancelSessionJob(KillComputeCommandArg arg, boolean debug) {
6761
return null;
6862
}
6963

64+
/** {@inheritDoc} */
65+
@Override public SecurityPermissionSet requiredPermissions() {
66+
return NO_PERMISSIONS;
67+
}
68+
7069
/** {@inheritDoc} */
7170
@Override public String toString() {
7271
return S.toString(ComputeCancelSessionJob.class, this);

0 commit comments

Comments
 (0)