/* * RHQ Management Platform * Copyright (C) 2005-2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.plugins.sshd; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Set; import net.augeas.Augeas; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.PropertyList; import org.rhq.core.domain.configuration.PropertyMap; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; import org.rhq.core.domain.configuration.definition.PropertyDefinition; import org.rhq.core.domain.configuration.definition.PropertyDefinitionList; import org.rhq.core.domain.configuration.definition.PropertyDefinitionMap; import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple; import org.rhq.core.domain.configuration.definition.PropertySimpleType; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.measurement.MeasurementDataNumeric; import org.rhq.core.domain.measurement.MeasurementReport; import org.rhq.core.domain.measurement.MeasurementScheduleRequest; import org.rhq.core.pluginapi.configuration.ConfigurationFacet; import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport; import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; import org.rhq.core.pluginapi.inventory.ResourceComponent; import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.pluginapi.measurement.MeasurementFacet; import org.rhq.core.pluginapi.util.ObjectUtil; import org.rhq.core.system.AggregateProcessInfo; import org.rhq.core.system.NetworkStats; import org.rhq.core.system.ProcessInfo; import org.rhq.core.system.ProcessInfo.ProcessInfoSnapshot; import org.rhq.core.util.exception.ThrowableUtil; /** * @author Greg Hinkle */ public class OpenSSHDComponent implements ResourceComponent, ConfigurationFacet, MeasurementFacet { private static final Log log = LogFactory.getLog(OpenSSHDComponent.class); private ResourceContext resourceContext; private AggregateProcessInfo processInfo; @Override public void start(ResourceContext resourceContext) throws InvalidPluginConfigurationException, Exception { this.resourceContext = resourceContext; this.processInfo = getSSHDProcess(); } @Override public void stop() { } @Override public AvailabilityType getAvailability() { try { // Get a fresh snapshot of the process ProcessInfoSnapshot processInfoSnapshot = (this.processInfo == null) ? null : this.processInfo .freshSnapshot(); if (processInfoSnapshot == null || !processInfoSnapshot.isRunning()) { this.processInfo = getSSHDProcess(); // Safe to get prior snapshot here, we've just recreated the process info instance processInfoSnapshot = (this.processInfo == null) ? null : this.processInfo.priorSnaphot(); } return (this.processInfo != null && processInfoSnapshot.isRunning()) ? AvailabilityType.UP : AvailabilityType.DOWN; } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("failed to get availability: " + ThrowableUtil.getAllMessages(e)); } return AvailabilityType.DOWN; } } private AggregateProcessInfo getSSHDProcess() { List<ProcessInfo> procs = resourceContext.getSystemInformation().getProcesses( "process|basename|match=sshd,process|basename|nomatch|parent=sshd"); if (procs.size() == 1) { return procs.get(0).getAggregateProcessTree(); } return null; } @Override public Configuration loadResourceConfiguration() throws Exception { Configuration pluginConfiguration = resourceContext.getPluginConfiguration(); ConfigurationDefinition resourceConfigurationDefinition = resourceContext.getResourceType() .getResourceConfigurationDefinition(); return loadResourceConfiguration(pluginConfiguration, resourceConfigurationDefinition); } /** * Performs the actual loading of a SSHD resource configuration. This method makes no calls to the resource * context or any of the instance variables populated by this component's startup to facilitate testing. * * @param pluginConfiguration contains values on how to retrieve the configuration * @param resourceConfigurationDefinition from the plugin descriptor, this describes the properties to retrieve * * @return values describing the configuration of the SSHD process * * @throws Exception if the augeas configuration is incorrect and the configuration cannot be loaded */ public Configuration loadResourceConfiguration(Configuration pluginConfiguration, ConfigurationDefinition resourceConfigurationDefinition) throws Exception { // Gather data necessary to create the Augeas hook PropertySimple lensesPathProperty = pluginConfiguration.getSimple("lenses-path"); if (lensesPathProperty == null) { throw new Exception("Lenses path not found in plugin configuration, cannot retrieve configuration"); } PropertySimple rootPathProperty = pluginConfiguration.getSimple("root-path"); if (rootPathProperty == null) { throw new Exception("Root path not found in plugin configuration, cannot retrieve configuration"); } String lensesPath = lensesPathProperty.getStringValue(); String rootPath = rootPathProperty.getStringValue(); // Find out where to look for sshd configuration files PropertySimple sshdPathProperty = pluginConfiguration.getSimple("config-path"); if (sshdPathProperty == null) { throw new Exception( "SSHD configuration path not found in plugin configuration, cannot retrive configuration"); } String sshdPath = sshdPathProperty.getStringValue(); // Usage of this value expects it to end with a slash, so make sure it's here if (!sshdPath.endsWith("/")) { sshdPath += "/"; } Augeas augeas = new Augeas(rootPath, lensesPath, Augeas.NONE); try { return getConfig(resourceConfigurationDefinition, sshdPath, augeas); } finally { augeas.close(); } } protected Configuration getConfig(ConfigurationDefinition resourceConfigurationDefinition, String sshdPath, Augeas augeas) throws Exception { List<String> matches = augeas.match(sshdPath + "*"); if (matches.size() == 0) { throw new Exception("Unable to load sshd_config data from augeas"); } Collection<PropertyDefinition> properties = resourceConfigurationDefinition.getPropertyDefinitions().values(); Configuration config = new Configuration(); config.setNotes("Loaded from Augeas at " + new Date()); for (PropertyDefinition p : properties) { if (p instanceof PropertyDefinitionSimple) { PropertyDefinitionSimple property = (PropertyDefinitionSimple) p; String value = augeas.get(sshdPath + property.getName()); if (value == null) continue; if (property.getType() == PropertySimpleType.BOOLEAN) { config.put(new PropertySimple(property.getName(), value.equalsIgnoreCase("yes"))); } else { config.put(new PropertySimple(property.getName(), value)); } } else if (p instanceof PropertyDefinitionList) { // This very hackish bit of code is to suport the list-of-maps standard with a single simple definition in the map PropertyDefinitionList listDef = ((PropertyDefinitionList) p); PropertyDefinitionMap mapDef = ((PropertyDefinitionMap) listDef.getMemberDefinition()); PropertyDefinitionSimple simpleDef = (PropertyDefinitionSimple) mapDef.getPropertyDefinitions().get(0); String name = simpleDef.getName(); List<String> allValues = new ArrayList<String>(); List<String> tests = augeas.match(sshdPath + "*"); for (String test : tests) { if (test.matches(sshdPath + name + ".*")) { String data = augeas.get(test); allValues.addAll(Arrays.asList(data.split(" "))); } } PropertyList list = new PropertyList(listDef.getName()); for (String value : allValues) { PropertyMap map = new PropertyMap(mapDef.getName(), new PropertySimple(simpleDef.getName(), value)); list.add(map); } } } return config; } @Override public void updateResourceConfiguration(ConfigurationUpdateReport report) { } @Override public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception { NetworkStats stats = resourceContext.getSystemInformation().getNetworkStats("localhost", 22); processInfo.refresh(); for (MeasurementScheduleRequest request : metrics) { if (request.getName().startsWith("NetworkStat.")) { int val = stats.getByName(request.getName().substring("NetworkStat.".length())); report.addData(new MeasurementDataNumeric(request, (double) val)); } else if (request.getName().startsWith("Process.")) { Double value = ObjectUtil.lookupDeepNumericAttributeProperty(processInfo, request.getName().substring("Process.".length())); report.addData(new MeasurementDataNumeric(request, value)); } } } }