/** * Creates the service that acts as the {@link org.jboss.as.controller.ModelController} for a Host * Controller process. * * @author Brian Stansberry (c) 2011 Red Hat Inc. */ public class DomainModelControllerService extends AbstractControllerService implements DomainController, HostModelUtil.HostModelRegistrar { public static final ServiceName SERVICE_NAME = HostControllerService.HC_SERVICE_NAME.append("model", "controller"); private static final int PINGER_POOL_SIZE; static { int poolSize = -1; try { poolSize = Integer.parseInt( SecurityActions.getSystemProperty("jboss.as.domain.ping.pool.size", "5")); } catch (Exception e) { // TODO log } finally { PINGER_POOL_SIZE = poolSize > 0 ? poolSize : 5; } } private volatile HostControllerConfigurationPersister hostControllerConfigurationPersister; private final HostControllerEnvironment environment; private final HostRunningModeControl runningModeControl; private final LocalHostControllerInfoImpl hostControllerInfo; private final HostFileRepository localFileRepository; private final RemoteFileRepository remoteFileRepository; private final InjectedValue<ProcessControllerConnectionService> injectedProcessControllerConnection = new InjectedValue<ProcessControllerConnectionService>(); private final ConcurrentMap<String, ProxyController> hostProxies; private final ConcurrentMap<String, HostRegistration> hostRegistrationMap = new ConcurrentHashMap<String, HostRegistration>(); private final Map<String, ProxyController> serverProxies; private final PrepareStepHandler prepareStepHandler; private final BootstrapListener bootstrapListener; private ManagementResourceRegistration modelNodeRegistration; private final AbstractVaultReader vaultReader; private final ContentRepository contentRepository; private final ExtensionRegistry extensionRegistry; private final ControlledProcessState processState; private final IgnoredDomainResourceRegistry ignoredRegistry; private final PathManagerService pathManager; private final ExpressionResolver expressionResolver; private final DelegatingResourceDefinition rootResourceDefinition; private final DomainControllerRuntimeIgnoreTransformationRegistry runtimeIgnoreTransformationRegistry; private volatile ServerInventory serverInventory; // TODO look into using the controller executor private volatile ExecutorService proxyExecutor; private volatile ScheduledExecutorService pingScheduler; static ServiceController<ModelController> addService( final ServiceTarget serviceTarget, final HostControllerEnvironment environment, final HostRunningModeControl runningModeControl, final ControlledProcessState processState, final BootstrapListener bootstrapListener, final PathManagerService pathManager) { final ConcurrentMap<String, ProxyController> hostProxies = new ConcurrentHashMap<String, ProxyController>(); final Map<String, ProxyController> serverProxies = new ConcurrentHashMap<String, ProxyController>(); final LocalHostControllerInfoImpl hostControllerInfo = new LocalHostControllerInfoImpl(processState, environment); final AbstractVaultReader vaultReader = service(AbstractVaultReader.class); ROOT_LOGGER.debugf("Using VaultReader %s", vaultReader); final ContentRepository contentRepository = ContentRepository.Factory.create(environment.getDomainContentDir()); final IgnoredDomainResourceRegistry ignoredRegistry = new IgnoredDomainResourceRegistry(hostControllerInfo); final ExtensionRegistry extensionRegistry = new ExtensionRegistry(ProcessType.HOST_CONTROLLER, runningModeControl); final DomainControllerRuntimeIgnoreTransformationRegistry runtimeIgnoreTransformationRegistry = new DomainControllerRuntimeIgnoreTransformationRegistry(); final PrepareStepHandler prepareStepHandler = new PrepareStepHandler( hostControllerInfo, contentRepository, hostProxies, serverProxies, ignoredRegistry, extensionRegistry, runtimeIgnoreTransformationRegistry); final ExpressionResolver expressionResolver = new RuntimeExpressionResolver(vaultReader); DomainModelControllerService service = new DomainModelControllerService( environment, runningModeControl, processState, hostControllerInfo, contentRepository, hostProxies, serverProxies, prepareStepHandler, vaultReader, ignoredRegistry, bootstrapListener, pathManager, expressionResolver, new DelegatingResourceDefinition(), extensionRegistry, runtimeIgnoreTransformationRegistry); ApplyMissingDomainModelResourcesHandler applyMissingDomainModelResourcesHandler = new ApplyMissingDomainModelResourcesHandler( service, environment, hostControllerInfo, ignoredRegistry); prepareStepHandler.initialize(applyMissingDomainModelResourcesHandler); return serviceTarget .addService(SERVICE_NAME, service) .addDependency( HostControllerService.HC_EXECUTOR_SERVICE_NAME, ExecutorService.class, service.getExecutorServiceInjector()) .addDependency( ProcessControllerConnectionService.SERVICE_NAME, ProcessControllerConnectionService.class, service.injectedProcessControllerConnection) .addDependency(PathManagerService.SERVICE_NAME) // ensure this is up .setInitialMode(ServiceController.Mode.ACTIVE) .install(); } private DomainModelControllerService( final HostControllerEnvironment environment, final HostRunningModeControl runningModeControl, final ControlledProcessState processState, final LocalHostControllerInfoImpl hostControllerInfo, final ContentRepository contentRepository, final ConcurrentMap<String, ProxyController> hostProxies, final Map<String, ProxyController> serverProxies, final PrepareStepHandler prepareStepHandler, final AbstractVaultReader vaultReader, final IgnoredDomainResourceRegistry ignoredRegistry, final BootstrapListener bootstrapListener, final PathManagerService pathManager, final ExpressionResolver expressionResolver, final DelegatingResourceDefinition rootResourceDefinition, final ExtensionRegistry extensionRegistry, final DomainControllerRuntimeIgnoreTransformationRegistry runtimeIgnoreTransformationRegistry) { super( ProcessType.HOST_CONTROLLER, runningModeControl, null, processState, rootResourceDefinition, prepareStepHandler, new RuntimeExpressionResolver(vaultReader)); this.environment = environment; this.runningModeControl = runningModeControl; this.processState = processState; this.hostControllerInfo = hostControllerInfo; this.localFileRepository = new LocalFileRepository( environment.getDomainBaseDir(), environment.getDomainContentDir(), environment.getDomainConfigurationDir()); this.remoteFileRepository = new RemoteFileRepository(localFileRepository); this.contentRepository = contentRepository; this.hostProxies = hostProxies; this.serverProxies = serverProxies; this.prepareStepHandler = prepareStepHandler; this.vaultReader = vaultReader; this.ignoredRegistry = ignoredRegistry; this.bootstrapListener = bootstrapListener; this.extensionRegistry = extensionRegistry; this.pathManager = pathManager; this.expressionResolver = expressionResolver; this.rootResourceDefinition = rootResourceDefinition; this.runtimeIgnoreTransformationRegistry = runtimeIgnoreTransformationRegistry; } @Override public RunningMode getCurrentRunningMode() { return runningModeControl.getRunningMode(); } @Override public LocalHostControllerInfo getLocalHostInfo() { return hostControllerInfo; } @Override public void registerRemoteHost( final String hostName, final ManagementChannelHandler handler, final Transformers transformers, Long remoteConnectionId, DomainControllerRuntimeIgnoreTransformationEntry runtimeIgnoreTransformation) throws SlaveRegistrationException { if (!hostControllerInfo.isMasterDomainController()) { throw SlaveRegistrationException.forHostIsNotMaster(); } if (runningModeControl.getRunningMode() == RunningMode.ADMIN_ONLY) { throw SlaveRegistrationException.forMasterInAdminOnlyMode( runningModeControl.getRunningMode()); } final PathElement pe = PathElement.pathElement(ModelDescriptionConstants.HOST, hostName); final PathAddress addr = PathAddress.pathAddress(pe); ProxyController existingController = modelNodeRegistration.getProxyController(addr); if (existingController != null || hostControllerInfo.getLocalHostName().equals(pe.getValue())) { throw SlaveRegistrationException.forHostAlreadyExists(pe.getValue()); } SlaveHostPinger pinger = remoteConnectionId == null ? null : new SlaveHostPinger(hostName, handler, pingScheduler, remoteConnectionId); hostRegistrationMap.put(hostName, new HostRegistration(remoteConnectionId, handler, pinger)); // Create the proxy controller final TransformingProxyController hostControllerClient = TransformingProxyController.Factory.create( handler, transformers, addr, ProxyOperationAddressTranslator.HOST); modelNodeRegistration.registerProxyController(pe, hostControllerClient); runtimeIgnoreTransformationRegistry.registerHost(hostName, runtimeIgnoreTransformation); hostProxies.put(hostName, hostControllerClient); // if (pinger != null) { // pinger.schedulePing(SlaveHostPinger.STD_TIMEOUT, SlaveHostPinger.STD_INTERVAL); // } } @Override public boolean isHostRegistered(String id) { return hostControllerInfo.getLocalHostName().equals(id) || hostRegistrationMap.containsKey(id); } @Override public void unregisterRemoteHost(String id, Long remoteConnectionId) { HostRegistration hostRegistration = hostRegistrationMap.get(id); if (hostRegistration != null) { if ((remoteConnectionId == null || remoteConnectionId.equals(hostRegistration.remoteConnectionId)) && hostRegistrationMap.remove(id, hostRegistration)) { if (hostRegistration.pinger != null) { hostRegistration.pinger.cancel(); } hostProxies.remove(id); runtimeIgnoreTransformationRegistry.unregisterHost(id); modelNodeRegistration.unregisterProxyController(PathElement.pathElement(HOST, id)); DOMAIN_LOGGER.unregisteredRemoteSlaveHost(id); } } } @Override public void pingRemoteHost(String id) { HostRegistration reg = hostRegistrationMap.get(id); if (reg != null && reg.pinger != null && !reg.pinger.isCancelled()) { reg.pinger.schedulePing(SlaveHostPinger.SHORT_TIMEOUT, 0); } } @Override public void registerRunningServer(final ProxyController serverControllerClient) { PathAddress pa = serverControllerClient.getProxyNodeAddress(); PathElement pe = pa.getElement(1); if (modelNodeRegistration.getProxyController(pa) != null) { throw MESSAGES.serverNameAlreadyRegistered(pe.getValue()); } ROOT_LOGGER.registeringServer(pe.getValue()); // Register the proxy final ManagementResourceRegistration hostRegistration = modelNodeRegistration.getSubModel( PathAddress.pathAddress( PathElement.pathElement(HOST, hostControllerInfo.getLocalHostName()))); hostRegistration.registerProxyController(pe, serverControllerClient); // Register local operation overrides final ManagementResourceRegistration serverRegistration = hostRegistration.getSubModel(PathAddress.EMPTY_ADDRESS.append(pe)); ServerConfigResourceDefinition.registerServerLifecycleOperations( serverRegistration, serverInventory); serverProxies.put(pe.getValue(), serverControllerClient); } @Override public void unregisterRunningServer(String serverName) { PathAddress pa = PathAddress.pathAddress( PathElement.pathElement(HOST, hostControllerInfo.getLocalHostName())); PathElement pe = PathElement.pathElement(RUNNING_SERVER, serverName); ROOT_LOGGER.unregisteringServer(serverName); ManagementResourceRegistration hostRegistration = modelNodeRegistration.getSubModel(pa); hostRegistration.unregisterProxyController(pe); serverProxies.remove(serverName); } @Override public ModelNode getProfileOperations(String profileName) { ModelNode operation = new ModelNode(); operation.get(OP).set(DESCRIBE); operation .get(OP_ADDR) .set(PathAddress.pathAddress(PathElement.pathElement(PROFILE, profileName)).toModelNode()); ModelNode rsp = getValue().execute(operation, null, null, null); if (!rsp.hasDefined(OUTCOME) || !SUCCESS.equals(rsp.get(OUTCOME).asString())) { ModelNode msgNode = rsp.get(FAILURE_DESCRIPTION); String msg = msgNode.isDefined() ? msgNode.toString() : MESSAGES.failedProfileOperationsRetrieval(); throw new RuntimeException(msg); } return rsp.require(RESULT); } @Override public HostFileRepository getLocalFileRepository() { return localFileRepository; } @Override public HostFileRepository getRemoteFileRepository() { if (hostControllerInfo.isMasterDomainController()) { throw MESSAGES.cannotAccessRemoteFileRepository(); } return remoteFileRepository; } @Override public void start(StartContext context) throws StartException { final ExecutorService executorService = getExecutorServiceInjector().getValue(); this.hostControllerConfigurationPersister = new HostControllerConfigurationPersister( environment, hostControllerInfo, executorService, extensionRegistry); setConfigurationPersister(hostControllerConfigurationPersister); prepareStepHandler.setExecutorService(executorService); ThreadFactory threadFactory = new JBossThreadFactory( new ThreadGroup("proxy-threads"), Boolean.FALSE, null, "%G - %t", null, null, doPrivileged(GetAccessControlContextAction.getInstance())); proxyExecutor = Executors.newCachedThreadPool(threadFactory); ThreadFactory pingerThreadFactory = new JBossThreadFactory( new ThreadGroup("proxy-pinger-threads"), Boolean.TRUE, null, "%G - %t", null, null, doPrivileged(GetAccessControlContextAction.getInstance())); pingScheduler = Executors.newScheduledThreadPool(PINGER_POOL_SIZE, pingerThreadFactory); super.start(context); } @Override protected void initModel(Resource rootResource, ManagementResourceRegistration rootRegistration) { HostModelUtil.createRootRegistry( rootRegistration, environment, ignoredRegistry, this, processType); VersionModelInitializer.registerRootResource( rootResource, environment != null ? environment.getProductConfig() : null); this.modelNodeRegistration = rootRegistration; } // See superclass start. This method is invoked from a separate non-MSC thread after start. So we // can do a fair // bit of stuff @Override protected void boot(final BootContext context) throws ConfigurationPersistenceException { final ServiceTarget serviceTarget = context.getServiceTarget(); boolean ok = false; boolean reachedServers = false; try { // Install server inventory callback ServerInventoryCallbackService.install(serviceTarget); // Parse the host.xml and invoke all the ops. The ops should rollback on any Stage.RUNTIME // failure // We run the first op ("add-host") separately to let it set up the host // ManagementResourceRegistration List<ModelNode> hostBootOps = hostControllerConfigurationPersister.load(); ModelNode addHostOp = hostBootOps.remove(0); ok = boot(Collections.singletonList(addHostOp), true); ok = ok && boot(hostBootOps, true); final RunningMode currentRunningMode = runningModeControl.getRunningMode(); if (ok) { // Now we know our discovery configuration. List<DiscoveryOption> discoveryOptions = hostControllerInfo.getRemoteDomainControllerDiscoveryOptions(); if (hostControllerInfo.isMasterDomainController() && (discoveryOptions != null)) { // Install the discovery service DiscoveryService.install( serviceTarget, discoveryOptions, hostControllerInfo.getNativeManagementInterface(), hostControllerInfo.getNativeManagementPort(), hostControllerInfo.isMasterDomainController()); } // Now we know our management interface configuration. Install the server inventory Future<ServerInventory> inventoryFuture = ServerInventoryService.install( serviceTarget, this, runningModeControl, environment, extensionRegistry, hostControllerInfo.getNativeManagementInterface(), hostControllerInfo.getNativeManagementPort()); if (!hostControllerInfo.isMasterDomainController() && !environment.isUseCachedDc()) { serverInventory = getFuture(inventoryFuture); if ((discoveryOptions != null) && !discoveryOptions.isEmpty()) { Future<MasterDomainControllerClient> clientFuture = RemoteDomainConnectionService.install( serviceTarget, getValue(), extensionRegistry, hostControllerInfo, environment.getProductConfig(), hostControllerInfo.getRemoteDomainControllerSecurityRealm(), remoteFileRepository, ignoredRegistry, new InternalExecutor(), this, environment); MasterDomainControllerClient masterDomainControllerClient = getFuture(clientFuture); // Registers us with the master and gets down the master copy of the domain model to our // DC // TODO make sure that the RDCS checks env.isUseCachedDC, and if true falls through to // that // BES 2012/02/04 Comment ^^^ implies the semantic is to use isUseCachedDC as a fallback // to // a failure to connect as opposed to being an instruction to not connect at all. I // believe // the current impl is the latter. Don't change this without a discussion first, as the // current semantic is a reasonable one. try { masterDomainControllerClient.register(); } catch (Exception e) { // We could not connect to the host ROOT_LOGGER.cannotConnectToMaster(e); System.exit(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE); } } else if (currentRunningMode != RunningMode.ADMIN_ONLY) { // Invalid configuration; no way to get the domain config ROOT_LOGGER.noDomainControllerConfigurationProvided( currentRunningMode, CommandLineConstants.ADMIN_ONLY, RunningMode.ADMIN_ONLY); System.exit(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE); } } else { if (environment.isUseCachedDc()) { remoteFileRepository.setRemoteFileRepositoryExecutor( new RemoteDomainConnectionService.RemoteFileRepositoryExecutor() { @Override public File getFile( String relativePath, byte repoId, HostFileRepository localFileRepository) { return localFileRepository.getFile(relativePath); } }); } // parse the domain.xml and load the steps // TODO look at having LocalDomainControllerAdd do this, using Stage.IMMEDIATE for the // steps ConfigurationPersister domainPersister = hostControllerConfigurationPersister.getDomainPersister(); ok = boot(domainPersister.load(), false); if (!ok && runningModeControl.getRunningMode().equals(RunningMode.ADMIN_ONLY)) { ROOT_LOGGER.reportAdminOnlyDomainXmlFailure(); ok = true; } if (ok) { InternalExecutor executor = new InternalExecutor(); ManagementRemotingServices.installManagementChannelServices( serviceTarget, ManagementRemotingServices.MANAGEMENT_ENDPOINT, new MasterDomainControllerOperationHandlerService( this, executor, executor, runtimeIgnoreTransformationRegistry), DomainModelControllerService.SERVICE_NAME, ManagementRemotingServices.DOMAIN_CHANNEL, null, null); serverInventory = getFuture(inventoryFuture); } } } if (ok) { // Install the server > host operation handler ServerToHostOperationHandlerFactoryService.install( serviceTarget, ServerInventoryService.SERVICE_NAME, proxyExecutor, new InternalExecutor(), this, expressionResolver); // demand native mgmt services serviceTarget .addService(ServiceName.JBOSS.append("native-mgmt-startup"), Service.NULL) .addDependency( ManagementRemotingServices.channelServiceName( ManagementRemotingServices.MANAGEMENT_ENDPOINT, ManagementRemotingServices.SERVER_CHANNEL)) .setInitialMode(ServiceController.Mode.ACTIVE) .install(); // demand http mgmt services serviceTarget .addService(ServiceName.JBOSS.append("http-mgmt-startup"), Service.NULL) .addDependency( ServiceBuilder.DependencyType.OPTIONAL, _UndertowHttpManagementService.SERVICE_NAME) .setInitialMode(ServiceController.Mode.ACTIVE) .install(); reachedServers = true; if (currentRunningMode == RunningMode.NORMAL) { startServers(); } } } catch (Exception e) { ROOT_LOGGER.caughtExceptionDuringBoot(e); if (!reachedServers) { ok = false; } } finally { if (ok) { try { finishBoot(); } finally { // Trigger the started message bootstrapListener.printBootStatistics(); } } else { // Die! ROOT_LOGGER.unsuccessfulBoot(); System.exit(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE); } } } private <T> T getFuture(Future<T> future) { try { return future.get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } catch (ExecutionException e) { throw new RuntimeException(e); } } private void startServers() { ModelNode addr = new ModelNode(); addr.add(HOST, hostControllerInfo.getLocalHostName()); ModelNode op = Util.getEmptyOperation(StartServersHandler.OPERATION_NAME, addr); getValue().execute(op, null, null, null); } @Override public void stop(final StopContext context) { serverInventory = null; extensionRegistry.clear(); super.stop(context); context.asynchronous(); Thread executorShutdown = new Thread( new Runnable() { @Override public void run() { try { pingScheduler.shutdownNow(); } finally { try { proxyExecutor.shutdown(); } finally { context.complete(); } } } }, DomainModelControllerService.class.getSimpleName() + " ExecutorService Shutdown Thread"); executorShutdown.start(); } @Override public void stopLocalHost() { stopLocalHost(0); } @Override public void stopLocalHost(int exitCode) { final ProcessControllerClient client = injectedProcessControllerConnection.getValue().getClient(); processState.setStopping(); try { client.shutdown(exitCode); } catch (IOException e) { throw MESSAGES.errorClosingDownHost(e); } } @Override public void registerHostModel(String hostName, ManagementResourceRegistration root) { HostModelUtil.createHostRegistry( hostName, root, hostControllerConfigurationPersister, environment, runningModeControl, localFileRepository, hostControllerInfo, new DelegatingServerInventory(), remoteFileRepository, contentRepository, this, extensionRegistry, vaultReader, ignoredRegistry, processState, pathManager); } public void initializeMasterDomainRegistry( final ManagementResourceRegistration root, final ExtensibleConfigurationPersister configurationPersister, final ContentRepository contentRepository, final HostFileRepository fileRepository, final ExtensionRegistry extensionRegistry, final PathManagerService pathManager) { initializeDomainResource( root, configurationPersister, contentRepository, fileRepository, true, hostControllerInfo, extensionRegistry, null, pathManager); } public void initializeSlaveDomainRegistry( final ManagementResourceRegistration root, final ExtensibleConfigurationPersister configurationPersister, final ContentRepository contentRepository, final HostFileRepository fileRepository, final LocalHostControllerInfo hostControllerInfo, final ExtensionRegistry extensionRegistry, final IgnoredDomainResourceRegistry ignoredDomainResourceRegistry, final PathManagerService pathManagery) { initializeDomainResource( root, configurationPersister, contentRepository, fileRepository, false, hostControllerInfo, extensionRegistry, ignoredDomainResourceRegistry, pathManager); } private void initializeDomainResource( final ManagementResourceRegistration root, final ExtensibleConfigurationPersister configurationPersister, final ContentRepository contentRepo, final HostFileRepository fileRepository, final boolean isMaster, final LocalHostControllerInfo hostControllerInfo, final ExtensionRegistry extensionRegistry, final IgnoredDomainResourceRegistry ignoredDomainResourceRegistry, final PathManagerService pathManager) { DomainRootDefinition domainRootDefinition = new DomainRootDefinition( this, environment, configurationPersister, contentRepo, fileRepository, isMaster, hostControllerInfo, extensionRegistry, ignoredDomainResourceRegistry, pathManager, isMaster ? runtimeIgnoreTransformationRegistry : null); rootResourceDefinition.setDelegate(domainRootDefinition, root); } private static class HostRegistration { private final Long remoteConnectionId; private final ManagementChannelHandler channelHandler; private final SlaveHostPinger pinger; private HostRegistration( Long remoteConnectionId, ManagementChannelHandler channelHandler, SlaveHostPinger pinger) { this.remoteConnectionId = remoteConnectionId; this.channelHandler = channelHandler; this.pinger = pinger; } @Override public int hashCode() { return remoteConnectionId == null ? Integer.MIN_VALUE : channelHandler.hashCode(); } @Override public boolean equals(Object obj) { return obj instanceof HostRegistration && safeEquals(remoteConnectionId, ((HostRegistration) obj).remoteConnectionId); } private static boolean safeEquals(Object a, Object b) { return a == b || (a != null && a.equals(b)); } } private class DelegatingServerInventory implements ServerInventory { public ProxyController serverCommunicationRegistered( String serverProcessName, ManagementChannelHandler channelHandler) { return serverInventory.serverCommunicationRegistered(serverProcessName, channelHandler); } public boolean serverReconnected( String serverProcessName, ManagementChannelHandler channelHandler) { return serverInventory.serverReconnected(serverProcessName, channelHandler); } public void serverProcessAdded(String serverProcessName) { serverInventory.serverProcessAdded(serverProcessName); } public void serverStartFailed(String serverProcessName) { serverInventory.serverStartFailed(serverProcessName); } @Override public void serverStarted(String serverProcessName) { serverInventory.serverStarted(serverProcessName); } public void serverProcessStopped(String serverProcessName) { serverInventory.serverProcessStopped(serverProcessName); } public String getServerProcessName(String serverName) { return serverInventory.getServerProcessName(serverName); } public String getProcessServerName(String processName) { return serverInventory.getProcessServerName(processName); } @Override public ServerStatus reloadServer(String serverName, boolean blocking) { return serverInventory.reloadServer(serverName, blocking); } public void processInventory(Map<String, ProcessInfo> processInfos) { serverInventory.processInventory(processInfos); } public Map<String, ProcessInfo> determineRunningProcesses() { return serverInventory.determineRunningProcesses(); } public Map<String, ProcessInfo> determineRunningProcesses(boolean serversOnly) { return serverInventory.determineRunningProcesses(serversOnly); } public ServerStatus determineServerStatus(String serverName) { return serverInventory.determineServerStatus(serverName); } public ServerStatus startServer(String serverName, ModelNode domainModel) { return serverInventory.startServer(serverName, domainModel); } @Override public ServerStatus startServer(String serverName, ModelNode domainModel, boolean blocking) { return serverInventory.startServer(serverName, domainModel, blocking); } public void reconnectServer( String serverName, ModelNode domainModel, byte[] authKey, boolean running, boolean stopping) { serverInventory.reconnectServer(serverName, domainModel, authKey, running, stopping); } public ServerStatus restartServer( String serverName, int gracefulTimeout, ModelNode domainModel) { return serverInventory.restartServer(serverName, gracefulTimeout, domainModel); } @Override public ServerStatus restartServer( String serverName, int gracefulTimeout, ModelNode domainModel, boolean blocking) { return serverInventory.restartServer(serverName, gracefulTimeout, domainModel, blocking); } public ServerStatus stopServer(String serverName, int gracefulTimeout) { return serverInventory.stopServer(serverName, gracefulTimeout); } @Override public ServerStatus stopServer(String serverName, int gracefulTimeout, boolean blocking) { return serverInventory.stopServer(serverName, gracefulTimeout, blocking); } public CallbackHandler getServerCallbackHandler() { return serverInventory.getServerCallbackHandler(); } @Override public void stopServers(int gracefulTimeout) { serverInventory.stopServers(gracefulTimeout); } @Override public void stopServers(int gracefulTimeout, boolean blockUntilStopped) { serverInventory.stopServers(gracefulTimeout, blockUntilStopped); } @Override public void connectionFinished() { serverInventory.connectionFinished(); } @Override public void serverProcessStarted(String processName) { serverInventory.serverProcessStarted(processName); } @Override public void serverProcessRemoved(String processName) { serverInventory.serverProcessRemoved(processName); } @Override public void operationFailed(String processName, ProcessMessageHandler.OperationType type) { serverInventory.operationFailed(processName, type); } @Override public void destroyServer(String serverName) { serverInventory.destroyServer(serverName); } @Override public void killServer(String serverName) { serverInventory.killServer(serverName); } @Override public void awaitServersState(Collection<String> serverNames, boolean started) { serverInventory.awaitServersState(serverNames, started); } } private static <S> S service(final Class<S> service) { final ServiceLoader<S> serviceLoader = ServiceLoader.load(service); final Iterator<S> it = serviceLoader.iterator(); if (it.hasNext()) return it.next(); return null; } @Override public ExtensionRegistry getExtensionRegistry() { return extensionRegistry; } @Override public ExpressionResolver getExpressionResolver() { return expressionResolver; } private static class DelegatingResourceDefinition implements ResourceDefinition { private volatile ResourceDefinition delegate; void setDelegate(DomainRootDefinition delegate, ManagementResourceRegistration root) { this.delegate = delegate; delegate.initialize(root); } @Override public void registerOperations(ManagementResourceRegistration resourceRegistration) { // These will be registered later } @Override public void registerChildren(ManagementResourceRegistration resourceRegistration) { // These will be registered later } @Override public void registerAttributes(ManagementResourceRegistration resourceRegistration) { // These will be registered later } @Override public PathElement getPathElement() { return delegate.getPathElement(); } @Override public DescriptionProvider getDescriptionProvider( ImmutableManagementResourceRegistration resourceRegistration) { return delegate.getDescriptionProvider(resourceRegistration); } } final class InternalExecutor implements HostControllerRegistrationHandler.OperationExecutor, ServerToHostProtocolHandler.OperationExecutor, MasterDomainControllerOperationHandlerService.TransactionalOperationExecutor { @Override public ModelNode execute( final ModelNode operation, final OperationMessageHandler handler, final ModelController.OperationTransactionControl control, final OperationAttachments attachments, final OperationStepHandler step) { return internalExecute(operation, handler, control, attachments, step); } @Override @SuppressWarnings("deprecation") public ModelNode joinActiveOperation( ModelNode operation, OperationMessageHandler handler, ModelController.OperationTransactionControl control, OperationAttachments attachments, OperationStepHandler step, int permit) { return executeReadOnlyOperation(operation, handler, control, attachments, step, permit); } @Override public ModelNode executeAndAttemptLock( final ModelNode operation, final OperationMessageHandler handler, final ModelController.OperationTransactionControl control, final OperationAttachments attachments, final OperationStepHandler step) { return internalExecute(operation, handler, control, attachments, step, true); } }; }
/** * Creates the service that acts as the {@link org.jboss.as.controller.ModelController} for a Host * Controller process. * * @author Brian Stansberry (c) 2011 Red Hat Inc. */ public class DomainModelControllerService extends AbstractControllerService implements DomainController, UnregisteredHostChannelRegistry { private static final Logger log = Logger.getLogger("org.jboss.as.host.controller"); public static final ServiceName SERVICE_NAME = HostControllerService.HC_SERVICE_NAME.append("model", "controller"); private HostControllerConfigurationPersister hostControllerConfigurationPersister; private final HostControllerEnvironment environment; private final RunningModeControl runningModeControl; private final LocalHostControllerInfoImpl hostControllerInfo; private final FileRepository localFileRepository; private final RemoteFileRepository remoteFileRepository; private final InjectedValue<ProcessControllerConnectionService> injectedProcessControllerConnection = new InjectedValue<ProcessControllerConnectionService>(); private final Map<String, ProxyController> hostProxies; private final Map<String, ProxyController> serverProxies; private final PrepareStepHandler prepareStepHandler; private final BootstrapListener bootstrapListener; private ManagementResourceRegistration modelNodeRegistration; private final Map<String, Channel> unregisteredHostChannels = new HashMap<String, Channel>(); private final Map<String, ProxyCreatedCallback> proxyCreatedCallbacks = new HashMap<String, ProxyCreatedCallback>(); // TODO look into using the controller executor private final ExecutorService proxyExecutor = Executors.newCachedThreadPool(); private final AbstractVaultReader vaultReader; private volatile ServerInventory serverInventory; public static ServiceController<ModelController> addService( final ServiceTarget serviceTarget, final HostControllerEnvironment environment, final RunningModeControl runningModeControl, final ControlledProcessState processState, final BootstrapListener bootstrapListener) { final Map<String, ProxyController> hostProxies = new ConcurrentHashMap<String, ProxyController>(); final Map<String, ProxyController> serverProxies = new ConcurrentHashMap<String, ProxyController>(); final LocalHostControllerInfoImpl hostControllerInfo = new LocalHostControllerInfoImpl(processState); final AbstractVaultReader vaultReader = service(AbstractVaultReader.class); log.debugf("Using VaultReader %s", vaultReader); final PrepareStepHandler prepareStepHandler = new PrepareStepHandler(hostControllerInfo, hostProxies, serverProxies); DomainModelControllerService service = new DomainModelControllerService( environment, runningModeControl, processState, hostControllerInfo, hostProxies, serverProxies, prepareStepHandler, vaultReader, bootstrapListener); return serviceTarget .addService(SERVICE_NAME, service) .addDependency( HostControllerService.HC_EXECUTOR_SERVICE_NAME, ExecutorService.class, service.getExecutorServiceInjector()) .addDependency( ProcessControllerConnectionService.SERVICE_NAME, ProcessControllerConnectionService.class, service.injectedProcessControllerConnection) .setInitialMode(ServiceController.Mode.ACTIVE) .install(); } private DomainModelControllerService( final HostControllerEnvironment environment, final RunningModeControl runningModeControl, final ControlledProcessState processState, final LocalHostControllerInfoImpl hostControllerInfo, final Map<String, ProxyController> hostProxies, final Map<String, ProxyController> serverProxies, final PrepareStepHandler prepareStepHandler, final AbstractVaultReader vaultReader, final BootstrapListener bootstrapListener) { super( ProcessType.HOST_CONTROLLER, runningModeControl, null, processState, DomainDescriptionProviders.ROOT_PROVIDER, prepareStepHandler, new RuntimeExpressionResolver(vaultReader)); this.environment = environment; this.runningModeControl = runningModeControl; this.hostControllerInfo = hostControllerInfo; this.localFileRepository = new LocalFileRepository(environment); this.remoteFileRepository = new RemoteFileRepository(localFileRepository); this.hostProxies = hostProxies; this.serverProxies = serverProxies; this.prepareStepHandler = prepareStepHandler; this.vaultReader = vaultReader; this.bootstrapListener = bootstrapListener; } @Override public LocalHostControllerInfo getLocalHostInfo() { return hostControllerInfo; } @Override public void registerRemoteHost(ProxyController hostControllerClient) throws SlaveRegistrationException { if (!hostControllerInfo.isMasterDomainController()) { throw SlaveRegistrationException.forHostIsNotMaster(); } if (runningModeControl.getRunningMode() == RunningMode.ADMIN_ONLY) { throw SlaveRegistrationException.forMasterInAdminOnlyMode( runningModeControl.getRunningMode()); } PathAddress pa = hostControllerClient.getProxyNodeAddress(); PathElement pe = pa.getElement(0); ProxyController existingController = modelNodeRegistration.getProxyController(pa); if (existingController != null || hostControllerInfo.getLocalHostName().equals(pe.getValue())) { throw SlaveRegistrationException.forHostAlreadyExists(pe.getValue()); } modelNodeRegistration.registerProxyController(pe, hostControllerClient); hostProxies.put(pe.getValue(), hostControllerClient); Logger.getLogger("org.jboss.domain").info("Registered remote slave host " + pe.getValue()); } @Override public void unregisterRemoteHost(String id) { unregisteredHostChannels.remove(id); if (hostProxies.remove(id) != null) { Logger.getLogger("org.jboss.domain").info("Unregistered remote slave host " + id); } modelNodeRegistration.unregisterProxyController(PathElement.pathElement(HOST, id)); } @Override public void registerRunningServer(ProxyController serverControllerClient) { PathAddress pa = serverControllerClient.getProxyNodeAddress(); PathElement pe = pa.getElement(1); if (modelNodeRegistration.getProxyController(pa) != null) { throw new IllegalArgumentException( "There is already a registered server named '" + pe.getValue() + "'"); } Logger.getLogger("org.jboss.host.controller").info("Registering server " + pe.getValue()); ManagementResourceRegistration hostRegistration = modelNodeRegistration.getSubModel(PathAddress.pathAddress(PathElement.pathElement(HOST))); hostRegistration.registerProxyController(pe, serverControllerClient); serverProxies.put(pe.getValue(), serverControllerClient); } @Override public void unregisterRunningServer(String serverName) { PathAddress pa = PathAddress.pathAddress( PathElement.pathElement(HOST, hostControllerInfo.getLocalHostName())); PathElement pe = PathElement.pathElement(RUNNING_SERVER, serverName); Logger.getLogger("org.jboss.host.controller").info("Unregistering server " + serverName); ManagementResourceRegistration hostRegistration = modelNodeRegistration.getSubModel(pa); hostRegistration.unregisterProxyController(pe); serverProxies.remove(serverName); } @Override public ModelNode getProfileOperations(String profileName) { ModelNode operation = new ModelNode(); operation.get(OP).set(DESCRIBE); operation .get(OP_ADDR) .set(PathAddress.pathAddress(PathElement.pathElement(PROFILE, profileName)).toModelNode()); ModelNode rsp = getValue().execute(operation, null, null, null); if (!rsp.hasDefined(OUTCOME) || !SUCCESS.equals(rsp.get(OUTCOME).asString())) { ModelNode msgNode = rsp.get(FAILURE_DESCRIPTION); String msg = msgNode.isDefined() ? msgNode.toString() : "Failed to retrieve profile operations from domain controller"; throw new RuntimeException(msg); } return rsp.require(RESULT); } @Override public FileRepository getLocalFileRepository() { return localFileRepository; } @Override public FileRepository getRemoteFileRepository() { if (hostControllerInfo.isMasterDomainController()) { throw new IllegalStateException( "Cannot access a remote file repository from the master domain controller"); } return remoteFileRepository; } @Override public void start(StartContext context) throws StartException { final ExecutorService executorService = getExecutorServiceInjector().getValue(); this.hostControllerConfigurationPersister = new HostControllerConfigurationPersister(environment, hostControllerInfo, executorService); setConfigurationPersister(hostControllerConfigurationPersister); prepareStepHandler.setExecutorService(executorService); super.start(context); } @Override protected void initModel(Resource rootResource, ManagementResourceRegistration rootRegistration) { DomainModelUtil.updateCoreModel(rootResource.getModel()); HostModelUtil.createHostRegistry( rootRegistration, hostControllerConfigurationPersister, environment, runningModeControl, localFileRepository, hostControllerInfo, new DelegatingServerInventory(), remoteFileRepository, this, this, vaultReader); this.modelNodeRegistration = rootRegistration; } // See superclass start. This method is invoked from a separate non-MSC thread after start. So we // can do a fair // bit of stuff @Override protected void boot(final BootContext context) throws ConfigurationPersistenceException { final ServiceTarget serviceTarget = context.getServiceTarget(); try { super.boot( hostControllerConfigurationPersister .load()); // This parses the host.xml and invokes all ops final RunningMode currentRunningMode = runningModeControl.getRunningMode(); // Now we know our management interface configuration. Install the server inventory Future<ServerInventory> inventoryFuture = ServerInventoryService.install( serviceTarget, this, environment, hostControllerInfo.getNativeManagementInterface(), hostControllerInfo.getNativeManagementPort()); // Install the core remoting endpoint and listener ManagementRemotingServices.installRemotingEndpoint( serviceTarget, ManagementRemotingServices.MANAGEMENT_ENDPOINT, hostControllerInfo.getLocalHostName(), EndpointService.EndpointType.MANAGEMENT, null, null); if (!hostControllerInfo.isMasterDomainController() && !environment.isUseCachedDc()) { serverInventory = getFuture(inventoryFuture); if (hostControllerInfo.getRemoteDomainControllerHost() != null) { Future<MasterDomainControllerClient> clientFuture = RemoteDomainConnectionService.install( serviceTarget, getValue(), hostControllerInfo.getLocalHostName(), hostControllerInfo.getRemoteDomainControllerHost(), hostControllerInfo.getRemoteDomainControllertPort(), hostControllerInfo.getRemoteDomainControllerSecurityRealm(), remoteFileRepository); MasterDomainControllerClient masterDomainControllerClient = getFuture(clientFuture); // Registers us with the master and gets down the master copy of the domain model to our // DC // TODO make sure that the RDCS checks env.isUseCachedDC, and if true falls through to // that try { masterDomainControllerClient.register(); } catch (IllegalStateException e) { // We could not connect to the host log.error(HostControllerMessages.MESSAGES.cannotConnectToMaster(e)); System.exit(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE); } } else if (currentRunningMode != RunningMode.ADMIN_ONLY) { // We could not connect to the host log.error( HostControllerMessages.MESSAGES.noDomainControllerConfigurationProvided( currentRunningMode, CommandLineConstants.ADMIN_ONLY, RunningMode.ADMIN_ONLY)); System.exit(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE); } } else { // TODO look at having LocalDomainControllerAdd do this, using Stage.IMMEDIATE for the steps // parse the domain.xml and load the steps ConfigurationPersister domainPersister = hostControllerConfigurationPersister.getDomainPersister(); super.boot(domainPersister.load()); ManagementRemotingServices.installManagementChannelServices( serviceTarget, ManagementRemotingServices.MANAGEMENT_ENDPOINT, new MasterDomainControllerOperationHandlerService(this, this), DomainModelControllerService.SERVICE_NAME, ManagementRemotingServices.DOMAIN_CHANNEL, null, null); serverInventory = getFuture(inventoryFuture); } // TODO look into adding some of these services in the handlers, but ON-DEMAND. // Then here just add some simple service that demands them ServerToHostOperationHandlerFactoryService.install( serviceTarget, ServerInventoryService.SERVICE_NAME, proxyExecutor); NativeManagementAddHandler.installNativeManagementServices( serviceTarget, hostControllerInfo, null, null); if (hostControllerInfo.getHttpManagementInterface() != null) { HttpManagementAddHandler.installHttpManagementServices( serviceTarget, hostControllerInfo, environment, null); } if (currentRunningMode == RunningMode.NORMAL) { startServers(); } // TODO when to call hostControllerConfigurationPersister.successful boot? Look into this for // standalone as well; may be broken now } finally { try { finishBoot(); } finally { bootstrapListener.tick(); } } } private <T> T getFuture(Future<T> future) { try { return future.get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } catch (ExecutionException e) { throw new RuntimeException(e); } } private void startServers() { ModelNode addr = new ModelNode(); addr.add(HOST, hostControllerInfo.getLocalHostName()); ModelNode op = Util.getEmptyOperation(StartServersHandler.OPERATION_NAME, addr); getValue().execute(op, null, null, null); } @Override public void stop(StopContext context) { serverInventory = null; super.stop(context); } @Override public void stopLocalHost() { final ProcessControllerClient client = injectedProcessControllerConnection.getValue().getClient(); try { client.shutdown(); } catch (IOException e) { throw new RuntimeException("Error closing down host", e); } } @Override public synchronized void registerChannel( final String hostName, final Channel channel, final ProxyCreatedCallback callback) { /* Disable this as part of the REM3-121 workarounds PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(HOST, hostName)); if (modelNodeRegistration.getProxyController(addr) != null) { throw new IllegalArgumentException("There is already a registered slave named '" + hostName + "'"); } */ if (unregisteredHostChannels.containsKey(hostName)) { throw new IllegalArgumentException("Already have a connection for host " + hostName); } unregisteredHostChannels.put(hostName, channel); proxyCreatedCallbacks.put(hostName, callback); channel.addCloseHandler( new CloseHandler<Channel>() { public void handleClose(final Channel closed, final IOException exception) { unregisteredHostChannels.remove(hostName); proxyCreatedCallbacks.remove(hostName); } }); } @Override public synchronized ProxyController popChannelAndCreateProxy(final String hostName) { final Channel channel = unregisteredHostChannels.remove(hostName); if (channel == null) { throw new IllegalArgumentException("No channel for host " + hostName); } channel.addCloseHandler( new CloseHandler<Channel>() { public void handleClose(final Channel closed, final IOException exception) { unregisterRemoteHost(hostName); } }); final PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.HOST, hostName)); RemoteProxyController proxy = RemoteProxyController.create( proxyExecutor, addr, ProxyOperationAddressTranslator.HOST, channel); ProxyCreatedCallback callback = proxyCreatedCallbacks.remove(hostName); if (callback != null) { callback.proxyCreated(proxy); } return proxy; } private class DelegatingServerInventory implements ServerInventory { public void serverRegistered( String serverProcessName, Channel channel, ProxyCreatedCallback callback) { serverInventory.serverRegistered(serverProcessName, channel, callback); } public void serverStartFailed(String serverProcessName) { serverInventory.serverStartFailed(serverProcessName); } public void serverStopped(String serverProcessName) { serverInventory.serverStopped(serverProcessName); } public String getServerProcessName(String serverName) { return serverInventory.getServerProcessName(serverName); } public String getProcessServerName(String processName) { return serverInventory.getProcessServerName(processName); } public void processInventory(Map<String, ProcessInfo> processInfos) { serverInventory.processInventory(processInfos); } public Map<String, ProcessInfo> determineRunningProcesses() { return serverInventory.determineRunningProcesses(); } public Map<String, ProcessInfo> determineRunningProcesses(boolean serversOnly) { return serverInventory.determineRunningProcesses(serversOnly); } public ServerStatus determineServerStatus(String serverName) { return serverInventory.determineServerStatus(serverName); } public int hashCode() { return serverInventory.hashCode(); } public ServerStatus startServer(String serverName, ModelNode domainModel) { return serverInventory.startServer(serverName, domainModel); } public void reconnectServer(String serverName, ModelNode domainModel, boolean running) { serverInventory.reconnectServer(serverName, domainModel, running); } public ServerStatus restartServer( String serverName, int gracefulTimeout, ModelNode domainModel) { return serverInventory.restartServer(serverName, gracefulTimeout, domainModel); } public ServerStatus stopServer(String serverName, int gracefulTimeout) { return serverInventory.stopServer(serverName, gracefulTimeout); } public CallbackHandler getServerCallbackHandler() { return serverInventory.getServerCallbackHandler(); } public boolean equals(Object obj) { return serverInventory.equals(obj); } public String toString() { return serverInventory.toString(); } @Override public void stopServers(int gracefulTimeout) { serverInventory.stopServers(gracefulTimeout); } } private static <S> S service(final Class<S> service) { final ServiceLoader<S> serviceLoader = ServiceLoader.load(service); final Iterator<S> it = serviceLoader.iterator(); if (it.hasNext()) return it.next(); return null; } }