/* * RHQ Management Platform * Copyright (C) 2005-2009 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.augeas; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import net.augeas.Augeas; import net.augeas.AugeasException; import net.augeas.jna.Aug; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.rhq.augeas.util.Glob; import org.rhq.core.domain.configuration.AbstractPropertyMap; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.ConfigurationUpdateStatus; import org.rhq.core.domain.configuration.Property; 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.resource.CreateResourceStatus; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.pluginapi.configuration.ConfigurationFacet; import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport; import org.rhq.core.pluginapi.inventory.CreateChildResourceFacet; import org.rhq.core.pluginapi.inventory.CreateResourceReport; import org.rhq.core.pluginapi.inventory.DeleteResourceFacet; import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; import org.rhq.core.pluginapi.inventory.ResourceComponent; import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.plugins.augeas.helper.AugeasNode; /** * @author Ian Springer * @author Lukas Krejci */ public class AugeasConfigurationComponent<T extends ResourceComponent<?>> implements ResourceComponent<T>, ConfigurationFacet, CreateChildResourceFacet, DeleteResourceFacet { /* Plugin config prop names */ public static final String INCLUDE_GLOBS_PROP = "configurationFilesInclusionPatterns"; public static final String EXCLUDE_GLOBS_PROP = "configurationFilesExclusionPatterns"; public static final String RESOURCE_CONFIGURATION_ROOT_NODE_PROP = "resourceConfigurationRootNode"; public static final String AUGEAS_MODULE_NAME_PROP = "augeasModuleName"; public static final String AUGEAS_ROOT_PATH_PROP = "augeasRootPath"; private static final boolean IS_WINDOWS = (File.separatorChar == '\\'); public static final String DEFAULT_AUGEAS_ROOT_PATH = (IS_WINDOWS) ? "C:/" : "/"; private final Log log = LogFactory.getLog(this.getClass()); private ResourceContext<T> resourceContext; private String resourceDescription; private List<String> includeGlobs; private List<String> excludeGlobs; private Augeas augeas; private AugeasNode resourceConfigRootNode; private String augeasRootPath; private String augeasLoadPath; protected String getAugeasRootPath() { return augeasRootPath; } /** * Returns the path the augeas library loads the lenses from. * @return */ protected String getAugeasLoadPath() { return augeasLoadPath; } public void start(ResourceContext<T> resourceContext) throws InvalidPluginConfigurationException, Exception { this.resourceContext = resourceContext; this.resourceDescription = this.resourceContext.getResourceType() + " Resource with key [" + this.resourceContext.getResourceKey() + "]"; initGlobs(); Configuration pluginConfig = this.resourceContext.getPluginConfiguration(); this.augeasRootPath = pluginConfig.getSimpleValue(AUGEAS_ROOT_PATH_PROP, DEFAULT_AUGEAS_ROOT_PATH); log.debug("Augeas Root Path = \"" + this.augeasRootPath + "\""); augeasLoadPath = resourceContext.getDataDirectory().getAbsolutePath() + File.separator + AugeasPluginLifecycleListener.LENSES_SUBDIRECTORY_NAME; if (isAugeasAvailable()) { initAugeas(); } else { if (IS_WINDOWS) { log.debug("Augeas not found - this is expected, since Augeas is not currently available for Windows."); } else { log.warn("Augeas not found - if on Fedora or RHEL, `yum install augeas`."); } } } public void stop() { close(); } public AvailabilityType getAvailability() { for (File f : getConfigurationFiles()) { singleFileAvailabilityCheck(f); } return AvailabilityType.UP; } public Configuration loadResourceConfiguration() throws Exception { if (!isAugeasAvailable()) { if (log.isDebugEnabled()) { log.debug("Can not load configuration as Augeas is not available"); } return null; } abortIfAugeasNotAvailable(); //augeas was initialized in abortIfAugeasNotAvailable(); try { ConfigurationDefinition resourceConfigDef = this.resourceContext.getResourceType() .getResourceConfigurationDefinition(); Configuration resourceConfig = new Configuration(); resourceConfig.setNotes("Loaded from Augeas at " + new Date()); Collection<PropertyDefinition> propDefs = resourceConfigDef.getPropertyDefinitions().values(); for (PropertyDefinition propDef : propDefs) { loadProperty(propDef, resourceConfig, this.augeas, this.resourceConfigRootNode); } // This will add error messages to any PropertySimples with invalid values, so they can be displayed by the GUI. validateResourceConfiguration(new ConfigurationUpdateReport(resourceConfig)); return resourceConfig; } finally { close(); } } protected void updateStructuredConfiguration(Configuration config) throws Exception { abortIfAugeasNotAvailable(); //augeas was initialized in abortIfAugeasNotAvailable try { ConfigurationDefinition resourceConfigDef = this.resourceContext.getResourceType() .getResourceConfigurationDefinition(); Collection<PropertyDefinition> propDefs = resourceConfigDef.getPropertyDefinitions().values(); for (PropertyDefinition propDef : propDefs) { setNode(propDef, config, this.augeas, this.resourceConfigRootNode); } // Write the updated tree out to the config file. saveConfigurationFiles(); } finally { close(); } } public void updateResourceConfiguration(ConfigurationUpdateReport report) { try { abortIfAugeasNotAvailable(); } catch (Exception e) { report.setErrorMessage(e.getLocalizedMessage()); return; } if (!validateResourceConfiguration(report)) { log.debug("Validation of updated Resource configuration for " + this.resourceDescription + " failed with the following errors: " + report.getErrorMessage()); report.setStatus(ConfigurationUpdateStatus.FAILURE); close(); return; } //augeas was initialized in abortIfAugeasNotAvailable(); try { ConfigurationDefinition resourceConfigDef = this.resourceContext.getResourceType() .getResourceConfigurationDefinition(); Configuration resourceConfig = report.getConfiguration(); Collection<PropertyDefinition> propDefs = resourceConfigDef.getPropertyDefinitions().values(); for (PropertyDefinition propDef : propDefs) { setNode(propDef, resourceConfig, this.augeas, this.resourceConfigRootNode); } // Write the updated tree out to the config file. saveConfigurationFiles(); // If we got this far, we've succeeded in our mission. report.setStatus(ConfigurationUpdateStatus.SUCCESS); } finally { close(); } } public CreateResourceReport createResource(CreateResourceReport report) { Configuration resourceConfig = report.getResourceConfiguration(); ConfigurationDefinition resourceConfigDef = report.getResourceType().getResourceConfigurationDefinition(); // First insert the root node corresponding to the new child Resource. String rootPath = getChildResourceConfigurationRootPath(report.getResourceType(), report.getResourceConfiguration()); initAugeas(); try { AugeasNode rootNode = new AugeasNode(rootPath); if (this.augeas.exists(rootNode.getPath())) { report.setStatus(CreateResourceStatus.FAILURE); report.setErrorMessage("An Augeas node already exists with path " + rootPath); return report; } String rootLabel = getChildResourceConfigurationRootLabel(report.getResourceType(), report.getResourceConfiguration()); this.augeas.set(rootNode.getPath(), rootLabel); // Then set all its child nodes. Collection<PropertyDefinition> propDefs = resourceConfigDef.getPropertyDefinitions().values(); for (PropertyDefinition propDef : propDefs) { setNode(propDef, resourceConfig, this.augeas, rootNode); } // Write the updated tree out to the config file. saveConfigurationFiles(); // If we got this far, we've succeeded in our mission. report.setStatus(CreateResourceStatus.SUCCESS); return report; } finally { close(); } } public void deleteResource() throws Exception { String rootPath = getResourceConfigurationRootPath(); initAugeas(); try { Augeas augeas = getAugeas(); augeas.remove(rootPath); augeas.save(); } finally { close(); } } /** * Subclasses should override this method in order to perform any validation that is not encapsulated * in the Configuration metadata. * * @param report the report to which any validation errors should be added * * @return true if the Configuration is valid, or false if it is not */ protected boolean validateResourceConfiguration(ConfigurationUpdateReport report) { return true; } protected AugeasNode getExistingChildNodeForListMemberPropertyMap(AugeasNode parentNode, PropertyDefinitionList propDefList, PropertyMap propMap) { String mapKey = getListMemberMapKey(propDefList); if (mapKey != null) { String existingChildNodeName = propMap.getSimple(mapKey).getStringValue(); AugeasNode existingChildNode = new AugeasNode(parentNode, existingChildNodeName); return (this.augeas.exists(existingChildNode.getPath())) ? existingChildNode : null; } else { return null; } } @NotNull protected String getResourceConfigurationRootPath() { Configuration pluginConfig = this.resourceContext.getPluginConfiguration(); String rootPath = pluginConfig.getSimpleValue(RESOURCE_CONFIGURATION_ROOT_NODE_PROP, null); if (rootPath == null) { String includeGlobs = pluginConfig.getSimple(INCLUDE_GLOBS_PROP).getStringValue(); if (includeGlobs.indexOf('|') != -1) { throw new IllegalStateException("Unable to determine resource configuration root Augeas path."); } rootPath = "/files" + includeGlobs; } return rootPath; } /** * Subclasses that wish to support child Resource creation must override this method. * * @param resourceType the type of child Resource being created * @param resourceConfig the Resource configuration for the child Resource being created * * @return the path of the Augeas node that should be created for the child Resource being created */ protected String getChildResourceConfigurationRootPath(ResourceType resourceType, Configuration resourceConfig) { throw new IllegalStateException("Class " + getClass().getName() + " does not override getChildResourceConfigurationRootPath() for " + resourceType + "."); } /** * Subclasses that wish to support child Resource creation must override this method. * * @param resourceType the type of child Resource being created * @param resourceConfig the Resource configuration for the child Resource being created * * @return the value of the Augeas node that should be created for the child Resource being created */ protected String getChildResourceConfigurationRootLabel(ResourceType resourceType, Configuration resourceConfig) { throw new IllegalStateException("Class " + getClass().getName() + " does not override getChildResourceConfigurationRootLabel() for " + resourceType + "."); } public ResourceContext<T> getResourceContext() { return this.resourceContext; } public String getResourceDescription() { return this.resourceDescription; } public List<File> getConfigurationFiles() { List<File> files = Glob.matchAll(new File(this.augeasRootPath), includeGlobs, Glob.ALPHABETICAL_COMPARATOR); Glob.excludeAll(files, excludeGlobs); return files; } /** * Returns initialized augeas instance. Augeas instance must be closed by calling method close on the Augeas instance * or by calling method close on AugeasConfigurationComponent instance after use of augeas. * @return */ public Augeas getAugeas() { if (this.augeas == null) initAugeas(); return this.augeas; } protected void setupAugeasModules(Augeas augeas) { Configuration pluginConfig = this.resourceContext.getPluginConfiguration(); String augeasModuleName = pluginConfig.getSimpleValue(AUGEAS_MODULE_NAME_PROP, null); if (augeasModuleName == null) { throw new IllegalStateException("Plugin config property '" + AUGEAS_MODULE_NAME_PROP + "' is required."); } augeas.set("/augeas/load/" + augeasModuleName + "/lens", augeasModuleName + ".lns"); int idx = 1; for (String incl : this.includeGlobs) { augeas.set("/augeas/load/" + augeasModuleName + "/incl[" + (idx++) + "]", incl); } idx = 1; for (String excl : this.excludeGlobs) { augeas.set("/augeas/load/" + augeasModuleName + "/excl[" + (idx++) + "]", excl); } } protected Augeas createAugeas() { Augeas augeas; try { augeas = new Augeas(this.augeasRootPath, augeasLoadPath, Augeas.NO_MODL_AUTOLOAD); setupAugeasModules(augeas); checkModuleErrors(augeas); } catch (Throwable e) { augeas = null; String msg = "Failed to initialize Augeas Java API: " + e.getMessage(); if (e instanceof NoClassDefFoundError) { msg += " - there is probably no native library available"; } log.warn(msg); } return augeas; } protected boolean isAugeasAvailable() { Aug aug; try { aug = Aug.INSTANCE; } catch (Error e) { return false; } if (log.isTraceEnabled()) { log.trace("Aug JNA object: " + aug); } return true; } protected String getAugeasPathRelativeToParent(PropertyDefinition propDef, AugeasNode parentNode, Augeas augeas) { return propDef.getName(); } protected void loadProperty(PropertyDefinition propDef, AbstractPropertyMap parentPropMap, Augeas augeas, AugeasNode parentNode) { String propName = getAugeasPathRelativeToParent(propDef, parentNode, augeas); AugeasNode node = (propName.equals(".")) ? parentNode : new AugeasNode(parentNode, propName); Property prop; if (propDef instanceof PropertyDefinitionSimple) { prop = createPropertySimple((PropertyDefinitionSimple) propDef, augeas, node); } else if (propDef instanceof PropertyDefinitionMap) { prop = createPropertyMap((PropertyDefinitionMap) propDef, augeas, node); } else if (propDef instanceof PropertyDefinitionList) { prop = createPropertyList((PropertyDefinitionList) propDef, augeas, node); } else { throw new IllegalStateException("Unsupported PropertyDefinition subclass: " + propDef.getClass().getName()); } if (prop != null) { parentPropMap.put(prop); } } protected Object toPropertyValue(PropertyDefinitionSimple propDefSimple, Augeas augeas, AugeasNode node) { return augeas.get(node.getPath()); } protected Property createPropertySimple(PropertyDefinitionSimple propDefSimple, Augeas augeas, AugeasNode node) { Object value; if (propDefSimple.getType() == PropertySimpleType.LONG_STRING) { List<String> childPaths = augeas.match(node.getPath()); if (childPaths.isEmpty()) { return null; } StringBuilder propValue = new StringBuilder(); for (String childPath : childPaths) { String childValue = augeas.get(childPath); propValue.append(childValue).append("\n"); } // Chop the final newline char. propValue.deleteCharAt(propValue.length() - 1); value = propValue.toString(); } else { value = toPropertyValue(propDefSimple, augeas, node); } return new PropertySimple(propDefSimple.getName(), value); } protected PropertyMap createPropertyMap(PropertyDefinitionMap propDefMap, Augeas augeas, AugeasNode node) { PropertyMap propMap = new PropertyMap(propDefMap.getName()); populatePropertyMap(propDefMap, propMap, augeas, node); return propMap; } protected Property createPropertyList(PropertyDefinitionList propDefList, Augeas augeas, AugeasNode node) { PropertyDefinition listMemberPropDef = propDefList.getMemberDefinition(); if (!(listMemberPropDef instanceof PropertyDefinitionMap)) { throw new IllegalArgumentException( "Invalid Resource ConfigurationDefinition - only lists of maps are supported."); } PropertyDefinitionMap listMemberPropDefMap = (PropertyDefinitionMap) listMemberPropDef; PropertyList propList = new PropertyList(propDefList.getName()); String mapKey = getListMemberMapKey(propDefList); String mapPath = getAugeasPathRelativeToParent(listMemberPropDefMap, node, augeas); String listMemberPathsExpression = node.getPath() + AugeasNode.SEPARATOR_CHAR + mapPath; List<String> listMemberPaths = augeas.match(listMemberPathsExpression); for (String listMemberPath : listMemberPaths) { AugeasNode listMemberNode = new AugeasNode(listMemberPath); PropertyMap listMemberPropMap = new PropertyMap(listMemberPropDefMap.getName()); propList.add(listMemberPropMap); // Add the "key" prop, if defined, to the map. if (mapKey != null) { PropertySimple keyProp = new PropertySimple(mapKey, listMemberNode.getName()); listMemberPropMap.put(keyProp); } // Populate the rest of the map child properties. populatePropertyMap(listMemberPropDefMap, listMemberPropMap, augeas, listMemberNode); } return propList; } protected void populatePropertyMap(PropertyDefinitionMap propDefMap, PropertyMap propMap, Augeas augeas, AugeasNode mapNode) { for (PropertyDefinition mapEntryPropDef : propDefMap.getOrderedPropertyDefinitions()) { loadProperty(mapEntryPropDef, propMap, augeas, mapNode); } } protected void setNode(PropertyDefinition propDef, AbstractPropertyMap parentPropMap, Augeas augeas, AugeasNode parentNode) { String propName = getAugeasPathRelativeToParent(propDef, parentNode, augeas); AugeasNode node = (propName.equals(".")) ? parentNode : new AugeasNode(parentNode, propName); if (isPropertyDefined(propDef, parentPropMap)) { // The property *is* defined, which means we either need to add or update the corresponding node in the // Augeas tree. if (propDef instanceof PropertyDefinitionSimple) { PropertyDefinitionSimple propDefSimple = (PropertyDefinitionSimple) propDef; PropertySimple propSimple = parentPropMap.getSimple(propDefSimple.getName()); setNodeFromPropertySimple(augeas, node, propDefSimple, propSimple); } else if (propDef instanceof PropertyDefinitionMap) { PropertyDefinitionMap propDefMap = (PropertyDefinitionMap) propDef; PropertyMap propMap = parentPropMap.getMap(propDefMap.getName()); setNodeFromPropertyMap(propDefMap, propMap, augeas, node); } else if (propDef instanceof PropertyDefinitionList) { PropertyDefinitionList propDefList = (PropertyDefinitionList) propDef; PropertyList propList = parentPropMap.getList(propDefList.getName()); setNodeFromPropertyList(propDefList, propList, augeas, node); } else { throw new IllegalStateException("Unsupported PropertyDefinition subclass: " + propDef.getClass().getName()); } } else { // The property *is not* defined - remove the corresponding node from the Augeas tree if it exists. removeNodeIfItExists(augeas, node); } } protected String toNodeValue(Augeas augeas, AugeasNode node, PropertyDefinitionSimple propDefSimple, PropertySimple propSimple) { return propSimple.getStringValue(); } protected String getNodeInsertionPoint(Augeas augeas, AugeasNode node, PropertyDefinitionSimple propDefSimple, PropertySimple propSimple) { return String.format("%s/*[following-sibling::*[1]=%s[1]]", node.getParent().getPath(), node.getPath()); } protected void setNodeFromPropertySimple(Augeas augeas, AugeasNode node, PropertyDefinitionSimple propDefSimple, PropertySimple propSimple) { String value = toNodeValue(augeas, node, propDefSimple, propSimple); if (propDefSimple.getType() == PropertySimpleType.LONG_STRING) { // First remove the existing items. //get the node position first, needed to say insert after node x String varName = "path"; String nodeExpression = getNodeInsertionPoint(augeas, node, propDefSimple, propSimple); augeas.defineNode(varName, nodeExpression, null); augeas.remove(node.getPath()); // Now add the updated items. String[] tokens = value.trim().split("\\s+"); for (int i = tokens.length; i > 0; i--) { String itemValue = tokens[i - 1]; if (itemValue != null && itemValue.trim().length() != 0) { augeas.insert("$" + varName, node.getName(), false); augeas.set(node.getPath() + "[1]", itemValue); } } } else { // Update the value of the existing node. augeas.set(node.getPath(), value); } } protected void setNodeFromPropertyMap(PropertyDefinitionMap propDefMap, PropertyMap propMap, Augeas augeas, AugeasNode mapNode) { for (PropertyDefinition mapEntryPropDef : propDefMap.getOrderedPropertyDefinitions()) { setNode(mapEntryPropDef, propMap, augeas, mapNode); } } protected void setNodeFromPropertyList(PropertyDefinitionList propDefList, PropertyList propList, Augeas augeas, AugeasNode listNode) { PropertyDefinition listMemberPropDef = propDefList.getMemberDefinition(); if (!(listMemberPropDef instanceof PropertyDefinitionMap)) { throw new IllegalArgumentException( "Invalid Resource ConfigurationDefinition - only lists of maps are supported."); } PropertyDefinitionMap listMemberPropDefMap = (PropertyDefinitionMap) listMemberPropDef; int listIndex = 0; // grab all the list member paths String listMemberPropDefMapPath = getAugeasPathRelativeToParent(listMemberPropDefMap, listNode, augeas); List<String> existingListMemberPaths = augeas.match(listNode.getPath() + AugeasNode.SEPARATOR_CHAR + listMemberPropDefMapPath); // now turn paths into augeas nodes List<AugeasNode> existingListMemberNodes = new ArrayList<AugeasNode>(); for (String existingListMemberPath : existingListMemberPaths) { existingListMemberNodes.add(new AugeasNode(existingListMemberPath)); } Set<AugeasNode> updatedListMemberNodes = new HashSet<AugeasNode>(); for (Property listMemberProp : propList.getList()) { PropertyMap listMemberPropMap = (PropertyMap) listMemberProp; AugeasNode memberNodeToUpdate = getExistingChildNodeForListMemberPropertyMap(listNode, propDefList, listMemberPropMap); if (memberNodeToUpdate != null) { // Keep track of the existing nodes that we'll be updating, so that we can remove all other existing // nodes. updatedListMemberNodes.add(memberNodeToUpdate); } else { // The maps in the list are non-keyed, or there is no map in the list with the same key as the map // being added, so create a new node for the map to add to the list. AugeasNode basePathNode = getNewListMemberNode(listNode, listMemberPropDefMap, listIndex); String var = "prop" + listIndex; String bpath = basePathNode.getPath(); augeas.defineNode(var, bpath, null); memberNodeToUpdate = new AugeasNode("$" + var); listIndex++; } // Update the node's children. setNodeFromPropertyMap(listMemberPropDefMap, listMemberPropMap, augeas, memberNodeToUpdate); } // Now remove any existing nodes that we did not update in the previous loop. for (AugeasNode existingListMemberNode : existingListMemberNodes) { if (!updatedListMemberNodes.contains(existingListMemberNode)) { augeas.remove(existingListMemberNode.getPath()); } } } protected AugeasNode getNewListMemberNode(AugeasNode listNode, PropertyDefinitionMap listMemberPropDefMap, int listIndex) { return new AugeasNode(listNode, getAugeasPathRelativeToParent(listMemberPropDefMap, listNode, getAugeas()) + "[" + listIndex + "]"); } private boolean isPropertyDefined(PropertyDefinition propDef, AbstractPropertyMap parentPropMap) { Property prop = parentPropMap.get(propDef.getName()); if (prop == null) { return false; } else { return (!(prop instanceof PropertySimple) || ((PropertySimple) prop).getStringValue() != null); } } private void removeNodeIfItExists(Augeas augeas, AugeasNode node) { if (augeas.exists(node.getPath())) { log.debug("Removing node " + node + " from Augeas tree..."); augeas.remove(node.getPath()); } } @Nullable private String getListMemberMapKey(PropertyDefinitionList propDefList) { Configuration pluginConfig = this.resourceContext.getPluginConfiguration(); PropertyMap mapKeyNames = pluginConfig.getMap("listMemberMapKeyNames"); if (mapKeyNames == null) { return null; } String listName = propDefList.getName(); return mapKeyNames.getSimpleValue(listName, null); } private void saveConfigurationFiles() { // TODO: Backup original file. try { this.augeas.save(); } catch (AugeasException e) { throw new RuntimeException(summarizeAugeasError(this.augeas), e); } } private void initGlobs() { Configuration pluginConfig = this.resourceContext.getPluginConfiguration(); PropertySimple includes = pluginConfig.getSimple(INCLUDE_GLOBS_PROP); PropertySimple excludes = pluginConfig.getSimple(EXCLUDE_GLOBS_PROP); includeGlobs = new ArrayList<String>(); excludeGlobs = new ArrayList<String>(); includeGlobs.addAll(Arrays.asList(includes.getStringValue().split("\\s*\\|\\s*"))); if (excludes != null && excludes.getStringValue() != null) { excludeGlobs.addAll(Arrays.asList(excludes.getStringValue().split("\\s*\\|\\s*"))); } } private void singleFileAvailabilityCheck(File f) { if (!f.isAbsolute()) { throw new InvalidPluginConfigurationException("Path '" + f.getPath() + "' is not an absolute path."); } if (!f.exists()) { throw new InvalidPluginConfigurationException("File '" + f.getPath() + "' does not exist."); } if (f.isDirectory()) { throw new InvalidPluginConfigurationException("Path '" + f.getPath() + "' is a directory, not a regular file."); } } protected String summarizeAugeasError(Augeas augeas) { StringBuilder summary = new StringBuilder(); String metadataNodePrefix = "/augeas/files"; for (String glob : this.includeGlobs) { if (glob.startsWith(AugeasNode.SEPARATOR)) { glob = glob.substring(1); } AugeasNode metadataNode = new AugeasNode(metadataNodePrefix, glob); AugeasNode errorNode = new AugeasNode(metadataNode, "error"); List<String> nodePaths = augeas.match(errorNode.getPath() + "/*"); for (String path : nodePaths) { String error = augeas.get(path); summary.append("File \"").append(path.substring(metadataNodePrefix.length(), path.length())) .append("\":\n").append(error).append("\n"); } } return summary.toString(); } protected void initAugeas() { if (this.augeas != null) { try { this.augeas.close(); } catch (Exception e) { } this.augeas = null; } this.augeas = createAugeas(); if (augeas!=null) { this.augeas.load(); checkModuleErrors(this.augeas); String resourceConfigRootPath = getResourceConfigurationRootPath(); if (resourceConfigRootPath.indexOf(AugeasNode.SEPARATOR_CHAR) != 0) { // root path is relative - make it absolute this.resourceConfigRootNode = new AugeasNode("/files/", resourceConfigRootPath); } else { // root path is already absolute this.resourceConfigRootNode = new AugeasNode(resourceConfigRootPath); } log.debug("Resource Config Root Node = \"" + this.resourceConfigRootNode + "\""); } } private void abortIfAugeasNotAvailable() throws Exception { if (getAugeas() == null) { if (isAugeasAvailable()) { initAugeas(); if (getAugeas() == null) { throw new Exception("Failed to initialize Augeas Java API."); } } else { String message; if (IS_WINDOWS) { message = "Configuration of " + getResourceContext().getResourceType().getName() + " Resources is not supported on Windows."; } else { message = "Configuration of " + getResourceContext().getResourceType().getName() + " Resources requires that the Augeas shared library be installed on the Agent system." + " If on Fedora or RHEL, `yum install augeas`."; } throw new Exception(message); } } } private void checkModuleErrors(Augeas augeas) { List<String> errors = augeas.match("/augeas/load//error"); if (errors != null && errors.size() > 0) { StringBuilder errorMessage = new StringBuilder(); for (String nodePath : errors) { AugeasNode node = new AugeasNode(nodePath); String moduleName = node.getParent().getName(); String errorText = augeas.get(nodePath); errorMessage.append("Module '").append(moduleName).append("' failed with the following errors:\n"); errorMessage.append(errorText); errorMessage.append("\n\n"); } throw new IllegalStateException("Augeas modules didn't load cleanly.\n" + errorMessage); } } /* (non-Javadoc) * @see java.lang.Object#finalize() */ @Override protected void finalize() throws Throwable { close(); super.finalize(); } public void close() { if (this.augeas != null) { try { this.augeas.close(); } catch (Exception e) { } this.augeas = null; } } }