/** * Copyright 2015-2016 Red Hat, Inc, and individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wildfly.swarm.monitor.runtime; import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.enterprise.inject.Vetoed; import org.jboss.as.controller.ModelController; import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.as.domain.management.SecurityRealm; import org.jboss.as.server.ServerEnvironment; import org.jboss.dmr.ModelNode; import org.jboss.logging.Logger; import org.jboss.msc.inject.Injector; import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceName; 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.wildfly.swarm.SwarmInfo; import org.wildfly.swarm.monitor.HealthMetaData; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FAILURE_DESCRIPTION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS; /** * @author Heiko Braun * @since 19/02/16 */ @Vetoed public class MonitorService implements Monitor, Service<MonitorService> { private static Logger LOG = Logger.getLogger("org.wildfly.swarm.monitor.health"); private static final String SELECT = "select"; public static final ServiceName SERVICE_NAME = ServiceName.of("swarm", "monitor"); public MonitorService(Optional<String> securityRealm) { this.securityRealm = securityRealm; } @Override public long getProbeTimeoutSeconds() { return DEFAULT_PROBE_TIMEOUT_SECONDS; } @Override public void start(StartContext startContext) throws StartException { executorService = Executors.newSingleThreadExecutor(); serverEnvironment = serverEnvironmentValue.getValue(); controllerClient = modelControllerValue.getValue().createClient(executorService); if (!securityRealm.isPresent()) { LOG.warn("You are running the monitoring endpoints without any security realm configuration!"); } } @Override public void stop(StopContext stopContext) { if (executorService != null) { executorService.shutdownNow(); } } @Override public MonitorService getValue() throws IllegalStateException, IllegalArgumentException { return this; } @Override public ModelNode getNodeInfo() { ModelNode op = new ModelNode(); op.get(ADDRESS).setEmptyList(); op.get(OP).set("query"); op.get(SELECT).add("name"); op.get(SELECT).add("server-state"); op.get(SELECT).add("suspend-state"); op.get(SELECT).add("running-mode"); op.get(SELECT).add("uuid"); try { ModelNode response = controllerClient.execute(op); ModelNode unwrapped = unwrap(response); unwrapped.get("swarm-version").set(SwarmInfo.VERSION); return unwrapped; } catch (IOException e) { return new ModelNode().get(FAILURE_DESCRIPTION).set(e.getMessage()); } } @Override public ModelNode heap() { // /core-service=platform-mbean/type=memory:read-resource(include-runtime=true) ModelNode op = new ModelNode(); op.get(ADDRESS).add("core-service", "platform-mbean"); op.get(ADDRESS).add("type", "memory"); op.get(OP).set("query"); op.get(SELECT).add("heap-memory-usage"); op.get(SELECT).add("non-heap-memory-usage"); try { ModelNode response = controllerClient.execute(op); return unwrap(response); } catch (IOException e) { return new ModelNode().get(FAILURE_DESCRIPTION).set(e.getMessage()); } } @Override public ModelNode threads() { // /core-service=platform-mbean/type=threading:read-resource(include-runtime=true) ModelNode op = new ModelNode(); op.get(ADDRESS).add("core-service", "platform-mbean"); op.get(ADDRESS).add("type", "threading"); op.get(OP).set("query"); op.get(SELECT).add("thread-count"); op.get(SELECT).add("peak-thread-count"); op.get(SELECT).add("total-started-thread-count"); op.get(SELECT).add("current-thread-cpu-time"); op.get(SELECT).add("current-thread-user-time"); try { ModelNode response = controllerClient.execute(op); return unwrap(response); } catch (IOException e) { return new ModelNode().get(FAILURE_DESCRIPTION).set(e.getMessage()); } } @Override public void registerHealth(HealthMetaData metaData) { LOG.info("Adding /health endpoint delegate: " + metaData.getWebContext()); this.endpoints.add(metaData); } @Override public List<HealthMetaData> getHealthURIs() { return Collections.unmodifiableList(this.endpoints); } @Override public Optional<SecurityRealm> getSecurityRealm() { if (securityRealm.isPresent() && null == securityRealmServiceValue.getOptionalValue()) { throw new RuntimeException("A security realm has been specified, but has not been configured: " + securityRealm.get()); } return securityRealmServiceValue.getOptionalValue() != null ? Optional.of(securityRealmServiceValue.getValue()) : Optional.empty(); } private static ModelNode unwrap(ModelNode response) { if (response.get(OUTCOME).asString().equals(SUCCESS)) { return response.get(RESULT); } else { return response; } } public Injector<ServerEnvironment> getServerEnvironmentInjector() { return this.serverEnvironmentValue; } public Injector<ModelController> getModelControllerInjector() { return this.modelControllerValue; } public Injector<SecurityRealm> getSecurityRealmInjector() { return this.securityRealmServiceValue; } private static final long DEFAULT_PROBE_TIMEOUT_SECONDS = 2; private final InjectedValue<ServerEnvironment> serverEnvironmentValue = new InjectedValue<ServerEnvironment>(); private final InjectedValue<ModelController> modelControllerValue = new InjectedValue<ModelController>(); private final InjectedValue<SecurityRealm> securityRealmServiceValue = new InjectedValue<SecurityRealm>(); private final Optional<String> securityRealm; private ExecutorService executorService; private ServerEnvironment serverEnvironment; private ModelControllerClient controllerClient; private CopyOnWriteArrayList<HealthMetaData> endpoints = new CopyOnWriteArrayList<HealthMetaData>(); }