Skip to content

Commit 482ea22

Browse files
committed
AS7-4841 Set up periodic pings between master and slave HCs; properly handle disconnections detected by them
split up applying extensions from the rest of the model fix ping/pong mgmt headers don't sync deployment files if they exist Don't bother unregistering if the channel is already closed AS7-4841 Use separate thread pool for slave initiated management requests Promptly fail the slave registration process if the host cannot support it
1 parent 8d4712f commit 482ea22

28 files changed

+1172
-157
lines changed

deployment-repository/src/main/java/org/jboss/as/repository/RemoteFileRequestAndHandler.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.io.OutputStream;
3434
import java.util.ArrayList;
3535
import java.util.List;
36+
import java.util.concurrent.Executor;
3637

3738
import org.jboss.as.protocol.StreamUtils;
3839
import org.jboss.as.protocol.mgmt.ActiveOperation;
@@ -51,9 +52,15 @@
5152
public abstract class RemoteFileRequestAndHandler {
5253

5354
private final RemoteFileProtocolIdMapper protocol;
55+
private final Executor asyncExecutor;
5456

5557
protected RemoteFileRequestAndHandler(RemoteFileProtocolIdMapper protocol) {
58+
this(protocol, null);
59+
}
60+
61+
protected RemoteFileRequestAndHandler(RemoteFileProtocolIdMapper protocol, Executor asyncExecutor) {
5662
this.protocol = protocol;
63+
this.asyncExecutor = asyncExecutor;
5764
}
5865

5966
public void sendRequest(FlushableDataOutput output, byte rootId, String filePath) throws IOException{
@@ -124,7 +131,7 @@ public void handleRequest(final DataInput input, final RootFileReader reader, fi
124131
expectHeader(input, protocol.paramFilePath());
125132
final String filePath = input.readUTF();
126133

127-
context.executeAsync(new ManagementRequestContext.AsyncTask<Void>() {
134+
ManagementRequestContext.AsyncTask<Void> task = new ManagementRequestContext.AsyncTask<Void>() {
128135
@Override
129136
public void execute(ManagementRequestContext<Void> context) throws Exception {
130137
final File localPath = reader.readRootFile(rootId, filePath);
@@ -137,7 +144,13 @@ public void execute(ManagementRequestContext<Void> context) throws Exception {
137144
StreamUtils.safeClose(output);
138145
}
139146
}
140-
});
147+
};
148+
149+
if (asyncExecutor == null) {
150+
context.executeAsync(task);
151+
} else {
152+
context.executeAsync(task, asyncExecutor);
153+
}
141154
}
142155

143156
private void writeResponse(final File localPath, final FlushableDataOutput output) throws IOException {

host-controller/src/main/java/org/jboss/as/domain/controller/DomainController.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
package org.jboss.as.domain.controller;
2424

2525
import org.jboss.as.controller.ProxyController;
26+
import org.jboss.as.controller.RunningMode;
27+
import org.jboss.as.controller.transform.Transformers;
28+
import org.jboss.as.protocol.mgmt.ManagementChannelHandler;
2629
import org.jboss.as.repository.HostFileRepository;
2730
import org.jboss.dmr.ModelNode;
2831
import org.jboss.msc.service.ServiceName;
@@ -40,6 +43,13 @@ public interface DomainController {
4043
*/
4144
ServiceName SERVICE_NAME = ServiceName.JBOSS.append("domain", "controller");
4245

46+
/**
47+
* Gets the domain controller's current running mode.
48+
*
49+
* @return the running mode
50+
*/
51+
RunningMode getCurrentRunningMode();
52+
4353
/**
4454
* Gets the local host controller info.
4555
*
@@ -48,16 +58,16 @@ public interface DomainController {
4858
LocalHostControllerInfo getLocalHostInfo();
4959

5060
/**
51-
* Registers a Host Controller with this domain controller.
61+
* Registers a slave Host Controller with this domain controller.
5262
*
53-
* @param hostControllerClient client the domain controller can use to communicate with the Host Controller.
5463
*
55-
* @throws IllegalArgumentException if there already exists a host controller with the same id as
56-
* <code>hostControllerClient</code>
57-
*
58-
* @throws SlaveRegistrationException if there is a problem registering the host
64+
* @param hostName the name of the slave host
65+
* @param handler handler for communications with the host
66+
* @param transformers transformation handler for converting resources and operations to forms appropriate for the slave
67+
* @param remoteConnectionId long identifying this specific connection to the host, or {@code null} if the host did not provide such an id
68+
* @throws SlaveRegistrationException if there is a problem registering the host
5969
*/
60-
void registerRemoteHost(final ProxyController hostControllerClient) throws SlaveRegistrationException;
70+
void registerRemoteHost(final String hostName, final ManagementChannelHandler handler, final Transformers transformers, Long remoteConnectionId) throws SlaveRegistrationException;
6171

6272
/**
6373
* Check if a Host Controller is already registered with this domain controller.
@@ -72,8 +82,18 @@ public interface DomainController {
7282
*
7383
* @param id the name of the previously
7484
* registered Host Controller
85+
* @param remoteConnectionId long identifying the specific connection to the host, or {@code null}. If {@code null}
86+
* the host's registration will be removed regardless of any remote connection id
87+
* that was provided at registration. If not {@code null}, the registration will only
88+
* be removed if the currently registered id matches the given id
89+
*/
90+
void unregisterRemoteHost(final String id, Long remoteConnectionId);
91+
92+
/**
93+
* Asynchronously ping the slave host with the given {@code hostName} to validate its connection.
94+
* @param hostName the name of the slave host
7595
*/
76-
void unregisterRemoteHost(final String id);
96+
void pingRemoteHost(String hostName);
7797

7898
/**
7999
* Registers a running server in the domain model

host-controller/src/main/java/org/jboss/as/domain/controller/DomainControllerMessages.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@
3333
import org.jboss.as.controller.PathAddress;
3434
import org.jboss.as.controller.RunningMode;
3535
import org.jboss.dmr.ModelNode;
36+
import org.jboss.logging.Cause;
3637
import org.jboss.logging.Message;
3738
import org.jboss.logging.MessageBundle;
3839
import org.jboss.logging.Messages;
40+
import org.jboss.modules.ModuleLoadException;
3941

4042
/**
4143
* This module is using message IDs in the range 10800-10899. This file is using the subset 10830-10899 for domain
@@ -546,4 +548,8 @@ public interface DomainControllerMessages {
546548
*/
547549
@Message(id = 10876, value = "No deployment content with hash %s is available in the deployment content repository for deployment '%s'. This is a fatal boot error. To correct the problem, either restart with the --admin-only switch set and use the CLI to install the missing content or remove it from the configuration, or remove the deployment from the xml configuraiton file and restart.")
548550
String noDeploymentContentWithHashAtBoot(String contentHash, String deploymentName);
551+
552+
@Message(id = 10877, value = "Failed to load module '%s'.")
553+
OperationFailedException failedToLoadModule(@Cause ModuleLoadException e,String module);
554+
549555
}

host-controller/src/main/java/org/jboss/as/domain/controller/DomainModelUtil.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
import org.jboss.as.controller.transform.SubsystemDescriptionDump;
9898
import org.jboss.as.domain.controller.descriptions.DomainDescriptionProviders;
9999
import org.jboss.as.domain.controller.descriptions.DomainRootDescription;
100+
import org.jboss.as.domain.controller.operations.ApplyExtensionsHandler;
100101
import org.jboss.as.domain.controller.operations.ApplyRemoteMasterDomainModelHandler;
101102
import org.jboss.as.domain.controller.operations.DomainServerLifecycleHandlers;
102103
import org.jboss.as.domain.controller.operations.LocalHostNameOperationHandler;
@@ -322,7 +323,10 @@ public void validateParameter(String parameterName, ModelNode value) throws Oper
322323
extensionRegistry.setSubsystemParentResourceRegistrations(profile, null);
323324

324325
if(!isMaster) {
325-
ApplyRemoteMasterDomainModelHandler armdmh = new ApplyRemoteMasterDomainModelHandler(extensionRegistry, fileRepository,
326+
final ApplyExtensionsHandler aexh = new ApplyExtensionsHandler(extensionRegistry, hostControllerInfo, ignoredDomainResourceRegistry);
327+
root.registerOperationHandler(ApplyExtensionsHandler.OPERATION_NAME, aexh, aexh, false, EntryType.PRIVATE);
328+
329+
ApplyRemoteMasterDomainModelHandler armdmh = new ApplyRemoteMasterDomainModelHandler(fileRepository,
326330
contentRepo, hostControllerInfo, ignoredDomainResourceRegistry);
327331
root.registerOperationHandler(ApplyRemoteMasterDomainModelHandler.OPERATION_NAME, armdmh, armdmh, false, OperationEntry.EntryType.PRIVATE);
328332
} else {
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* JBoss, Home of Professional Open Source.
3+
* Copyright 2012, Red Hat, Inc., and individual contributors
4+
* as indicated by the @author tags. See the copyright.txt file in the
5+
* distribution for a full listing of individual contributors.
6+
*
7+
* This is free software; you can redistribute it and/or modify it
8+
* under the terms of the GNU Lesser General Public License as
9+
* published by the Free Software Foundation; either version 2.1 of
10+
* the License, or (at your option) any later version.
11+
*
12+
* This software is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this software; if not, write to the Free
19+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21+
*/
22+
23+
package org.jboss.as.domain.controller.operations;
24+
25+
import org.jboss.as.controller.Extension;
26+
import org.jboss.as.controller.OperationContext;
27+
import org.jboss.as.controller.OperationFailedException;
28+
import org.jboss.as.controller.OperationStepHandler;
29+
import org.jboss.as.controller.PathAddress;
30+
import org.jboss.as.controller.PathElement;
31+
import org.jboss.as.controller.ProxyController;
32+
import org.jboss.as.controller.descriptions.DescriptionProvider;
33+
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DOMAIN_MODEL;
34+
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.EXTENSION;
35+
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HOST;
36+
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
37+
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
38+
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER;
39+
import org.jboss.as.controller.extension.ExtensionRegistry;
40+
import org.jboss.as.controller.extension.ExtensionResource;
41+
import org.jboss.as.controller.registry.Resource;
42+
import static org.jboss.as.domain.controller.DomainControllerLogger.ROOT_LOGGER;
43+
import org.jboss.as.domain.controller.DomainControllerMessages;
44+
import org.jboss.as.domain.controller.LocalHostControllerInfo;
45+
import org.jboss.as.domain.controller.ServerIdentity;
46+
import org.jboss.as.domain.controller.operations.coordination.DomainServerUtils;
47+
import org.jboss.as.host.controller.ignored.IgnoredDomainResourceRegistry;
48+
import org.jboss.as.server.operations.ServerRestartRequiredHandler;
49+
import org.jboss.dmr.ModelNode;
50+
import org.jboss.modules.Module;
51+
import org.jboss.modules.ModuleIdentifier;
52+
import org.jboss.modules.ModuleLoadException;
53+
54+
import java.util.HashSet;
55+
import java.util.Locale;
56+
import java.util.Map;
57+
import java.util.Set;
58+
59+
/**
60+
* Step handler responsible for adding the extensions as part of the host registration process.
61+
*
62+
* @author Emanuel Muckenhuber
63+
*/
64+
public class ApplyExtensionsHandler implements OperationStepHandler, DescriptionProvider {
65+
66+
public static final String OPERATION_NAME = "resolve-subsystems";
67+
private final Set<String> appliedExtensions = new HashSet<String>();
68+
private final ExtensionRegistry extensionRegistry;
69+
private final LocalHostControllerInfo localHostInfo;
70+
private final IgnoredDomainResourceRegistry ignoredResourceRegistry;
71+
72+
public ApplyExtensionsHandler(ExtensionRegistry extensionRegistry, LocalHostControllerInfo localHostInfo, final IgnoredDomainResourceRegistry ignoredResourceRegistry) {
73+
this.extensionRegistry = extensionRegistry;
74+
this.localHostInfo = localHostInfo;
75+
this.ignoredResourceRegistry = ignoredResourceRegistry;
76+
}
77+
78+
@Override
79+
public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
80+
// We get the model as a list of resources descriptions
81+
final ModelNode domainModel = operation.get(DOMAIN_MODEL);
82+
final ModelNode startRoot = Resource.Tools.readModel(context.readResourceFromRoot(PathAddress.EMPTY_ADDRESS));
83+
84+
final Resource rootResource = context.readResourceForUpdate(PathAddress.EMPTY_ADDRESS);
85+
for(Resource.ResourceEntry entry : rootResource.getChildren(EXTENSION)) {
86+
rootResource.removeChild(entry.getPathElement());
87+
}
88+
89+
for (final ModelNode resourceDescription : domainModel.asList()) {
90+
final PathAddress resourceAddress = PathAddress.pathAddress(resourceDescription.require("domain-resource-address"));
91+
if (ignoredResourceRegistry.isResourceExcluded(resourceAddress)) {
92+
continue;
93+
}
94+
95+
final Resource resource = getResource(resourceAddress, rootResource, context);
96+
if (resourceAddress.size() == 1 && resourceAddress.getElement(0).getKey().equals(EXTENSION)) {
97+
final String module = resourceAddress.getElement(0).getValue();
98+
if (!appliedExtensions.contains(module)) {
99+
appliedExtensions.add(module);
100+
initializeExtension(module);
101+
}
102+
} else {
103+
continue;
104+
}
105+
resource.writeModel(resourceDescription.get("domain-resource-model"));
106+
}
107+
if (!context.isBooting()) {
108+
final Resource domainRootResource = context.readResourceForUpdate(PathAddress.EMPTY_ADDRESS);
109+
final ModelNode endRoot = Resource.Tools.readModel(domainRootResource);
110+
final Set<ServerIdentity> affectedServers = new HashSet<ServerIdentity>();
111+
final ModelNode hostModel = endRoot.require(HOST).asPropertyList().iterator().next().getValue();
112+
final Map<String, ProxyController> serverProxies = DomainServerUtils.getServerProxies(localHostInfo.getLocalHostName(), domainRootResource, context.getResourceRegistration());
113+
114+
final ModelNode startExtensions = startRoot.get(EXTENSION);
115+
final ModelNode finishExtensions = endRoot.get(EXTENSION);
116+
if (!startExtensions.equals(finishExtensions)) {
117+
// This affects all servers
118+
affectedServers.addAll(DomainServerUtils.getAllRunningServers(hostModel, localHostInfo.getLocalHostName(), serverProxies));
119+
}
120+
121+
if (!affectedServers.isEmpty()) {
122+
ROOT_LOGGER.domainModelChangedOnReConnect(affectedServers);
123+
final Set<ServerIdentity> runningServers = DomainServerUtils.getAllRunningServers(hostModel, localHostInfo.getLocalHostName(), serverProxies);
124+
for (ServerIdentity serverIdentity : affectedServers) {
125+
if(!runningServers.contains(serverIdentity)) {
126+
continue;
127+
}
128+
final PathAddress serverAddress = PathAddress.pathAddress(PathElement.pathElement(HOST, serverIdentity.getHostName()), PathElement.pathElement(SERVER, serverIdentity.getServerName()));
129+
final OperationStepHandler handler = context.getResourceRegistration().getOperationHandler(serverAddress, ServerRestartRequiredHandler.OPERATION_NAME);
130+
final ModelNode op = new ModelNode();
131+
op.get(OP).set(ServerRestartRequiredHandler.OPERATION_NAME);
132+
op.get(OP_ADDR).set(serverAddress.toModelNode());
133+
context.addStep(op, handler, OperationContext.Stage.IMMEDIATE);
134+
}
135+
}
136+
}
137+
138+
context.completeStep();
139+
}
140+
141+
private Resource getResource(PathAddress resourceAddress, Resource rootResource, OperationContext context) {
142+
if(resourceAddress.size() == 0) {
143+
return rootResource;
144+
}
145+
Resource temp = rootResource;
146+
int idx = 0;
147+
for(PathElement element : resourceAddress) {
148+
temp = temp.getChild(element);
149+
if(temp == null) {
150+
if (idx == 0) {
151+
String type = element.getKey();
152+
if (type.equals(EXTENSION)) {
153+
// Needs a specialized resource type
154+
temp = new ExtensionResource(element.getValue(), extensionRegistry);
155+
context.addResource(resourceAddress, temp);
156+
}
157+
}
158+
if (temp == null) {
159+
temp = context.createResource(resourceAddress);
160+
}
161+
break;
162+
}
163+
idx++;
164+
}
165+
return temp;
166+
}
167+
168+
protected void initializeExtension(String module) throws OperationFailedException {
169+
try {
170+
for (final Extension extension : Module.loadServiceFromCallerModuleLoader(ModuleIdentifier.fromString(module), Extension.class)) {
171+
ClassLoader oldTccl = SecurityActions.setThreadContextClassLoader(extension.getClass());
172+
try {
173+
extension.initializeParsers(extensionRegistry.getExtensionParsingContext(module, null));
174+
extension.initialize(extensionRegistry.getExtensionContext(module));
175+
} finally {
176+
SecurityActions.setThreadContextClassLoader(oldTccl);
177+
}
178+
}
179+
} catch (ModuleLoadException e) {
180+
throw DomainControllerMessages.MESSAGES.failedToLoadModule(e, module);
181+
}
182+
}
183+
184+
@Override
185+
public ModelNode getModelDescription(Locale locale) {
186+
return new ModelNode(); // PRIVATE operation requires no description
187+
}
188+
189+
}

0 commit comments

Comments
 (0)