/* * JBoss, Home of Professional Open Source. * Copyright 2011, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.host.controller; import static java.security.AccessController.doPrivileged; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CORE_SERVICE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESCRIBE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FAILURE_DESCRIPTION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HOST; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HOST_CONNECTION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MANAGEMENT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MANAGEMENT_OPERATIONS; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PROFILE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RUNNING_SERVER; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER_LAUNCH; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVICE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS; import static org.jboss.as.domain.controller.HostConnectionInfo.Events.create; import static org.jboss.as.host.controller.logging.HostControllerLogger.DOMAIN_LOGGER; import static org.jboss.as.host.controller.logging.HostControllerLogger.ROOT_LOGGER; import static org.jboss.as.remoting.Protocol.REMOTE_HTTPS; import static org.jboss.as.remoting.Protocol.REMOTE_HTTP; import static org.jboss.as.remoting.Protocol.REMOTE; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.jboss.as.controller.AbstractControllerService; import org.jboss.as.controller.BlockingTimeout; import org.jboss.as.controller.BootContext; import org.jboss.as.controller.Cancellable; import org.jboss.as.controller.CapabilityRegistry; import org.jboss.as.controller.ControlledProcessState; import org.jboss.as.controller.ControlledProcessStateService; import org.jboss.as.controller.ExpressionResolver; import org.jboss.as.controller.ManagementModel; import org.jboss.as.controller.ModelController; import org.jboss.as.controller.ModelController.OperationTransactionControl; import org.jboss.as.controller.ModelControllerServiceInitialization; import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.OperationStepHandler; import org.jboss.as.controller.PathAddress; import org.jboss.as.controller.PathElement; import org.jboss.as.controller.ProcessType; import org.jboss.as.controller.ProxyController; import org.jboss.as.controller.ProxyOperationAddressTranslator; import org.jboss.as.controller.RunningMode; import org.jboss.as.controller.TransformingProxyController; import org.jboss.as.controller.access.management.DelegatingConfigurableAuthorizer; import org.jboss.as.controller.access.management.ManagementSecurityIdentitySupplier; import org.jboss.as.controller.audit.ManagedAuditLogger; import org.jboss.as.controller.audit.ManagedAuditLoggerImpl; import org.jboss.as.controller.capability.registry.ImmutableCapabilityRegistry; import org.jboss.as.controller.client.Operation; import org.jboss.as.controller.client.OperationAttachments; import org.jboss.as.controller.client.OperationBuilder; import org.jboss.as.controller.client.OperationMessageHandler; import org.jboss.as.controller.client.OperationResponse; import org.jboss.as.controller.client.helpers.domain.ServerStatus; import org.jboss.as.controller.descriptions.ModelDescriptionConstants; import org.jboss.as.controller.extension.ExtensionRegistry; import org.jboss.as.controller.extension.MutableRootResourceRegistrationProvider; import org.jboss.as.controller.extension.RuntimeHostControllerInfoAccessor; import org.jboss.as.controller.logging.ControllerLogger; import org.jboss.as.controller.notification.Notification; import org.jboss.as.controller.operations.common.Util; import org.jboss.as.controller.persistence.ConfigurationPersistenceException; import org.jboss.as.controller.persistence.ConfigurationPersister; import org.jboss.as.controller.persistence.ExtensibleConfigurationPersister; import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.as.controller.registry.PlaceholderResource; import org.jboss.as.controller.registry.Resource; import org.jboss.as.controller.registry.ResourceProvider; import org.jboss.as.controller.services.path.PathManagerService; import org.jboss.as.controller.transform.Transformers; import org.jboss.as.domain.controller.DomainController; import org.jboss.as.domain.controller.HostConnectionInfo; import org.jboss.as.domain.controller.HostConnectionInfo.Event; import org.jboss.as.domain.controller.HostRegistrations; import org.jboss.as.domain.controller.LocalHostControllerInfo; import org.jboss.as.domain.controller.SlaveRegistrationException; import org.jboss.as.domain.controller.logging.DomainControllerLogger; import org.jboss.as.domain.controller.operations.ApplyExtensionsHandler; import org.jboss.as.domain.controller.operations.DomainModelIncludesValidator; import org.jboss.as.domain.controller.operations.coordination.PrepareStepHandler; import org.jboss.as.domain.controller.resources.DomainRootDefinition; import org.jboss.as.domain.management.CoreManagementResourceDefinition; import org.jboss.as.host.controller.RemoteDomainConnectionService.RemoteFileRepository; import org.jboss.as.host.controller.discovery.DiscoveryOption; import org.jboss.as.host.controller.discovery.DomainControllerManagementInterface; import org.jboss.as.host.controller.ignored.IgnoredDomainResourceRegistry; import org.jboss.as.host.controller.logging.HostControllerLogger; import org.jboss.as.host.controller.mgmt.DomainHostExcludeRegistry; import org.jboss.as.host.controller.mgmt.HostControllerRegistrationHandler; import org.jboss.as.host.controller.mgmt.MasterDomainControllerOperationHandlerService; import org.jboss.as.host.controller.mgmt.ServerToHostOperationHandlerFactoryService; import org.jboss.as.host.controller.mgmt.ServerToHostProtocolHandler; import org.jboss.as.host.controller.mgmt.SlaveHostPinger; import org.jboss.as.host.controller.model.host.AdminOnlyDomainConfigPolicy; import org.jboss.as.host.controller.operations.LocalHostControllerInfoImpl; import org.jboss.as.host.controller.operations.StartServersHandler; import org.jboss.as.host.controller.resources.ServerConfigResourceDefinition; import org.jboss.as.process.CommandLineConstants; import org.jboss.as.process.ExitCodes; import org.jboss.as.process.ProcessControllerClient; import org.jboss.as.process.ProcessInfo; import org.jboss.as.process.ProcessMessageHandler; import org.jboss.as.protocol.mgmt.ManagementChannelHandler; import org.jboss.as.remoting.management.ManagementRemotingServices; import org.jboss.as.repository.ContentRepository; import org.jboss.as.repository.HostFileRepository; import org.jboss.as.repository.LocalFileRepository; import org.jboss.as.server.BootstrapListener; import org.jboss.as.server.RuntimeExpressionResolver; import org.jboss.as.server.controller.resources.VersionModelInitializer; import org.jboss.as.server.mgmt.UndertowHttpManagementService; import org.jboss.as.server.services.security.AbstractVaultReader; import org.jboss.dmr.ModelNode; import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceBuilder; import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.ServiceTarget; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; import org.jboss.msc.value.InjectedValue; import org.jboss.threads.AsyncFutureTask; import org.jboss.threads.JBossThreadFactory; import org.wildfly.common.Assert; import org.wildfly.security.manager.WildFlySecurityManager; /** * 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, HostRegistrations { 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(WildFlySecurityManager.getPropertyPrivileged("jboss.as.domain.ping.pool.size", "5")); } catch (Exception e) { // TODO log } finally { PINGER_POOL_SIZE = Math.max(1, poolSize); } } 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 DomainSlaveHostRegistrations slaveHostRegistrations = new DomainSlaveHostRegistrations(); 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 hostExtensionRegistry; private final ExtensionRegistry extensionRegistry; private final ControlledProcessState processState; private final IgnoredDomainResourceRegistry ignoredRegistry; private final PathManagerService pathManager; private final ExpressionResolver expressionResolver; private final DomainDelegatingResourceDefinition rootResourceDefinition; private final CapabilityRegistry capabilityRegistry; private final DomainHostExcludeRegistry domainHostExcludeRegistry; private final AtomicBoolean domainModelComplete = new AtomicBoolean(false); private final PartialModelIndicator partialModelIndicator = new PartialModelIndicator() { @Override public boolean isModelPartial() { return !domainModelComplete.get(); } }; // @GuardedBy(this) private Future<ServerInventory> inventoryFuture; private final AtomicBoolean serverInventoryLock = new AtomicBoolean(); // @GuardedBy(serverInventoryLock), after the HC started reads just use the volatile value private volatile ServerInventory serverInventory; private volatile ScheduledExecutorService pingScheduler; private volatile ManagementResourceRegistration hostModelRegistration; private volatile MasterDomainControllerClient masterDomainControllerClient; static ServiceController<ModelController> addService(final ServiceTarget serviceTarget, final HostControllerEnvironment environment, final HostRunningModeControl runningModeControl, final ControlledProcessState processState, final BootstrapListener bootstrapListener, final PathManagerService pathManager, final CapabilityRegistry capabilityRegistry) { 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 = loadVaultReaderService(); ROOT_LOGGER.debugf("Using VaultReader %s", vaultReader); final ContentRepository contentRepository = ContentRepository.Factory.create(environment.getDomainContentDir(), environment.getDomainTempDir()); final IgnoredDomainResourceRegistry ignoredRegistry = new IgnoredDomainResourceRegistry(hostControllerInfo); final ManagedAuditLogger auditLogger = createAuditLogger(environment); final DelegatingConfigurableAuthorizer authorizer = new DelegatingConfigurableAuthorizer(); final ManagementSecurityIdentitySupplier securityIdentitySupplier = new ManagementSecurityIdentitySupplier(); final RuntimeHostControllerInfoAccessor hostControllerInfoAccessor = new DomainHostControllerInfoAccessor(hostControllerInfo); final ProcessType processType = environment.getProcessType(); final ExtensionRegistry hostExtensionRegistry = new ExtensionRegistry(processType, runningModeControl, auditLogger, authorizer, securityIdentitySupplier, hostControllerInfoAccessor); final ExtensionRegistry extensionRegistry = new ExtensionRegistry(processType, runningModeControl, auditLogger, authorizer, securityIdentitySupplier, hostControllerInfoAccessor); final PrepareStepHandler prepareStepHandler = new PrepareStepHandler(hostControllerInfo, hostProxies, serverProxies, ignoredRegistry, extensionRegistry); final ExpressionResolver expressionResolver = new RuntimeExpressionResolver(vaultReader); final DomainHostExcludeRegistry domainHostExcludeRegistry = new DomainHostExcludeRegistry(); final DomainModelControllerService service = new DomainModelControllerService(environment, runningModeControl, processState, hostControllerInfo, contentRepository, hostProxies, serverProxies, prepareStepHandler, vaultReader, ignoredRegistry, bootstrapListener, pathManager, expressionResolver, new DomainDelegatingResourceDefinition(), hostExtensionRegistry, extensionRegistry, auditLogger, authorizer, securityIdentitySupplier, capabilityRegistry, domainHostExcludeRegistry); HostControllerEnvironmentService.addService(environment, serviceTarget); 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 DomainDelegatingResourceDefinition rootResourceDefinition, final ExtensionRegistry hostExtensionRegistry, final ExtensionRegistry extensionRegistry, final ManagedAuditLogger auditLogger, final DelegatingConfigurableAuthorizer authorizer, final ManagementSecurityIdentitySupplier securityIdentitySupplier, final CapabilityRegistry capabilityRegistry, final DomainHostExcludeRegistry domainHostExcludeRegistry) { super(environment.getProcessType(), runningModeControl, null, processState, rootResourceDefinition, prepareStepHandler, new RuntimeExpressionResolver(vaultReader), auditLogger, authorizer, securityIdentitySupplier, capabilityRegistry); 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.hostExtensionRegistry = hostExtensionRegistry; this.extensionRegistry = extensionRegistry; this.pathManager = pathManager; this.expressionResolver = expressionResolver; this.rootResourceDefinition = rootResourceDefinition; this.capabilityRegistry = capabilityRegistry; this.domainHostExcludeRegistry = domainHostExcludeRegistry; } private static ManagedAuditLogger createAuditLogger(HostControllerEnvironment environment) { return new ManagedAuditLoggerImpl(environment.getProductConfig().resolveVersion(), false); } @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, final Long remoteConnectionId, final boolean registerProxyController) 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()); } final SlaveHostPinger pinger = remoteConnectionId == null ? null : new SlaveHostPinger(hostName, handler, pingScheduler, remoteConnectionId); final String address = handler.getRemoteAddress().getHostAddress(); slaveHostRegistrations.registerHost(hostName, pinger, address); if (registerProxyController) { // Create the proxy controller final TransformingProxyController hostControllerClient = TransformingProxyController.Factory.create(handler, transformers, addr, ProxyOperationAddressTranslator.HOST); modelNodeRegistration.registerProxyController(pe, hostControllerClient); hostProxies.put(hostName, hostControllerClient); } } @Override public boolean isHostRegistered(String id) { final DomainSlaveHostRegistrations.DomainHostConnection registration = slaveHostRegistrations.getRegistration(id); return registration != null && registration.isConnected(); } @Override public void unregisterRemoteHost(String id, Long remoteConnectionId, boolean cleanShutdown) { DomainSlaveHostRegistrations.DomainHostConnection hostRegistration = slaveHostRegistrations.getRegistration(id); if (hostRegistration != null) { if ((remoteConnectionId == null || remoteConnectionId.equals(hostRegistration.getRemoteConnectionId()))) { final SlaveHostPinger pinger = hostRegistration.getPinger(); if (pinger != null) { pinger.cancel(); } boolean registered = hostProxies.remove(id) != null; modelNodeRegistration.unregisterProxyController(PathElement.pathElement(HOST, id)); if (registered) { final String address = hostRegistration.getAddress(); final Event event = cleanShutdown ? create(HostConnectionInfo.EventType.UNREGISTERED, address) : create(HostConnectionInfo.EventType.UNCLEAN_UNREGISTRATION, address); slaveHostRegistrations.unregisterHost(id, event); if (!cleanShutdown) { DOMAIN_LOGGER.lostConnectionToRemoteHost(id); } else { DOMAIN_LOGGER.unregisteredRemoteSlaveHost(id); } } } } } @Override public void addHostEvent(String hostName, Event event) { slaveHostRegistrations.addEvent(hostName, event); } @Override public void pruneExpired() { slaveHostRegistrations.pruneExpired(); } @Override public void pruneDisconnected() { slaveHostRegistrations.pruneDisconnected(); } @Override public HostConnectionInfo getHostInfo(String hostName) { return slaveHostRegistrations.getRegistration(hostName); } @Override public void pingRemoteHost(String id) { DomainSlaveHostRegistrations.DomainHostConnection reg = slaveHostRegistrations.getRegistration(id); if (reg != null && reg.getPinger() != null && !reg.getPinger().isCancelled()) { reg.getPinger().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 HostControllerLogger.ROOT_LOGGER.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 void reportServerInstability(String serverName) { MasterDomainControllerClient mdc = masterDomainControllerClient; if (mdc != null) { mdc.reportServerInstability(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()); operation.get(SERVER_LAUNCH).set(true); 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() : HostControllerLogger.ROOT_LOGGER.failedProfileOperationsRetrieval(); throw new RuntimeException(msg); } return rsp.require(RESULT); } @Override public HostFileRepository getLocalFileRepository() { return localFileRepository; } @Override public HostFileRepository getRemoteFileRepository() { if (hostControllerInfo.isMasterDomainController()) { throw HostControllerLogger.ROOT_LOGGER.cannotAccessRemoteFileRepository(); } return remoteFileRepository; } @Override public void start(StartContext context) throws StartException { final ExecutorService executorService = getExecutorServiceInjector().getValue(); this.hostControllerConfigurationPersister = new HostControllerConfigurationPersister(environment, hostControllerInfo, executorService, hostExtensionRegistry, extensionRegistry); setConfigurationPersister(hostControllerConfigurationPersister); prepareStepHandler.setExecutorService(executorService); ThreadFactory pingerThreadFactory = doPrivileged(new PrivilegedAction<JBossThreadFactory>() { public JBossThreadFactory run() { return new JBossThreadFactory(new ThreadGroup("proxy-pinger-threads"), Boolean.TRUE, null, "%G - %t", null, null); } }); pingScheduler = Executors.newScheduledThreadPool(PINGER_POOL_SIZE, pingerThreadFactory); super.start(context); pingScheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { slaveHostRegistrations.pruneExpired(); } catch (Exception e) { HostControllerLogger.DOMAIN_LOGGER.debugf(e, "failed to execute eviction task"); } } }, 1, 1, TimeUnit.MINUTES); } @Override protected void initModel(ManagementModel managementModel, Resource modelControllerResource) { HostModelUtil.createRootRegistry(managementModel.getRootResourceRegistration(), environment, ignoredRegistry, this, processType, authorizer, modelControllerResource); VersionModelInitializer.registerRootResource(managementModel.getRootResource(), environment != null ? environment.getProductConfig() : null); CoreManagementResourceDefinition.registerDomainResource(managementModel.getRootResource(), authorizer.getWritableAuthorizerConfiguration()); this.modelNodeRegistration = managementModel.getRootResourceRegistration(); // Register the slave host info ResourceProvider.Tool.addResourceProvider(HOST_CONNECTION, new ResourceProvider() { @Override public boolean has(String name) { return slaveHostRegistrations.contains(name); } @Override public Resource get(String name) { return PlaceholderResource.INSTANCE; } @Override public boolean hasChildren() { return true; } @Override public Set<String> children() { return slaveHostRegistrations.getHosts(); } @Override public void register(String name, Resource resource) { throw new UnsupportedOperationException(); } @Override public void register(String value, int index, Resource resource) { } @Override public Resource remove(String name) { throw new UnsupportedOperationException(); } @Override public ResourceProvider clone() { return this; } }, managementModel.getRootResource().getChild(CoreManagementResourceDefinition.PATH_ELEMENT)); } @Override protected OperationStepHandler createExtraValidationStepHandler() { return new OperationStepHandler() { @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { if (!context.isBooting()) { PathAddress addr = context.getCurrentAddress(); if (addr.size() > 0 && addr.getLastElement().getKey().equals(SUBSYSTEM)) { //For subsystem adds in domain mode we need to check that the new subsystem does not break the rule //that when profile includes are used, we don't allow overriding subsystems. DomainModelIncludesValidator.addValidationStep(context, operation); } } } }; } // 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 List<ModelNode> hostBootOps = hostControllerConfigurationPersister.load(); // We run the first op ("add-host") separately to let it set up the host ManagementResourceRegistration ModelNode addHostOp = hostBootOps.remove(0); HostControllerLogger.ROOT_LOGGER.debug("Invoking the initial add-host op"); //Disable model validation here since it will will fail ok = boot(Collections.singletonList(addHostOp), true, true); // Add the controller initialization operation hostBootOps.add(registerModelControllerServiceInitializationBootStep(context)); //Pass in a custom mutable root resource registration provider for the remaining host model ops boot //This will be used to make sure that any extensions added in parallel get registered in the host model if (ok) { HostControllerLogger.ROOT_LOGGER.debug("Invoking remaining host.xml ops"); ok = boot(hostBootOps, true, true, new MutableRootResourceRegistrationProvider() { public ManagementResourceRegistration getRootResourceRegistrationForUpdate(OperationContext context) { return hostModelRegistration; } }); } final RunningMode currentRunningMode = runningModeControl.getRunningMode(); if (ok) { // Now we know our management interface configuration. Install the server inventory Future<ServerInventory> inventoryFuture = installServerInventory(serviceTarget); // Now we know our discovery configuration. List<DiscoveryOption> discoveryOptions = hostControllerInfo.getRemoteDomainControllerDiscoveryOptions(); if (hostControllerInfo.isMasterDomainController() && (discoveryOptions != null)) { // Install the discovery service installDiscoveryService(serviceTarget, discoveryOptions); } boolean useLocalDomainXml = hostControllerInfo.isMasterDomainController(); boolean isCachedDc = environment.isUseCachedDc(); if (!useLocalDomainXml) { // Block for the ServerInventory establishServerInventory(inventoryFuture); boolean discoveryConfigured = (discoveryOptions != null) && !discoveryOptions.isEmpty(); if (currentRunningMode != RunningMode.ADMIN_ONLY) { if (discoveryConfigured) { // Try and connect. // If can't connect && !environment.isUseCachedDc(), abort // Otherwise if can't connect, use local domain.xml and start trying to reconnect later DomainConnectResult connectResult = connectToDomainMaster(serviceTarget, currentRunningMode, isCachedDc, false); if (connectResult == DomainConnectResult.ABORT) { ok = false; } else if (connectResult == DomainConnectResult.FAILED) { useLocalDomainXml = true; } } else { // Invalid configuration; no way to get the domain config ROOT_LOGGER.noDomainControllerConfigurationProvided(currentRunningMode, CommandLineConstants.ADMIN_ONLY, RunningMode.ADMIN_ONLY); SystemExiter.abort(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE); } } else { // We're in admin-only mode. See how we handle access control config // if cached-dc is specified, we try and use the last configuration we have before failing. if (isCachedDc) { useLocalDomainXml = true; } switch (hostControllerInfo.getAdminOnlyDomainConfigPolicy()) { case ALLOW_NO_CONFIG: // our current setup is good, if we're using --cached-dc, we'll try and load the config below // if not, we'll start empty. break; case FETCH_FROM_MASTER: if (discoveryConfigured) { // Try and connect. // If can't connect && !environment.isUseCachedDc(), abort // Otherwise if can't connect, use local domain.xml but DON'T start trying to reconnect later DomainConnectResult connectResult = connectToDomainMaster(serviceTarget, currentRunningMode, isCachedDc, true); ok = connectResult != DomainConnectResult.ABORT; } else { // try and use a local cached version below before failing if (isCachedDc) { break; } // otherwise, this is an invalid configuration; no way to get the domain config ROOT_LOGGER.noDomainControllerConfigurationProvidedForAdminOnly( ModelDescriptionConstants.ADMIN_ONLY_POLICY, AdminOnlyDomainConfigPolicy.REQUIRE_LOCAL_CONFIG, CommandLineConstants.CACHED_DC, RunningMode.ADMIN_ONLY); SystemExiter.abort(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE); break; } break; case REQUIRE_LOCAL_CONFIG: // if we have a cached copy, and --cached-dc we can try to use that below if (isCachedDc) { break; } // otherwise, this is an invalid configuration; no way to get the domain config ROOT_LOGGER.noAccessControlConfigurationAvailable(currentRunningMode, ModelDescriptionConstants.ADMIN_ONLY_POLICY, AdminOnlyDomainConfigPolicy.REQUIRE_LOCAL_CONFIG, CommandLineConstants.CACHED_DC, currentRunningMode); SystemExiter.abort(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE); break; default: throw new IllegalStateException(hostControllerInfo.getAdminOnlyDomainConfigPolicy().toString()); } } } if (useLocalDomainXml) { if (!hostControllerInfo.isMasterDomainController() && isCachedDc) { ROOT_LOGGER.usingCachedDC(CommandLineConstants.CACHED_DC, ConfigurationPersisterFactory.CACHED_DOMAIN_XML); } // 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(); // if we're using --cached-dc, we have to have had a persisted copy of the domain config for this to work // otherwise we fail and can't continue. List<ModelNode> domainBootOps = domainPersister.load(); HostControllerLogger.ROOT_LOGGER.debug("Invoking domain.xml ops"); ok = boot(domainBootOps, false); domainModelComplete.set(ok); if (!ok && runningModeControl.getRunningMode().equals(RunningMode.ADMIN_ONLY)) { ROOT_LOGGER.reportAdminOnlyDomainXmlFailure(); ok = true; } if (ok && processType != ProcessType.EMBEDDED_HOST_CONTROLLER) { InternalExecutor executor = new InternalExecutor(); ManagementRemotingServices.installManagementChannelServices(serviceTarget, ManagementRemotingServices.MANAGEMENT_ENDPOINT, new MasterDomainControllerOperationHandlerService(this, executor, executor, environment.getDomainTempDir(), this, domainHostExcludeRegistry), DomainModelControllerService.SERVICE_NAME, ManagementRemotingServices.DOMAIN_CHANNEL, HostControllerService.HC_EXECUTOR_SERVICE_NAME, HostControllerService.HC_SCHEDULED_EXECUTOR_SERVICE_NAME); // Block for the ServerInventory establishServerInventory(inventoryFuture); } // register local host controller final String hostName = hostControllerInfo.getLocalHostName(); slaveHostRegistrations.registerHost(hostName, null, "local"); } } if (ok && hostControllerInfo.getAdminOnlyDomainConfigPolicy() != AdminOnlyDomainConfigPolicy.ALLOW_NO_CONFIG) { final ModelNode validate = new ModelNode(); validate.get(OP).set("validate"); validate.get(OP_ADDR).setEmptyList(); final ModelNode result = internalExecute(OperationBuilder.create(validate).build(), OperationMessageHandler.DISCARD, OperationTransactionControl.COMMIT, new OperationStepHandler() { @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { DomainModelIncludesValidator.validateAtBoot(context, operation); } }).getResponseNode(); if (!SUCCESS.equals(result.get(OUTCOME).asString())) { throw new OperationFailedException(result.get(FAILURE_DESCRIPTION)); } } if (ok && processType != ProcessType.EMBEDDED_HOST_CONTROLLER) { // Install the server > host operation handler ServerToHostOperationHandlerFactoryService.install(serviceTarget, ServerInventoryService.SERVICE_NAME, getExecutorServiceInjector().getValue(), new InternalExecutor(), this, expressionResolver, environment.getDomainTempDir()); // 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 Notification notification = new Notification(ModelDescriptionConstants.BOOT_COMPLETE_NOTIFICATION, PathAddress.pathAddress(PathElement.pathElement(CORE_SERVICE, MANAGEMENT), PathElement.pathElement(SERVICE, MANAGEMENT_OPERATIONS)), ControllerLogger.MGMT_OP_LOGGER.bootComplete()); getNotificationSupport().emit(notification); bootstrapListener.printBootStatistics(); } } else { // Die! String failed = ROOT_LOGGER.unsuccessfulBoot(); ROOT_LOGGER.fatal(failed); bootstrapListener.bootFailure(failed); // don't exit if we're embedded if (processType != ProcessType.EMBEDDED_HOST_CONTROLLER) { SystemExiter.abort(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE); } } } } @Override protected final PartialModelIndicator getPartialModelIndicator() { return partialModelIndicator; } private Future<ServerInventory> installServerInventory(final ServiceTarget serviceTarget) { if (hostControllerInfo.getHttpManagementSecureInterface() != null && !hostControllerInfo.getHttpManagementSecureInterface().isEmpty() && hostControllerInfo.getHttpManagementSecurePort() > 0) { return ServerInventoryService.install(serviceTarget, this, runningModeControl, environment, extensionRegistry, hostControllerInfo.getHttpManagementSecureInterface(), hostControllerInfo.getHttpManagementSecurePort(), REMOTE_HTTPS.toString()); } if (hostControllerInfo.getNativeManagementInterface() != null && !hostControllerInfo.getNativeManagementInterface().isEmpty() && hostControllerInfo.getNativeManagementPort() > 0) { return ServerInventoryService.install(serviceTarget, this, runningModeControl, environment, extensionRegistry, hostControllerInfo.getNativeManagementInterface(), hostControllerInfo.getNativeManagementPort(), REMOTE.toString()); } if (processType == ProcessType.EMBEDDED_HOST_CONTROLLER) { return getPlaceHolderInventory(); } return ServerInventoryService.install(serviceTarget, this, runningModeControl, environment, extensionRegistry, hostControllerInfo.getHttpManagementInterface(), hostControllerInfo.getHttpManagementPort(), REMOTE_HTTP.toString()); } private void installDiscoveryService(final ServiceTarget serviceTarget, List<DiscoveryOption> discoveryOptions) { List<DomainControllerManagementInterface> interfaces = new ArrayList<>(); if (hostControllerInfo.getNativeManagementInterface() != null && !hostControllerInfo.getNativeManagementInterface().isEmpty() && hostControllerInfo.getNativeManagementPort() > 0) { interfaces.add(new DomainControllerManagementInterface(hostControllerInfo.getNativeManagementPort(), hostControllerInfo.getNativeManagementInterface(), REMOTE)); } if (hostControllerInfo.getHttpManagementSecureInterface() != null && !hostControllerInfo.getHttpManagementSecureInterface().isEmpty() && hostControllerInfo.getHttpManagementSecurePort() > 0) { interfaces.add(new DomainControllerManagementInterface(hostControllerInfo.getHttpManagementSecurePort(), hostControllerInfo.getHttpManagementSecureInterface(), REMOTE_HTTPS)); } if (hostControllerInfo.getHttpManagementInterface() != null && !hostControllerInfo.getHttpManagementInterface().isEmpty() && hostControllerInfo.getHttpManagementPort() > 0) { interfaces.add(new DomainControllerManagementInterface(hostControllerInfo.getHttpManagementPort(), hostControllerInfo.getHttpManagementInterface(), REMOTE_HTTP)); } DiscoveryService.install(serviceTarget, discoveryOptions, interfaces, hostControllerInfo.isMasterDomainController()); } private enum DomainConnectResult { CONNECTED, FAILED, ABORT } private DomainConnectResult connectToDomainMaster(ServiceTarget serviceTarget, RunningMode currentRunningMode, boolean usingCachedDC, boolean adminOnly) { Future<MasterDomainControllerClient> clientFuture = RemoteDomainConnectionService.install(serviceTarget, getValue(), extensionRegistry, hostControllerInfo, hostControllerInfo.getRemoteDomainControllerSecurityRealm(), remoteFileRepository, contentRepository, ignoredRegistry, new DomainModelControllerService.InternalExecutor(), this, environment, getExecutorServiceInjector().getValue(), currentRunningMode, serverProxies, domainModelComplete); masterDomainControllerClient = getFuture(clientFuture); //Registers us with the master and gets down the master copy of the domain model to our DC // if --cached-dc is used and the DC is unavailable, we'll use a cached copy of the domain config // (if available), and poll for reconnection to the DC. Once the DC becomes available again, the domain // config will be re-synchronized. try { masterDomainControllerClient.register(); return DomainConnectResult.CONNECTED; } catch (Exception e) { //We could not connect to the host ROOT_LOGGER.cannotConnectToMaster(e); if (!usingCachedDC) { if (currentRunningMode == RunningMode.ADMIN_ONLY) { ROOT_LOGGER.fetchConfigFromDomainMasterFailed(currentRunningMode, ModelDescriptionConstants.ADMIN_ONLY_POLICY, AdminOnlyDomainConfigPolicy.REQUIRE_LOCAL_CONFIG, CommandLineConstants.CACHED_DC); } SystemExiter.abort(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE); // If we got here, the Exiter didn't really exit. Must be embedded. // Inform the caller so it knows not to proceed with boot. return DomainConnectResult.ABORT; } else if (!adminOnly) { // Register a service that will try again once we reach RUNNING state DeferredDomainConnectService.install(serviceTarget, masterDomainControllerClient); } return DomainConnectResult.FAILED; } } @Override protected ModelControllerServiceInitializationParams getModelControllerServiceInitializationParams() { final ServiceLoader<ModelControllerServiceInitialization> sl = ServiceLoader.load(ModelControllerServiceInitialization.class); return new ModelControllerServiceInitializationParams(sl) { @Override public String getHostName() { return hostControllerInfo.getLocalHostName(); } }; } private void establishServerInventory(Future<ServerInventory> future) { DelegatingServerInventory dse = new DelegatingServerInventory(); synchronized (serverInventoryLock) { try { serverInventory = getFuture(future); serverInventoryLock.set(true); } finally { serverInventoryLock.notifyAll(); } } } 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) { synchronized (serverInventoryLock) { try { serverInventory = null; serverInventoryLock.set(false); } finally { serverInventoryLock.notifyAll(); } } extensionRegistry.clear(); domainModelComplete.set(false); super.stop(context); } protected void stopAsynchronous(StopContext context) { pingScheduler.shutdownNow(); } @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 HostControllerLogger.ROOT_LOGGER.errorClosingDownHost(e); } } @Override public void registerHostModel(String hostName, ManagementResourceRegistration root) { hostModelRegistration = HostModelUtil.createHostRegistry(hostName, root, hostControllerConfigurationPersister, environment, runningModeControl, localFileRepository, hostControllerInfo, new DelegatingServerInventory(), remoteFileRepository, contentRepository, this, hostExtensionRegistry, extensionRegistry, vaultReader, ignoredRegistry, processState, pathManager, authorizer, securityIdentitySupplier, getAuditLogger(), getBootErrorCollector()); } 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, authorizer, securityIdentitySupplier, this, domainHostExcludeRegistry, getMutableRootResourceRegistrationProvider()); rootResourceDefinition.setDelegate(domainRootDefinition, root); } private class DelegatingServerInventory implements ServerInventory { /* * WFLY-2370. Max period a caller to this class can wait for boot ops to complete * in the ModelController and boot moves on to starting the ServerInventory. * Generally this should be a very small window, as the boot ops install * very few services other than the management interface that would * let user requests hit this class in the first place. */ private static final long SERVER_INVENTORY_TIMEOUT = 10000; private synchronized ServerInventory getServerInventory() { if (processType == ProcessType.EMBEDDED_HOST_CONTROLLER) { return getServerInventory(true); } return getServerInventory(false); } private synchronized ServerInventory getServerInventory(boolean placeHolder) { try { if (placeHolder) { return getPlaceHolderInventory().get(); } } catch (Exception e) { throw new RuntimeException(e); } ServerInventory result = null; synchronized (serverInventoryLock) { if (serverInventoryLock.get()) { // Usual case result = serverInventory; } else { try { serverInventoryLock.wait(SERVER_INVENTORY_TIMEOUT); if (serverInventoryLock.get()) { result = serverInventory; } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } if (result == null) { // Odd case. TODO i18n message throw new IllegalStateException(); } return result; } @Override public ProxyController serverCommunicationRegistered(String serverProcessName, ManagementChannelHandler channelHandler) { return getServerInventory().serverCommunicationRegistered(serverProcessName, channelHandler); } @Override public boolean serverReconnected(String serverProcessName, ManagementChannelHandler channelHandler) { return getServerInventory().serverReconnected(serverProcessName, channelHandler); } @Override public void serverProcessAdded(String serverProcessName) { getServerInventory().serverProcessAdded(serverProcessName); } @Override public void serverStartFailed(String serverProcessName) { getServerInventory().serverStartFailed(serverProcessName); } @Override public void serverUnstable(String serverProcessName) { getServerInventory().serverUnstable(serverProcessName); } @Override public void serverStarted(String serverProcessName) { getServerInventory().serverStarted(serverProcessName); } @Override public void serverProcessStopped(String serverProcessName) { getServerInventory().serverProcessStopped(serverProcessName); } @Override public String getServerProcessName(String serverName) { return getServerInventory().getServerProcessName(serverName); } @Override public String getProcessServerName(String processName) { return getServerInventory().getProcessServerName(processName); } @Override public ServerStatus reloadServer(String serverName, boolean blocking, boolean suspend) { return getServerInventory().reloadServer(serverName, blocking, suspend); } @Override public void processInventory(Map<String, ProcessInfo> processInfos) { getServerInventory().processInventory(processInfos); } @Override public Map<String, ProcessInfo> determineRunningProcesses() { return getServerInventory().determineRunningProcesses(); } @Override public Map<String, ProcessInfo> determineRunningProcesses(boolean serversOnly) { return getServerInventory().determineRunningProcesses(serversOnly); } @Override public ServerStatus determineServerStatus(String serverName) { return getServerInventory().determineServerStatus(serverName); } @Override public ServerStatus startServer(String serverName, ModelNode domainModel) { return getServerInventory().startServer(serverName, domainModel); } @Override public ServerStatus startServer(String serverName, ModelNode domainModel, boolean blocking, boolean suspend) { return getServerInventory().startServer(serverName, domainModel, blocking, suspend); } @Override public void reconnectServer(String serverName, ModelNode domainModel, String authKey, boolean running, boolean stopping) { getServerInventory().reconnectServer(serverName, domainModel, authKey, running, stopping); } @Override public ServerStatus restartServer(String serverName, int gracefulTimeout, ModelNode domainModel) { return getServerInventory().restartServer(serverName, gracefulTimeout, domainModel); } @Override public ServerStatus restartServer(String serverName, int gracefulTimeout, ModelNode domainModel, boolean blocking, boolean suspend) { return getServerInventory().restartServer(serverName, gracefulTimeout, domainModel, blocking, suspend); } @Override public ServerStatus stopServer(String serverName, int gracefulTimeout) { return getServerInventory().stopServer(serverName, gracefulTimeout); } @Override public ServerStatus stopServer(String serverName, int gracefulTimeout, boolean blocking) { return getServerInventory().stopServer(serverName, gracefulTimeout, blocking); } @Override public CallbackHandler getServerCallbackHandler() { return getServerInventory().getServerCallbackHandler(); } @Override public void stopServers(int gracefulTimeout) { getServerInventory().stopServers(gracefulTimeout); } @Override public void stopServers(int gracefulTimeout, boolean blockUntilStopped) { getServerInventory().stopServers(gracefulTimeout, blockUntilStopped); } @Override public void connectionFinished() { getServerInventory().connectionFinished(); } @Override public void serverProcessStarted(String processName) { getServerInventory().serverProcessStarted(processName); } @Override public void serverProcessRemoved(String processName) { getServerInventory().serverProcessRemoved(processName); } @Override public void operationFailed(String processName, ProcessMessageHandler.OperationType type) { getServerInventory().operationFailed(processName, type); } @Override public void destroyServer(String serverName) { getServerInventory().destroyServer(serverName); } @Override public void killServer(String serverName) { getServerInventory().killServer(serverName); } @Override public void awaitServersState(Collection<String> serverNames, boolean started) { getServerInventory().awaitServersState(serverNames, started); } @Override public List<ModelNode> suspendServers(Set<String> serverNames, BlockingTimeout blockingTimeout) { return getServerInventory().suspendServers(serverNames, blockingTimeout); } @Override public List<ModelNode> resumeServers(Set<String> serverNames, BlockingTimeout blockingTimeout) { return getServerInventory().resumeServers(serverNames, blockingTimeout); } @Override public List<ModelNode> suspendServers(Set<String> serverNames, int timeout, BlockingTimeout blockingTimeout) { return getServerInventory().suspendServers(serverNames, timeout, blockingTimeout); } } private static AbstractVaultReader loadVaultReaderService() { final ServiceLoader<AbstractVaultReader> serviceLoader = ServiceLoader.load(AbstractVaultReader.class, DomainModelControllerService.class.getClassLoader()); final Iterator<AbstractVaultReader> it = serviceLoader.iterator(); // TODO WFCORE-114 get rid of catching/suppressing errors once we have a complete impl in WFCORE ServiceConfigurationError sce = null; try { while (it.hasNext()) { return it.next(); } } catch (ServiceConfigurationError e) { sce = e; } if (sce != null) { DomainControllerLogger.HOST_CONTROLLER_LOGGER.debugf(sce, "Cannot instantiate provider of service %s", AbstractVaultReader.class); } return null; } @Override public ExtensionRegistry getExtensionRegistry() { return extensionRegistry; } @Override public ImmutableCapabilityRegistry getCapabilityRegistry() { return capabilityRegistry; } @Override public ExpressionResolver getExpressionResolver() { return expressionResolver; } private static class DomainDelegatingResourceDefinition extends org.jboss.as.controller.DelegatingResourceDefinition{ void setDelegate(DomainRootDefinition delegate, ManagementResourceRegistration root) { super.setDelegate(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 void registerNotifications(ManagementResourceRegistration resourceRegistration) { //These will be registered later } } final class InternalExecutor implements HostControllerRegistrationHandler.OperationExecutor, ServerToHostProtocolHandler.OperationExecutor, MasterDomainControllerOperationHandlerService.TransactionalOperationExecutor { @Override public ModelNode execute(Operation operation, OperationMessageHandler handler, OperationTransactionControl control, OperationStepHandler step) { return internalExecute(operation, handler, control, step).getResponseNode(); } @Override public ModelNode installSlaveExtensions(List<ModelNode> extensions) { Operation operation = ApplyExtensionsHandler.getOperation(extensions); OperationStepHandler stepHandler = modelNodeRegistration.getOperationHandler(PathAddress.EMPTY_ADDRESS, ApplyExtensionsHandler.OPERATION_NAME); return internalExecute(operation, OperationMessageHandler.logging, OperationTransactionControl.COMMIT, stepHandler, false, true).getResponseNode(); } @Override @SuppressWarnings("deprecation") public ModelNode joinActiveOperation(ModelNode operation, OperationMessageHandler handler, OperationTransactionControl control, OperationStepHandler step, int permit) { return executeReadOnlyOperation(operation, handler, control, step, permit); } @Override public OperationResponse executeAndAttemptLock(Operation operation, OperationMessageHandler handler, OperationTransactionControl control, OperationStepHandler step) { return internalExecute(operation, handler, control, step, true); } @Override public ModelNode executeReadOnly(ModelNode operation, OperationStepHandler handler, OperationTransactionControl control) { return executeReadOnlyOperation(operation, control, handler); } @Override public ModelNode executeReadOnly(ModelNode operation, Resource model, OperationStepHandler handler, OperationTransactionControl control) { return executeReadOnlyOperation(operation, model, control, handler); } @Override public void acquireReadlock(final Integer operationID) throws IllegalArgumentException, InterruptedException { Assert.checkNotNullParam("operationID", operationID); // acquire a read (shared mode) lock for this registration, released in releaseReadlock acquireReadLock(operationID); } @Override public void releaseReadlock(final Integer operationID) throws IllegalArgumentException { Assert.checkNotNullParam("operationID", operationID); releaseReadLock(operationID); } } private static final class DomainHostControllerInfoAccessor implements RuntimeHostControllerInfoAccessor { private final LocalHostControllerInfoImpl hostControllerInfo; public DomainHostControllerInfoAccessor(LocalHostControllerInfoImpl hostControllerInfo) { this.hostControllerInfo = hostControllerInfo; } @Override public HostControllerInfo getHostControllerInfo(OperationContext context) throws OperationFailedException { if (context.isBooting() && context.getCurrentStage() == OperationContext.Stage.MODEL) { throw ControllerLogger.ROOT_LOGGER.onlyAccessHostControllerInfoInRuntimeStage(); } return new HostControllerInfo() { public boolean isMasterHc() { return hostControllerInfo.isMasterDomainController(); } }; } } private class FutureServerInventory extends AsyncFutureTask<ServerInventory>{ public FutureServerInventory() { super(null); } private void setInventory(ServerInventory inventory) { super.setResult(inventory); } private void setFailure(final Throwable t) { super.setFailed(t); } } // this is a placeholder object used in certain cases where the live inventory is not available // e.g. offline embedded mode private FutureServerInventory getPlaceHolderInventory() { FutureServerInventory future = new FutureServerInventory(); ServerInventory inventory = new ServerInventory() { @Override public String getServerProcessName(String serverName) { return ManagedServer.getServerProcessName(serverName); } @Override public String getProcessServerName(String processName) { return ManagedServer.getServerName(processName); } @Override public Map<String, ProcessInfo> determineRunningProcesses() { return Collections.emptyMap(); } @Override public Map<String, ProcessInfo> determineRunningProcesses(boolean serversOnly) { return Collections.emptyMap(); } @Override public ServerStatus determineServerStatus(String serverName) { return ServerStatus.STOPPED; } @Override public ServerStatus startServer(String serverName, ModelNode domainModel) { return ServerStatus.STOPPED; } @Override public ServerStatus startServer(String serverName, ModelNode domainModel, boolean blocking, boolean suspend) { return ServerStatus.STOPPED; } @Override public ServerStatus restartServer(String serverName, int gracefulTimeout, ModelNode domainModel) { return ServerStatus.STOPPED; } @Override public ServerStatus restartServer(String serverName, int gracefulTimeout, ModelNode domainModel, boolean blocking, boolean suspend) { return ServerStatus.STOPPED; } @Override public ServerStatus stopServer(String serverName, int gracefulTimeout) { return ServerStatus.STARTED; } @Override public ServerStatus stopServer(String serverName, int gracefulTimeout, boolean blocking) { return ServerStatus.STARTED; } @Override public void stopServers(int gracefulTimeout) { } @Override public void stopServers(int gracefulTimeout, boolean blockUntilStopped) { } @Override public void reconnectServer(String serverName, ModelNode domainModel, String authKey, boolean running, boolean stopping) { } @Override public ServerStatus reloadServer(String serverName, boolean blocking, boolean suspend) { return ServerStatus.STOPPED; } @Override public void destroyServer(String serverName) { } @Override public void killServer(String serverName) { } @Override public CallbackHandler getServerCallbackHandler() { CallbackHandler callback = new CallbackHandler() { @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { } }; return callback; } @Override public ProxyController serverCommunicationRegistered(String serverProcessName, ManagementChannelHandler channelHandler) { return new ProxyController() { @Override public PathAddress getProxyNodeAddress() { return null; } @Override public void execute(ModelNode operation, OperationMessageHandler handler, ProxyOperationControl control, OperationAttachments attachments, BlockingTimeout blockingTimeout) { } }; } @Override public boolean serverReconnected(String serverProcessName, ManagementChannelHandler channelHandler) { return true; } @Override public void serverStarted(String serverProcessName) { } @Override public void serverStartFailed(String serverProcessName) { } @Override public void serverUnstable(String serverProcessName) { } @Override public void serverProcessStopped(String serverProcessName) { } @Override public void connectionFinished() { } @Override public void serverProcessAdded(String processName) { } @Override public void serverProcessStarted(String processName) { } @Override public void serverProcessRemoved(String processName) { } @Override public void operationFailed(String processName, ProcessMessageHandler.OperationType type) { } @Override public void processInventory(Map<String, ProcessInfo> processInfos) { } @Override public void awaitServersState(Collection<String> serverNames, boolean started) { } @Override public List<ModelNode> suspendServers(Set<String> serverNames, BlockingTimeout blockingTimeout) { return Collections.emptyList(); } @Override public List<ModelNode> resumeServers(Set<String> serverNames, BlockingTimeout blockingTimeout) { return Collections.emptyList(); } @Override public List<ModelNode> suspendServers(Set<String> serverNames, int timeout, BlockingTimeout blockingTimeout) { return Collections.emptyList(); } }; future.setInventory(inventory); return future; } private static class DeferredDomainConnectService implements Service<Void>, PropertyChangeListener { private final MasterDomainControllerClient domainControllerClient; private final InjectedValue<ControlledProcessStateService> injectedValue = new InjectedValue<>(); private boolean activated; private volatile Cancellable connectionFuture; private static void install(ServiceTarget target, MasterDomainControllerClient domainControllerClient) { DeferredDomainConnectService service = new DeferredDomainConnectService(domainControllerClient); target.addService(DomainModelControllerService.SERVICE_NAME.append("deferred-domain-connect"), service) .addDependency(ControlledProcessStateService.SERVICE_NAME, ControlledProcessStateService.class, service.injectedValue) .install(); } private DeferredDomainConnectService(MasterDomainControllerClient domainControllerClient) { this.domainControllerClient = domainControllerClient; } @Override public void start(StartContext context) throws StartException { ControlledProcessStateService cpss = injectedValue.getValue(); cpss.addPropertyChangeListener(this); } @Override public void stop(StopContext context) { Cancellable toCancel = connectionFuture; if (toCancel != null) { toCancel.cancel(); } } @Override public Void getValue() throws IllegalStateException, IllegalArgumentException { return null; } @Override public void propertyChange(PropertyChangeEvent evt) { ControlledProcessState.State newState = (ControlledProcessState.State) evt.getNewValue(); if (newState == ControlledProcessState.State.RUNNING) { boolean callReconnect; synchronized (this) { callReconnect = !activated; activated = true; } if (callReconnect) { connectionFuture = domainControllerClient.pollForConnect(); } } } } }