Skip to content

Commit f225542

Browse files
IGNITE-28219 Control utility: Add events control commands
1 parent d48adb1 commit f225542

17 files changed

Lines changed: 819 additions & 1 deletion

docs/_docs/events/listening-to-events.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ include::code-snippets/dotnet/WorkingWithEvents.cs[tag=enablingEvents,indent=0]
4545
tab:C++[unsupported]
4646
--
4747

48+
Events can also be enabled/disabled in runtime by link:tools/control-script[control-utility].
49+
4850
== Getting the Events Interface
4951

5052
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:

docs/_docs/tools/control-script.adoc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,3 +1628,18 @@ Parameters:
16281628
|--node-id | A list of nodes to rebuild indexes on. If not specified, schedules rebuild on all nodes.
16291629
|--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.
16301630
|--group-names | Comma-separated list of cache group names. Can be used simultaneously with cache names.
1631+
1632+
1633+
== Events subscription management
1634+
1635+
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).
1636+
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.
1637+
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.
1638+
1639+
[source, shell]
1640+
----
1641+
control.sh|bat --event enable event1[,...,eventN]
1642+
control.sh|bat --event disable event1[,...,eventN]
1643+
control.sh|bat --event status
1644+
control.sh|bat --event list
1645+
----

modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.apache.ignite.util.GridCommandHandlerConsistencySensitiveTest;
2929
import org.apache.ignite.util.GridCommandHandlerConsistencyTest;
3030
import org.apache.ignite.util.GridCommandHandlerDefragmentationTest;
31+
import org.apache.ignite.util.GridCommandHandlerEventTest;
3132
import org.apache.ignite.util.GridCommandHandlerIndexForceRebuildTest;
3233
import org.apache.ignite.util.GridCommandHandlerIndexListTest;
3334
import org.apache.ignite.util.GridCommandHandlerIndexRebuildStatusTest;
@@ -64,6 +65,8 @@
6465
GridCommandHandlerConsistencySensitiveTest.class,
6566
GridCommandHandlerConsistencyRepairCorrectnessAtomicTest.class,
6667

68+
GridCommandHandlerEventTest.class,
69+
6770
RollingUpgradeCommandTest.class,
6871
SystemViewCommandTest.class,
6972
MetricCommandTest.class,
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.ignite.util;
19+
20+
import java.security.Permissions;
21+
import org.apache.ignite.Ignite;
22+
import org.apache.ignite.configuration.IgniteConfiguration;
23+
import org.apache.ignite.events.EventType;
24+
import org.apache.ignite.internal.processors.security.impl.TestSecurityData;
25+
import org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider;
26+
import org.apache.ignite.internal.util.typedef.F;
27+
import org.apache.ignite.internal.util.typedef.G;
28+
import org.apache.ignite.internal.util.typedef.internal.U;
29+
import org.junit.Test;
30+
31+
import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
32+
import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_UNEXPECTED_ERROR;
33+
import static org.apache.ignite.internal.commandline.SecurityCommandHandlerPermissionsTest.DEFAULT_PWD;
34+
import static org.apache.ignite.internal.commandline.SecurityCommandHandlerPermissionsTest.TEST_NO_PERMISSIONS_LOGIN;
35+
import static org.apache.ignite.internal.commandline.SecurityCommandHandlerPermissionsTest.enrichWithConnectionArguments;
36+
import static org.apache.ignite.plugin.security.SecurityPermission.ADMIN_OPS;
37+
import static org.apache.ignite.plugin.security.SecurityPermission.EVENTS_DISABLE;
38+
import static org.apache.ignite.plugin.security.SecurityPermission.EVENTS_ENABLE;
39+
import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALL_PERMISSIONS;
40+
import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.NO_PERMISSIONS;
41+
import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.systemPermissions;
42+
import static org.junit.Assume.assumeTrue;
43+
44+
/** */
45+
public class GridCommandHandlerEventTest extends GridCommandHandlerAbstractTest {
46+
/** */
47+
private static final String LOGIN_EVT_ENABLE = "test_login_evt_enable";
48+
49+
/** */
50+
private static final String LOGIN_EVT_DISABLE = "test_login_evt_disable";
51+
52+
/** */
53+
private static final String LOGIN_EVT_STATUS = "test_login_evt_status";
54+
55+
/** */
56+
@Override protected void afterTest() throws Exception {
57+
super.afterTest();
58+
59+
stopAllGrids();
60+
}
61+
62+
/** */
63+
@Test
64+
public void testEventEnableDIsable() throws Exception {
65+
startGrids(2);
66+
startClientGrid("client");
67+
68+
assertEvents(false, EventType.EVT_CACHE_STARTED, EventType.EVT_CACHE_STOPPED);
69+
70+
assertEquals(EXIT_CODE_OK, execute("--event", "enable", "EVT_CACHE_STARTED,EVT_CACHE_STOPPED"));
71+
72+
assertEvents(true, EventType.EVT_CACHE_STARTED, EventType.EVT_CACHE_STOPPED);
73+
74+
injectTestSystemOut();
75+
76+
assertEquals(EXIT_CODE_OK, execute("--event", "status"));
77+
78+
String out = testOut.toString();
79+
80+
assertTrue(out.contains("EVT_CACHE_STARTED"));
81+
assertTrue(out.contains("EVT_CACHE_STOPPED"));
82+
83+
assertEquals(EXIT_CODE_OK, execute("--event", "disable", "EVT_CACHE_STARTED,EVT_CACHE_STOPPED"));
84+
85+
assertEvents(false, EventType.EVT_CACHE_STARTED, EventType.EVT_CACHE_STOPPED);
86+
}
87+
88+
/** */
89+
@Test
90+
public void testDifferentSetOfEventsOnNodes() throws Exception {
91+
startGrid(getConfiguration(getTestIgniteInstanceName(0))
92+
.setIncludeEventTypes(EventType.EVT_TX_STARTED, EventType.EVT_CACHE_STARTED));
93+
94+
startGrid(getConfiguration(getTestIgniteInstanceName(1))
95+
.setIncludeEventTypes(EventType.EVT_TX_STARTED, EventType.EVT_CACHE_STOPPED));
96+
97+
injectTestSystemOut();
98+
99+
assertEquals(EXIT_CODE_OK, execute("--event", "status"));
100+
101+
String out = testOut.toString();
102+
103+
assertTrue(out.contains("EVT_TX_STARTED"));
104+
assertTrue(out.contains("Warning: Event EVT_CACHE_STARTED is enabled only on part of nodes"));
105+
assertTrue(out.contains("Warning: Event EVT_CACHE_STOPPED is enabled only on part of nodes"));
106+
}
107+
108+
/** */
109+
@Test
110+
public void testUnknownEvent() throws Exception {
111+
startGrids(2);
112+
113+
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, execute("--event", "enable", "EVT_NO_SUCH_EVENT"));
114+
}
115+
116+
/** */
117+
@Test
118+
public void testEventList() throws Exception {
119+
startGrids(2);
120+
121+
injectTestSystemOut();
122+
123+
assertEquals(EXIT_CODE_OK, execute("--event", "list"));
124+
125+
String out = testOut.toString();
126+
127+
for (String evt : U.gridEventNames().values())
128+
assertTrue(out.contains("EVT_" + evt));
129+
}
130+
131+
/** */
132+
@Test
133+
public void testEventWithSecurity() throws Exception {
134+
assumeTrue(cliCommandHandler());
135+
136+
startGrid(getConfigurationWithSecurity(getTestIgniteInstanceName(0)));
137+
startGrid(getConfigurationWithSecurity(getTestIgniteInstanceName(1)));
138+
139+
assertExecuteWithSecurity(LOGIN_EVT_ENABLE, "--event", "enable", "EVT_CACHE_STARTED,EVT_CACHE_STOPPED");
140+
141+
assertEvents(true, EventType.EVT_CACHE_STARTED, EventType.EVT_CACHE_STOPPED);
142+
143+
assertExecuteWithSecurity(LOGIN_EVT_STATUS, "--event", "status");
144+
145+
assertExecuteWithSecurity(LOGIN_EVT_DISABLE, "--event", "disable", "EVT_CACHE_STARTED,EVT_CACHE_STOPPED");
146+
147+
assertEvents(false, EventType.EVT_CACHE_STARTED, EventType.EVT_CACHE_STOPPED);
148+
}
149+
150+
/** */
151+
private IgniteConfiguration getConfigurationWithSecurity(String igniteInstanceName) throws Exception {
152+
IgniteConfiguration cfg = getConfiguration(igniteInstanceName);
153+
154+
cfg.setPluginProviders(
155+
new TestSecurityPluginProvider(
156+
igniteInstanceName,
157+
DEFAULT_PWD,
158+
ALL_PERMISSIONS,
159+
false,
160+
new TestSecurityData(TEST_NO_PERMISSIONS_LOGIN, DEFAULT_PWD, NO_PERMISSIONS, new Permissions()),
161+
new TestSecurityData(LOGIN_EVT_ENABLE, DEFAULT_PWD, systemPermissions(EVENTS_ENABLE), new Permissions()),
162+
new TestSecurityData(LOGIN_EVT_DISABLE, DEFAULT_PWD, systemPermissions(EVENTS_DISABLE), new Permissions()),
163+
new TestSecurityData(LOGIN_EVT_STATUS, DEFAULT_PWD, systemPermissions(ADMIN_OPS), new Permissions()))
164+
);
165+
166+
return cfg;
167+
}
168+
169+
/** */
170+
private void assertExecuteWithSecurity(String allowedLogin, String... cmdArgs) {
171+
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, execute(enrichWithConnectionArguments(F.asList(cmdArgs),
172+
TEST_NO_PERMISSIONS_LOGIN)));
173+
174+
assertEquals(EXIT_CODE_OK, execute(enrichWithConnectionArguments(F.asList(cmdArgs), allowedLogin)));
175+
}
176+
177+
/** */
178+
private void assertEvents(boolean enabled, int... evts) {
179+
for (Ignite ignite : G.allGrids()) {
180+
for (int i = 0; i < evts.length; i++)
181+
assertEquals(enabled, ignite.events().isEnabled(evts[i]));
182+
}
183+
}
184+
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.apache.ignite.internal.management.defragmentation.DefragmentationCommand;
3030
import org.apache.ignite.internal.management.diagnostic.DiagnosticCommand;
3131
import org.apache.ignite.internal.management.encryption.EncryptionCommand;
32+
import org.apache.ignite.internal.management.event.EventCommand;
3233
import org.apache.ignite.internal.management.kill.KillCommand;
3334
import org.apache.ignite.internal.management.meta.MetaCommand;
3435
import org.apache.ignite.internal.management.metric.MetricCommand;
@@ -77,7 +78,8 @@ public IgniteCommandRegistry() {
7778
new DefragmentationCommand(),
7879
new PerformanceStatisticsCommand(),
7980
new CdcCommand(),
80-
new ConsistencyCommand()
81+
new ConsistencyCommand(),
82+
new EventCommand()
8183
);
8284

8385
U.loadService(CommandsProvider.class).forEach(p -> p.commands().forEach(this::register));
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.ignite.internal.management.event;
19+
20+
import org.apache.ignite.internal.management.api.CommandRegistryImpl;
21+
22+
/** Command to enable/disable events. */
23+
public class EventCommand extends CommandRegistryImpl {
24+
/** */
25+
public EventCommand() {
26+
super(
27+
new EventEnableCommand(),
28+
new EventDisableCommand(),
29+
new EventStatusCommand(),
30+
new EventListCommand()
31+
);
32+
}
33+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.ignite.internal.management.event;
19+
20+
import org.apache.ignite.internal.Order;
21+
import org.apache.ignite.internal.dto.IgniteDataTransferObject;
22+
import org.apache.ignite.internal.management.api.Argument;
23+
import org.apache.ignite.internal.management.api.Positional;
24+
25+
/** */
26+
public class EventCommandArg extends IgniteDataTransferObject {
27+
/** */
28+
private static final long serialVersionUID = 0;
29+
30+
/** */
31+
@Order(0)
32+
@Positional
33+
@Argument(
34+
description = "Comma separated list of events",
35+
example = "event1[,...,eventN]")
36+
String[] events;
37+
38+
/** */
39+
public String[] events() {
40+
return events;
41+
}
42+
43+
/** */
44+
public void events(String[] events) {
45+
this.events = events;
46+
}
47+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.ignite.internal.management.event;
19+
20+
import java.util.Collection;
21+
import java.util.function.Consumer;
22+
import org.apache.ignite.cluster.ClusterNode;
23+
import org.apache.ignite.internal.management.api.ComputeCommand;
24+
25+
/** */
26+
public class EventDisableCommand implements ComputeCommand<EventCommandArg, String> {
27+
/** {@inheritDoc} */
28+
@Override public String description() {
29+
return "Disable events";
30+
}
31+
32+
/** {@inheritDoc} */
33+
@Override public Class<EventDisableCommandArg> argClass() {
34+
return EventDisableCommandArg.class;
35+
}
36+
37+
/** {@inheritDoc} */
38+
@Override public Class<EventEnableDisableTask> taskClass() {
39+
return EventEnableDisableTask.class;
40+
}
41+
42+
/** {@inheritDoc} */
43+
@Override public Collection<ClusterNode> nodes(Collection<ClusterNode> nodes, EventCommandArg arg) {
44+
return nodes;
45+
}
46+
47+
/** {@inheritDoc} */
48+
@Override public void printResult(EventCommandArg arg, String res, Consumer<String> printer) {
49+
printer.accept(res);
50+
}
51+
52+
/** */
53+
public static class EventDisableCommandArg extends EventCommandArg {
54+
/** */
55+
private static final long serialVersionUID = 0;
56+
}
57+
}

0 commit comments

Comments
 (0)