From ab5bd7224c721cf54b93926798f75afacb120953 Mon Sep 17 00:00:00 2001 From: Aleksey Plekhanov Date: Fri, 13 Mar 2026 17:19:05 +0300 Subject: [PATCH] IGNITE-28219 Control utility: Add events control commands --- docs/_docs/events/listening-to-events.adoc | 2 + docs/_docs/tools/control-script.adoc | 15 ++ .../IgniteControlUtilityTestSuite2.java | 3 + .../util/GridCommandHandlerEventTest.java | 184 ++++++++++++++++++ .../management/IgniteCommandRegistry.java | 4 +- .../management/event/EventCommand.java | 33 ++++ .../management/event/EventCommandArg.java | 47 +++++ .../management/event/EventDisableCommand.java | 57 ++++++ .../management/event/EventEnableCommand.java | 57 ++++++ .../event/EventEnableDisableTask.java | 109 +++++++++++ .../management/event/EventListCommand.java | 50 +++++ .../management/event/EventListTask.java | 60 ++++++ .../management/event/EventStatusCommand.java | 55 ++++++ .../management/event/EventStatusTask.java | 99 ++++++++++ .../ignite/internal/util/IgniteUtils.java | 9 + ...mmandHandlerClusterByClassTest_help.output | 18 ++ ...ndlerClusterByClassWithSSLTest_help.output | 18 ++ 17 files changed, 819 insertions(+), 1 deletion(-) create mode 100644 modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerEventTest.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/management/event/EventCommand.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/management/event/EventCommandArg.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/management/event/EventDisableCommand.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/management/event/EventEnableCommand.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/management/event/EventEnableDisableTask.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/management/event/EventListCommand.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/management/event/EventListTask.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/management/event/EventStatusCommand.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/management/event/EventStatusTask.java diff --git a/docs/_docs/events/listening-to-events.adoc b/docs/_docs/events/listening-to-events.adoc index ea61c35012eca..fc555e683ffc9 100644 --- a/docs/_docs/events/listening-to-events.adoc +++ b/docs/_docs/events/listening-to-events.adoc @@ -45,6 +45,8 @@ include::code-snippets/dotnet/WorkingWithEvents.cs[tag=enablingEvents,indent=0] tab:C++[unsupported] -- +Events can also be enabled/disabled in runtime by the link:tools/control-script[control utility]. + == Getting the Events Interface The events functionality is available through the events interface, which provides methods for listening to cluster events. The events interface can be obtained from an instance of `Ignite` as follows: diff --git a/docs/_docs/tools/control-script.adoc b/docs/_docs/tools/control-script.adoc index ba5c5b0924c86..43fbd37a154f8 100644 --- a/docs/_docs/tools/control-script.adoc +++ b/docs/_docs/tools/control-script.adoc @@ -1628,3 +1628,18 @@ Parameters: |--node-id | A list of nodes to rebuild indexes on. If not specified, schedules rebuild on all nodes. |--cache-names | Comma-separated list of cache names, optionally with indexes. If indexes are not specified, all indexes of the cache will be scheduled for the rebuild operation. Can be used simultaneously with cache group names. |--group-names | Comma-separated list of cache group names. Can be used simultaneously with cache names. + + +== Events subscription management + +By default, almost all link:events/events[Ignite events] are disabled (except for a few that are implicitly enabled because they are required by the system). +To use event listeners, you must explicitly enable each event type you're interested in. This can be done either statically via `IgniteConfiguration` (as described in the link:events/listening-to-events[Working with Events] section), or dynamically during runtime using the control utility. +The control utility provides commands to enable events, disable events, check the status of enabled events and get a list of supported by the Ignite events. + +[source, shell] +---- +control.sh|bat --event enable event1[,...,eventN] +control.sh|bat --event disable event1[,...,eventN] +control.sh|bat --event status +control.sh|bat --event list +---- diff --git a/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java b/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java index d7ed2b5124613..fc778e70364ff 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java @@ -28,6 +28,7 @@ import org.apache.ignite.util.GridCommandHandlerConsistencySensitiveTest; import org.apache.ignite.util.GridCommandHandlerConsistencyTest; import org.apache.ignite.util.GridCommandHandlerDefragmentationTest; +import org.apache.ignite.util.GridCommandHandlerEventTest; import org.apache.ignite.util.GridCommandHandlerIndexForceRebuildTest; import org.apache.ignite.util.GridCommandHandlerIndexListTest; import org.apache.ignite.util.GridCommandHandlerIndexRebuildStatusTest; @@ -64,6 +65,8 @@ GridCommandHandlerConsistencySensitiveTest.class, GridCommandHandlerConsistencyRepairCorrectnessAtomicTest.class, + GridCommandHandlerEventTest.class, + RollingUpgradeCommandTest.class, SystemViewCommandTest.class, MetricCommandTest.class, diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerEventTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerEventTest.java new file mode 100644 index 0000000000000..9f2280b7345aa --- /dev/null +++ b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerEventTest.java @@ -0,0 +1,184 @@ +/* + * 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.util; + +import java.security.Permissions; +import org.apache.ignite.Ignite; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.events.EventType; +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.G; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.junit.Test; + +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.commandline.SecurityCommandHandlerPermissionsTest.DEFAULT_PWD; +import static org.apache.ignite.internal.commandline.SecurityCommandHandlerPermissionsTest.TEST_NO_PERMISSIONS_LOGIN; +import static org.apache.ignite.internal.commandline.SecurityCommandHandlerPermissionsTest.enrichWithConnectionArguments; +import static org.apache.ignite.plugin.security.SecurityPermission.ADMIN_OPS; +import static org.apache.ignite.plugin.security.SecurityPermission.EVENTS_DISABLE; +import static org.apache.ignite.plugin.security.SecurityPermission.EVENTS_ENABLE; +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.junit.Assume.assumeTrue; + +/** */ +public class GridCommandHandlerEventTest extends GridCommandHandlerAbstractTest { + /** */ + private static final String LOGIN_EVT_ENABLE = "test_login_evt_enable"; + + /** */ + private static final String LOGIN_EVT_DISABLE = "test_login_evt_disable"; + + /** */ + private static final String LOGIN_EVT_STATUS = "test_login_evt_status"; + + /** */ + @Override protected void afterTest() throws Exception { + super.afterTest(); + + stopAllGrids(); + } + + /** */ + @Test + public void testEventEnableDIsable() throws Exception { + startGrids(2); + startClientGrid("client"); + + assertEvents(false, EventType.EVT_CACHE_STARTED, EventType.EVT_CACHE_STOPPED); + + assertEquals(EXIT_CODE_OK, execute("--event", "enable", "EVT_CACHE_STARTED,EVT_CACHE_STOPPED")); + + assertEvents(true, EventType.EVT_CACHE_STARTED, EventType.EVT_CACHE_STOPPED); + + injectTestSystemOut(); + + assertEquals(EXIT_CODE_OK, execute("--event", "status")); + + String out = testOut.toString(); + + assertTrue(out.contains("EVT_CACHE_STARTED")); + assertTrue(out.contains("EVT_CACHE_STOPPED")); + + assertEquals(EXIT_CODE_OK, execute("--event", "disable", "EVT_CACHE_STARTED,EVT_CACHE_STOPPED")); + + assertEvents(false, EventType.EVT_CACHE_STARTED, EventType.EVT_CACHE_STOPPED); + } + + /** */ + @Test + public void testDifferentSetOfEventsOnNodes() throws Exception { + startGrid(getConfiguration(getTestIgniteInstanceName(0)) + .setIncludeEventTypes(EventType.EVT_TX_STARTED, EventType.EVT_CACHE_STARTED)); + + startGrid(getConfiguration(getTestIgniteInstanceName(1)) + .setIncludeEventTypes(EventType.EVT_TX_STARTED, EventType.EVT_CACHE_STOPPED)); + + injectTestSystemOut(); + + assertEquals(EXIT_CODE_OK, execute("--event", "status")); + + String out = testOut.toString(); + + assertTrue(out.contains("EVT_TX_STARTED")); + assertTrue(out.contains("Warning: Event EVT_CACHE_STARTED is enabled only on part of nodes")); + assertTrue(out.contains("Warning: Event EVT_CACHE_STOPPED is enabled only on part of nodes")); + } + + /** */ + @Test + public void testUnknownEvent() throws Exception { + startGrids(2); + + assertEquals(EXIT_CODE_UNEXPECTED_ERROR, execute("--event", "enable", "EVT_NO_SUCH_EVENT")); + } + + /** */ + @Test + public void testEventList() throws Exception { + startGrids(2); + + injectTestSystemOut(); + + assertEquals(EXIT_CODE_OK, execute("--event", "list")); + + String out = testOut.toString(); + + for (String evt : U.gridEventNames().values()) + assertTrue(out.contains("EVT_" + evt)); + } + + /** */ + @Test + public void testEventWithSecurity() throws Exception { + assumeTrue(cliCommandHandler()); + + startGrid(getConfigurationWithSecurity(getTestIgniteInstanceName(0))); + startGrid(getConfigurationWithSecurity(getTestIgniteInstanceName(1))); + + assertExecuteWithSecurity(LOGIN_EVT_ENABLE, "--event", "enable", "EVT_CACHE_STARTED,EVT_CACHE_STOPPED"); + + assertEvents(true, EventType.EVT_CACHE_STARTED, EventType.EVT_CACHE_STOPPED); + + assertExecuteWithSecurity(LOGIN_EVT_STATUS, "--event", "status"); + + assertExecuteWithSecurity(LOGIN_EVT_DISABLE, "--event", "disable", "EVT_CACHE_STARTED,EVT_CACHE_STOPPED"); + + assertEvents(false, EventType.EVT_CACHE_STARTED, EventType.EVT_CACHE_STOPPED); + } + + /** */ + private IgniteConfiguration getConfigurationWithSecurity(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = getConfiguration(igniteInstanceName); + + cfg.setPluginProviders( + new TestSecurityPluginProvider( + igniteInstanceName, + DEFAULT_PWD, + ALL_PERMISSIONS, + false, + new TestSecurityData(TEST_NO_PERMISSIONS_LOGIN, DEFAULT_PWD, NO_PERMISSIONS, new Permissions()), + new TestSecurityData(LOGIN_EVT_ENABLE, DEFAULT_PWD, systemPermissions(EVENTS_ENABLE), new Permissions()), + new TestSecurityData(LOGIN_EVT_DISABLE, DEFAULT_PWD, systemPermissions(EVENTS_DISABLE), new Permissions()), + new TestSecurityData(LOGIN_EVT_STATUS, DEFAULT_PWD, systemPermissions(ADMIN_OPS), new Permissions())) + ); + + return cfg; + } + + /** */ + private void assertExecuteWithSecurity(String allowedLogin, String... cmdArgs) { + assertEquals(EXIT_CODE_UNEXPECTED_ERROR, execute(enrichWithConnectionArguments(F.asList(cmdArgs), + TEST_NO_PERMISSIONS_LOGIN))); + + assertEquals(EXIT_CODE_OK, execute(enrichWithConnectionArguments(F.asList(cmdArgs), allowedLogin))); + } + + /** */ + private void assertEvents(boolean enabled, int... evts) { + for (Ignite ignite : G.allGrids()) { + for (int i = 0; i < evts.length; i++) + assertEquals(enabled, ignite.events().isEnabled(evts[i])); + } + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/IgniteCommandRegistry.java b/modules/core/src/main/java/org/apache/ignite/internal/management/IgniteCommandRegistry.java index 1f28f1cfbd24c..9e6b2194ded16 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/IgniteCommandRegistry.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/IgniteCommandRegistry.java @@ -29,6 +29,7 @@ import org.apache.ignite.internal.management.defragmentation.DefragmentationCommand; import org.apache.ignite.internal.management.diagnostic.DiagnosticCommand; import org.apache.ignite.internal.management.encryption.EncryptionCommand; +import org.apache.ignite.internal.management.event.EventCommand; import org.apache.ignite.internal.management.kill.KillCommand; import org.apache.ignite.internal.management.meta.MetaCommand; import org.apache.ignite.internal.management.metric.MetricCommand; @@ -77,7 +78,8 @@ public IgniteCommandRegistry() { new DefragmentationCommand(), new PerformanceStatisticsCommand(), new CdcCommand(), - new ConsistencyCommand() + new ConsistencyCommand(), + new EventCommand() ); U.loadService(CommandsProvider.class).forEach(p -> p.commands().forEach(this::register)); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventCommand.java new file mode 100644 index 0000000000000..81ddcb5c77de1 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventCommand.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.management.event; + +import org.apache.ignite.internal.management.api.CommandRegistryImpl; + +/** Command to enable/disable events. */ +public class EventCommand extends CommandRegistryImpl { + /** */ + public EventCommand() { + super( + new EventEnableCommand(), + new EventDisableCommand(), + new EventStatusCommand(), + new EventListCommand() + ); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventCommandArg.java b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventCommandArg.java new file mode 100644 index 0000000000000..000386c0a098d --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventCommandArg.java @@ -0,0 +1,47 @@ +/* + * 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.management.event; + +import org.apache.ignite.internal.Order; +import org.apache.ignite.internal.dto.IgniteDataTransferObject; +import org.apache.ignite.internal.management.api.Argument; +import org.apache.ignite.internal.management.api.Positional; + +/** */ +public class EventCommandArg extends IgniteDataTransferObject { + /** */ + private static final long serialVersionUID = 0; + + /** */ + @Order(0) + @Positional + @Argument( + description = "Comma separated list of events", + example = "event1[,...,eventN]") + String[] events; + + /** */ + public String[] events() { + return events; + } + + /** */ + public void events(String[] events) { + this.events = events; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventDisableCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventDisableCommand.java new file mode 100644 index 0000000000000..8a8f492280122 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventDisableCommand.java @@ -0,0 +1,57 @@ +/* + * 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.management.event; + +import java.util.Collection; +import java.util.function.Consumer; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.management.api.ComputeCommand; + +/** */ +public class EventDisableCommand implements ComputeCommand { + /** {@inheritDoc} */ + @Override public String description() { + return "Disable events"; + } + + /** {@inheritDoc} */ + @Override public Class argClass() { + return EventDisableCommandArg.class; + } + + /** {@inheritDoc} */ + @Override public Class taskClass() { + return EventEnableDisableTask.class; + } + + /** {@inheritDoc} */ + @Override public Collection nodes(Collection nodes, EventCommandArg arg) { + return nodes; + } + + /** {@inheritDoc} */ + @Override public void printResult(EventCommandArg arg, String res, Consumer printer) { + printer.accept(res); + } + + /** */ + public static class EventDisableCommandArg extends EventCommandArg { + /** */ + private static final long serialVersionUID = 0; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventEnableCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventEnableCommand.java new file mode 100644 index 0000000000000..35037ef5f4368 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventEnableCommand.java @@ -0,0 +1,57 @@ +/* + * 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.management.event; + +import java.util.Collection; +import java.util.function.Consumer; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.management.api.ComputeCommand; + +/** */ +public class EventEnableCommand implements ComputeCommand { + /** {@inheritDoc} */ + @Override public String description() { + return "Enable events"; + } + + /** {@inheritDoc} */ + @Override public Class argClass() { + return EventEnableCommandArg.class; + } + + /** {@inheritDoc} */ + @Override public Class taskClass() { + return EventEnableDisableTask.class; + } + + /** {@inheritDoc} */ + @Override public Collection nodes(Collection nodes, EventCommandArg arg) { + return nodes; + } + + /** {@inheritDoc} */ + @Override public void printResult(EventCommandArg arg, String res, Consumer printer) { + printer.accept(res); + } + + /** */ + public static class EventEnableCommandArg extends EventCommandArg { + /** */ + private static final long serialVersionUID = 0; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventEnableDisableTask.java b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventEnableDisableTask.java new file mode 100644 index 0000000000000..4b9f0919fe0a2 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventEnableDisableTask.java @@ -0,0 +1,109 @@ +/* + * 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.management.event; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.ignite.IgniteException; +import org.apache.ignite.compute.ComputeJobResult; +import org.apache.ignite.internal.processors.task.GridInternal; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.internal.visor.VisorJob; +import org.apache.ignite.internal.visor.VisorMultiNodeTask; +import org.apache.ignite.plugin.security.SecurityPermissionSet; +import org.jetbrains.annotations.Nullable; + +import static org.apache.ignite.plugin.security.SecurityPermission.EVENTS_DISABLE; +import static org.apache.ignite.plugin.security.SecurityPermission.EVENTS_ENABLE; +import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.systemPermissions; + +/** + * Enable/disable events task. + */ +@GridInternal +public class EventEnableDisableTask extends VisorMultiNodeTask { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** {@inheritDoc} */ + @Override protected VisorJob job(EventCommandArg arg) { + return new EventEnableDisableJob(arg, debug); + } + + /** {@inheritDoc} */ + @Nullable @Override protected String reduce0(List results) { + for (ComputeJobResult res : results) { + if (res.getException() != null) + throw res.getException(); + } + + return results.get(0).getData(); + } + + /** The job for enable/disable events. */ + private static class EventEnableDisableJob extends VisorJob { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** + * @param arg Job argument. + * @param debug Flag indicating whether debug information should be printed into node log. + */ + protected EventEnableDisableJob(EventCommandArg arg, boolean debug) { + super(arg, debug); + } + + /** {@inheritDoc} */ + @Override protected String run(EventCommandArg arg) throws IgniteException { + Map evtToName = U.gridEventNames(); + + Map nameToEvt = evtToName.entrySet().stream() + .collect(Collectors.toMap(e -> "EVT_" + e.getValue(), Map.Entry::getKey)); + + int[] evtTypes = new int[arg.events.length]; + + for (int i = 0; i < arg.events.length; i++) { + String evtName = arg.events[i]; + + if (!nameToEvt.containsKey(evtName)) + throw new IgniteException("Failed to find event by name [evt=" + evtName + ']'); + + evtTypes[i] = nameToEvt.get(evtName); + } + + if (arg instanceof EventEnableCommand.EventEnableCommandArg) { + ignite.context().event().enableEvents(evtTypes); + + return "Events enabled"; + } + else { + ignite.context().event().disableEvents(evtTypes); + + return "Events desabled"; + } + } + + /** {@inheritDoc} */ + @Override public SecurityPermissionSet requiredPermissions() { + return systemPermissions( + argument(0) instanceof EventEnableCommand.EventEnableCommandArg ? EVENTS_ENABLE : EVENTS_DISABLE + ); + } + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventListCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventListCommand.java new file mode 100644 index 0000000000000..751d7288b25cf --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventListCommand.java @@ -0,0 +1,50 @@ +/* + * 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.management.event; + +import java.util.Collection; +import java.util.function.Consumer; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.management.api.ComputeCommand; +import org.apache.ignite.internal.management.api.NoArg; + +/** */ +public class EventListCommand implements ComputeCommand> { + /** {@inheritDoc} */ + @Override public String description() { + return "List of all supported events"; + } + + /** {@inheritDoc} */ + @Override public Class argClass() { + return NoArg.class; + } + + /** {@inheritDoc} */ + @Override public Class taskClass() { + return EventListTask.class; + } + + /** {@inheritDoc} */ + @Override public void printResult(NoArg arg, Collection res, Consumer printer) { + printer.accept("Supported events:"); + + for (String r : res) + printer.accept(r); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventListTask.java b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventListTask.java new file mode 100644 index 0000000000000..07b40977de6d0 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventListTask.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.management.event; + +import java.util.Collection; +import java.util.stream.Collectors; +import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.management.api.NoArg; +import org.apache.ignite.internal.processors.task.GridInternal; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.internal.visor.VisorJob; +import org.apache.ignite.internal.visor.VisorOneNodeTask; + +/** + * List of supported events task. + */ +@GridInternal +public class EventListTask extends VisorOneNodeTask> { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** {@inheritDoc} */ + @Override protected VisorJob> job(NoArg arg) { + return new EventListJob(arg, debug); + } + + /** The job for view all supported events. */ + private static class EventListJob extends VisorJob> { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** + * @param arg Job argument. + * @param debug Flag indicating whether debug information should be printed into node log. + */ + protected EventListJob(NoArg arg, boolean debug) { + super(arg, debug); + } + + /** {@inheritDoc} */ + @Override protected Collection run(NoArg arg) throws IgniteException { + return U.gridEventNames().values().stream().map(e -> "EVT_" + e).sorted().collect(Collectors.toList()); + } + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventStatusCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventStatusCommand.java new file mode 100644 index 0000000000000..25cf50cbe459f --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventStatusCommand.java @@ -0,0 +1,55 @@ +/* + * 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.management.event; + +import java.util.Collection; +import java.util.function.Consumer; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.management.api.ComputeCommand; +import org.apache.ignite.internal.management.api.NoArg; + +/** */ +public class EventStatusCommand implements ComputeCommand> { + /** {@inheritDoc} */ + @Override public String description() { + return "Status of enabled events"; + } + + /** {@inheritDoc} */ + @Override public Class argClass() { + return NoArg.class; + } + + /** {@inheritDoc} */ + @Override public Class taskClass() { + return EventStatusTask.class; + } + + /** {@inheritDoc} */ + @Override public Collection nodes(Collection nodes, NoArg arg) { + return nodes; + } + + /** {@inheritDoc} */ + @Override public void printResult(NoArg arg, Collection res, Consumer printer) { + printer.accept("Enabled events:"); + + for (String r : res) + printer.accept(r); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventStatusTask.java b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventStatusTask.java new file mode 100644 index 0000000000000..75301bb3cba5c --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/event/EventStatusTask.java @@ -0,0 +1,99 @@ +/* + * 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.management.event; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import org.apache.ignite.IgniteException; +import org.apache.ignite.compute.ComputeJobResult; +import org.apache.ignite.internal.management.api.NoArg; +import org.apache.ignite.internal.processors.task.GridInternal; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.internal.visor.VisorJob; +import org.apache.ignite.internal.visor.VisorMultiNodeTask; +import org.jetbrains.annotations.Nullable; + +/** + * Enabled events status task. + */ +@GridInternal +public class EventStatusTask extends VisorMultiNodeTask, Collection> { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** {@inheritDoc} */ + @Override protected VisorJob> job(NoArg arg) { + return new EventStatusJob(arg, debug); + } + + /** {@inheritDoc} */ + @Nullable @Override protected Collection reduce0(List results) { + for (ComputeJobResult res : results) { + if (res.getException() != null) + throw res.getException(); + } + + Set res = new TreeSet<>((Collection)results.get(0).getData()); + + for (int i = 1; i < results.size(); i++) { + Collection res0 = results.get(i).getData(); + + res.retainAll(res0); + } + + for (int i = 0; i < results.size(); i++) { + Collection res0 = results.get(i).getData(); + + for (String evtName : res0) { + if (!res.contains(evtName)) + res.add("Warning: Event " + evtName + " is enabled only on part of nodes"); + } + } + + return res; + } + + /** The job for view enabled events status. */ + private static class EventStatusJob extends VisorJob> { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** + * @param arg Job argument. + * @param debug Flag indicating whether debug information should be printed into node log. + */ + protected EventStatusJob(NoArg arg, boolean debug) { + super(arg, debug); + } + + /** {@inheritDoc} */ + @Override protected Collection run(NoArg arg) throws IgniteException { + int[] evts = ignite.context().event().enabledEvents(); + + Collection res = new ArrayList<>(); + + for (int i = 0; i < evts.length; i++) + res.add("EVT_" + U.gridEventName(evts[i])); + + return res; + } + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java index 41783b4d8155b..94b0aaab023b8 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java @@ -705,6 +705,15 @@ public static String gridEventName(int type) { return name != null ? name : Integer.toString(type); } + /** + * Gets known grid events with names. + * + * @return Map of event types to names. + */ + public static Map gridEventNames() { + return Collections.unmodifiableMap(GRID_EVT_NAMES); + } + /** * Gets all event types. * diff --git a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output index ade6902b3a50b..d6c4da6f3b953 100644 --- a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output +++ b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output @@ -504,6 +504,24 @@ If the file name isn't specified the output file name is: '.bin': Finalize partitions update counters: control.(sh|bat) --consistency finalize + Enable events: + control.(sh|bat) --event enable event1[,...,eventN] + + Parameters: + event1[,...,eventN] - Comma separated list of events. + + Disable events: + control.(sh|bat) --event disable event1[,...,eventN] + + Parameters: + event1[,...,eventN] - Comma separated list of events. + + Status of enabled events: + control.(sh|bat) --event status + + List of all supported events: + control.(sh|bat) --event list + By default commands affecting the cluster require interactive confirmation. Use --yes option to disable it. diff --git a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output index 834742e78ebb7..bd415c16a18c0 100644 --- a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output +++ b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output @@ -504,6 +504,24 @@ If the file name isn't specified the output file name is: '.bin': Finalize partitions update counters: control.(sh|bat) --consistency finalize + Enable events: + control.(sh|bat) --event enable event1[,...,eventN] + + Parameters: + event1[,...,eventN] - Comma separated list of events. + + Disable events: + control.(sh|bat) --event disable event1[,...,eventN] + + Parameters: + event1[,...,eventN] - Comma separated list of events. + + Status of enabled events: + control.(sh|bat) --event status + + List of all supported events: + control.(sh|bat) --event list + By default commands affecting the cluster require interactive confirmation. Use --yes option to disable it.