From: <isp...@rh...> - 2009-10-09 23:32:19
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg DL { border : 1px #006 solid; background-color : #369; padding : 6px; color : #fff; } #msg DT { float : left; width : 6em; font-weight : bold; } #msg DL, #msg DT, #msg UL, #msg LI { font-family : arial,helvetica,sans-serif; font-size : 10pt; } h3 { font-family : arial,helvetica,sans-serif; font-size : 10pt; font-weight : bold; } #msg PRE { overflow : auto; white-space : normal; background-color : #ffc; border : 1px #fc0 solid; padding : 6px; } #msg UL, PRE, .diff { overflow : auto; } #patch h4 { font-family : arial,helvetica,sans-serif; font-size : 10pt; } #patch h4 { padding: 8px; background : #369; color : #fff; margin : 0; } #patch .propset h4, #patch .binary h4 {margin: 0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {background:#eeeeee;padding: 0 0 10px 0;} #patch .propset .diff, #patch .binary .diff {padding: 10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch .add {background:#ddffdd;} #patch .rem {background:#ffdddd;} #patch .lines, .info {color:#888888;background:#ffffff;} .diff { width : 100%; } #msg DL { border : 1px #006 solid; background-color : #369; padding : 6px; color : #fff; } #msg DT { float : left; width : 6em; font-weight : bold; } #msg DL, #msg DT, #msg UL, #msg LI { font-family : arial,helvetica,sans-serif; font-size : 10pt; } h3 { font-family : arial,helvetica,sans-serif; font-size : 10pt; font-weight : bold; } #msg PRE { overflow : auto; white-space : normal; background-color : #ffc; border : 1px #fc0 solid; padding : 6px; } #msg UL, PRE, .diff { overflow : auto; } #patch h4 { font-family : arial,helvetica,sans-serif; font-size : 10pt; } #patch h4 { padding: 8px; background : #369; color : #fff; margin : 0; } #patch .propset h4, #patch .binary h4 {margin: 0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {background:#eeeeee;padding: 0 0 10px 0;} #patch .propset .diff, #patch .binary .diff {padding: 10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch .add {background:#ddffdd;} #patch .rem {background:#ffdddd;} #patch .lines, .info {color:#888888;background:#ffffff;} .diff { width : 100%; } --></style> <title>[rhq-project.org rhq] [5246] first draft of code for generically loading and updating configs using Augeas (has not been tested yet)</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>5246</dd> <dt>Author</dt> <dd>ispringer</dd> <dt>Date</dt> <dd>2009-10-09 18:32:07 -0500 (Fri, 09 Oct 2009)</dd> </dl> <h3>Log Message</h3> <pre>first draft of code for generically loading and updating configs using Augeas (has not been tested yet)</pre> <h3>Modified Paths</h3> <ul> <li><a href="#rhqtrunkmodulespluginsaugeaspomxml">rhq/trunk/modules/plugins/augeas/pom.xml</a></li> <li><a href="#rhqtrunkmodulespluginsaugeassrcmainjavaorgrhqpluginsaugeasAugeasPluginLifecycleListenerjava">rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasPluginLifecycleListener.java</a></li> <li><a href="#rhqtrunkmodulespluginsaugeassrcmainresourcesMETAINFrhqpluginxml">rhq/trunk/modules/plugins/augeas/src/main/resources/META-INF/rhq-plugin.xml</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#rhqtrunkmodulespluginsaugeassrcmainjavaorgrhqpluginsaugeasAugeasConfigurationComponentjava">rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasConfigurationComponent.java</a></li> <li>rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/</li> <li><a href="#rhqtrunkmodulespluginsaugeassrcmainjavaorgrhqpluginsaugeashelperAugeasNodejava">rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/AugeasNode.java</a></li> <li><a href="#rhqtrunkmodulespluginsaugeassrcmainjavaorgrhqpluginsaugeashelperAugeasUtilityjava">rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/AugeasUtility.java</a></li> <li><a href="#rhqtrunkmodulespluginsaugeassrcmainjavaorgrhqpluginsaugeashelperMapKeyjava">rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/MapKey.java</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="rhqtrunkmodulespluginsaugeaspomxml"></a> <div class="modfile"><h4>Modified: rhq/trunk/modules/plugins/augeas/pom.xml (5245 => 5246)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/augeas/pom.xml 2009-10-09 14:51:34 UTC (rev 5245) +++ rhq/trunk/modules/plugins/augeas/pom.xml 2009-10-09 23:32:07 UTC (rev 5246) </span><span class="lines">@@ -16,17 +16,19 @@ </span><span class="cx"> <description>An abstract plugin for configuring resources via Augeas</description> <dependencies> </span><span class="add">+ </span><span class="cx"> <dependency> <groupId>net.augeas</groupId> </span><span class="rem">- <artifactId>java-augeas</artifactId> - <version>1.0</version> </span><span class="add">+ <artifactId>augeas</artifactId> + <version>0.0.1</version> </span><span class="cx"> </dependency> <dependency> </span><span class="rem">- <groupId>com.sun.jna</groupId> </span><span class="add">+ <groupId>net.java.dev.jna</groupId> </span><span class="cx"> <artifactId>jna</artifactId> </span><span class="rem">- <version>3.0.1</version> </span><span class="add">+ <version>3.2.2</version> </span><span class="cx"> </dependency> </span><span class="add">+ </span><span class="cx"> </dependencies> <build> </span><span class="lines">@@ -43,16 +45,19 @@ </span><span class="cx"> </goals> <configuration> <artifactItems> </span><span class="add">+ </span><span class="cx"> <artifactItem> </span><span class="rem">- <groupId>com.sun.jna</groupId> </span><span class="add">+ <groupId>net.java.dev.jna</groupId> </span><span class="cx"> <artifactId>jna</artifactId> </span><span class="rem">- <version>3.0.1</version> </span><span class="add">+ <version>3.2.2</version> </span><span class="cx"> </artifactItem> </span><span class="add">+ </span><span class="cx"> <artifactItem> <groupId>net.augeas</groupId> </span><span class="rem">- <artifactId>java-augeas</artifactId> - <version>1.0</version> </span><span class="add">+ <artifactId>augeas</artifactId> + <version>0.0.1</version> </span><span class="cx"> </artifactItem> </span><span class="add">+ </span><span class="cx"> </artifactItems> <outputDirectory>${project.build.outputDirectory}/lib</outputDirectory> </configuration> </span><span class="lines">@@ -140,4 +145,4 @@ </span><span class="cx"> </profiles> </span><span class="rem">-</project> </span><span class="cx">\ No newline at end of file </span><span class="add">+</project> </span></pre></div> <a id="rhqtrunkmodulespluginsaugeassrcmainjavaorgrhqpluginsaugeasAugeasConfigurationComponentjava"></a> <div class="addfile"><h4>Added: rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasConfigurationComponent.java (0 => 5246)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasConfigurationComponent.java (rev 0) +++ rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasConfigurationComponent.java 2009-10-09 23:32:07 UTC (rev 5246) </span><span class="lines">@@ -0,0 +1,411 @@ </span><span class="add">+/* + * Jopr 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.plugins.augeas; + +import java.io.File; +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 org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jetbrains.annotations.Nullable; + +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.pluginapi.configuration.ConfigurationUpdateReport; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import org.rhq.core.pluginapi.inventory.ResourceContext; +import org.rhq.plugins.augeas.helper.AugeasNode; +import org.rhq.plugins.augeas.helper.AugeasUtility; +import org.rhq.plugins.augeas.helper.MapKey; + +/** + * @author Ian Springer + */ +public class AugeasConfigurationComponent { + private static final String AUGEAS_LOAD_PATH = "/usr/local/share/augeas/lenses"; + private static final String AUGEAS_ROOT_PATH = "/"; + + private final Log log = LogFactory.getLog(this.getClass()); + + private ResourceContext resourceContext; + private File configFile; + private AugeasNode augeasConfigFileNode; + private Augeas augeas; + + public void start(ResourceContext resourceContext) throws InvalidPluginConfigurationException, Exception { + this.resourceContext = resourceContext; + + Configuration pluginConfig = this.resourceContext.getPluginConfiguration(); + String configFilePath = pluginConfig.getSimpleValue("configFile", null); + + if (configFilePath != null) { + this.configFile = new File(configFilePath); + + if (!this.configFile.exists()) { + throw new InvalidPluginConfigurationException("Config file not found at specified location: " + + this.configFile); + } + // TODO: check that path is absolute. + } + + String augeasModuleName = pluginConfig.getSimpleValue("augeasModuleName", null); + if (augeasModuleName == null) { + throw new InvalidPluginConfigurationException("'augeasModuleName' plugin configuration property is required."); + } + + this.augeas = new Augeas(AUGEAS_ROOT_PATH, AUGEAS_LOAD_PATH, Augeas.NO_MODL_AUTOLOAD | Augeas.SAVE_BACKUP); + + this.augeas.set("/augeas/load/" + augeasModuleName + "/lens", augeasModuleName + ".lns"); + this.augeas.set("/augeas/load/" + augeasModuleName + "/incl", this.configFile.getPath()); + + this.augeasConfigFileNode = new AugeasNode("/files" + AugeasNode.SEPARATOR_CHAR + this.configFile.getPath()); + } + + public void stop() { + this.augeas.close(); + } + + public AvailabilityType getAvailability() { + if (this.configFile == null) { + return AvailabilityType.DOWN; + } + return this.configFile.exists() ? AvailabilityType.UP : AvailabilityType.DOWN; + } + + public Configuration loadResourceConfiguration() throws Exception { + // Load the config file from disk and build a tree representation of it. + this.augeas.load(); + + 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.augeasConfigFileNode); + } + + return resourceConfig; + } + + public void updateResourceConfiguration(ConfigurationUpdateReport report) { + // Load the config file from disk and build a tree representation of it. + this.augeas.load(); + + ConfigurationDefinition resourceConfigDef = + this.resourceContext.getResourceType().getResourceConfigurationDefinition(); + Configuration resourceConfig = report.getConfiguration(); + + Collection<PropertyDefinition> propDefs = resourceConfigDef.getPropertyDefinitions().values(); + for (PropertyDefinition propDef : propDefs) { + setNode(propDef, resourceConfig, augeas, this.augeasConfigFileNode); + } + + // Write the updated tree out to the config file. + this.augeas.save(); + + // If we got this far, we've succeeded in our mission. + report.setStatus(ConfigurationUpdateStatus.SUCCESS); + } + + private void loadProperty(PropertyDefinition propDef, AbstractPropertyMap parentPropMap, + Augeas augeas, AugeasNode parentNode) { + String propName = propDef.getName(); + 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()); + } + parentPropMap.put(prop); + } + + private void checkListForMembersWithNonUniqueKeys(AugeasNode node, PropertyList propList, MapKey mapKey) { + if (mapKey != null) { + // If the maps are defined as having unique keys, log a message if they are not unique. + Set<String> keys = new HashSet<String>(); + for (Property listMemberProp : propList.getList()) { + PropertyMap listMemberPropMap = (PropertyMap)listMemberProp; + PropertySimple keyProp = listMemberPropMap.getSimple(mapKey.getName()); + String key = keyProp.getStringValue(); + if (!keys.add(key)) { + if (mapKey.getAugeasMapping() == MapKey.AugeasMapping.MAP_NODE_NAME) { + log.debug("[" + node + "] node contains more than one child named [" + key + "]."); + } else { + log.debug("[" + node + "] node contains more than one grandchild named [" + key + "]."); + } + } + } + } + } + + private Property createPropertySimple(PropertyDefinitionSimple propDefSimple, Augeas augeas, AugeasNode node) { + String 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 = augeas.get(node.getPath()); + } + return new PropertySimple(propDefSimple.getName(), value); + } + + private PropertyMap createPropertyMap(PropertyDefinitionMap propDefMap, Augeas augeas, AugeasNode node) { + PropertyMap propMap = new PropertyMap(propDefMap.getName()); + populatePropertyMap(propDefMap, propMap, augeas, node); + return propMap; + } + + private 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()); + MapKey mapKey = getMapKey(listMemberPropDefMap); + List<String> listMemberPaths = augeas.match(node.getPath() + "/*"); + for (String listMemberPath : listMemberPaths) { + AugeasNode listMemberNode = new AugeasNode(listMemberPath); + + PropertyMap listMemberPropMap = new PropertyMap(listMemberPropDefMap.getName()); + propList.add(listMemberPropMap); + + // Add the key prop to the map if there is one. + if (mapKey != null && mapKey.getAugeasMapping() == MapKey.AugeasMapping.MAP_NODE_NAME) { + PropertySimple keyProp = new PropertySimple(mapKey.getName(), listMemberNode.getName()); + listMemberPropMap.put(keyProp); + } + // Populate the rest of the map child properties. + populatePropertyMap(listMemberPropDefMap, listMemberPropMap, augeas, listMemberNode); + } + + checkListForMembersWithNonUniqueKeys(node, propList, mapKey); + return propList; + } + + private void populatePropertyMap(PropertyDefinitionMap propDefMap, PropertyMap propMap, Augeas augeas, + AugeasNode mapNode) { + for (PropertyDefinition mapEntryPropDef : propDefMap.getPropertyDefinitions().values()) { + loadProperty(mapEntryPropDef, propMap, augeas, mapNode); + } + } + + private void setNode(PropertyDefinition propDef, AbstractPropertyMap parentPropMap, Augeas augeas, + AugeasNode parentNode) { + String propName = propDef.getName(); + 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); + } + } + + private void setNodeFromPropertySimple(Augeas augeas, AugeasNode node, PropertyDefinitionSimple propDefSimple, + PropertySimple propSimple) { + String value = propSimple.getStringValue(); + if (propDefSimple.getType() == PropertySimpleType.LONG_STRING) { + // First remove the existing items. + List<String> childPaths = augeas.match(node.getPath() + "[*]"); + for (String childPath : childPaths) { + augeas.remove(childPath); + } + + // Now add the updated items. + String[] tokens = value.trim().split("\\s+"); + for (int i = 0, tokensLength = tokens.length; i < tokensLength; i++) { + String itemPath = node.getPath() + "[" + (i + 1) + "]"; + String itemValue = tokens[i]; + augeas.set(itemPath, itemValue); + } + } else { + // Update the value of the existing node. + augeas.set(node.getPath(), value); + } + } + + private void setNodeFromPropertyMap(PropertyDefinitionMap propDefMap, PropertyMap propMap, Augeas augeas, + AugeasNode mapNode) { + for (PropertyDefinition mapEntryPropDef : propDefMap.getPropertyDefinitions().values()) { + setNode(mapEntryPropDef, propMap, augeas, mapNode); + } + } + + private 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; + MapKey mapKey = getMapKey(listMemberPropDefMap); + + Set<String> keys = new HashSet<String>(); + int listIndex = 0; + Set<AugeasNode> updatedMemberNodes = new HashSet<AugeasNode>(); + for (Property listMemberProp : propList.getList()) { + PropertyMap listMemberPropMap = (PropertyMap)listMemberProp; + AugeasNode memberNodeToUpdate = null; + + // If the map is defined as having a unique key, see if there's an existing map with the key. + if (mapKey != null) { + PropertySimple keyProp = listMemberPropMap.getSimple(mapKey.getName()); + String key = keyProp.getStringValue(); + if (!keys.add(key)) { + // Don't allow them to save the config if it contains maps with non-unique keys that are supposed + // to have unique keys. + throw new RuntimeException("List [" + propList.getName() + " contains more than one map with property [" + + keyProp.getName() + "] with value of [" + key + "]."); + } + + if (mapKey.getAugeasMapping() == MapKey.AugeasMapping.MAP_NODE_NAME) { + if (augeas.exists(listNode.getPath() + "/" + key)) { + memberNodeToUpdate = new AugeasNode(listNode, key); + } + } else { + String nameFilter = listNode.getPath() + "/*/" + mapKey.getName(); + List<String> namePaths = AugeasUtility.matchFilter(augeas, nameFilter, key); + if (!namePaths.isEmpty()) { + String namePath = namePaths.get(0); + AugeasNode nameNode = new AugeasNode(namePath); + memberNodeToUpdate = nameNode.getParent(); + } + } + } + + if (memberNodeToUpdate != null) { + // Keep track of the existing nodes that we'll be updating, so that we can remove all other existing + // nodes. + updatedMemberNodes.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. + memberNodeToUpdate = new AugeasNode(listNode, "0" + 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. + List<String> existingListMemberPaths = augeas.match(listNode.getPath() + "/*"); + for (String existingListMemberPath : existingListMemberPaths) { + AugeasNode existingListMemberNode = new AugeasNode(existingListMemberPath); + if (!updatedMemberNodes.contains(existingListMemberNode)) { + augeas.remove(existingListMemberPath); + } + } + } + + 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 MapKey getMapKey(PropertyDefinitionMap propDefMap) { + Configuration pluginConfig = this.resourceContext.getPluginConfiguration(); + PropertyMap mapKeys = pluginConfig.getMap("mapKeys"); + if (mapKeys == null) { + return null; + } + String mapName = propDefMap.getName(); + PropertyMap mapKeyProp = mapKeys.getMap(mapName); + if (mapKeyProp == null) { + return null; + } + // TODO: Add error handling for when "name" and "augeasMapping" props are not set. + String name = mapKeyProp.getSimple("name").getStringValue(); + String augeasMappingName = mapKeyProp.getSimple("augeasMapping").getStringValue(); + MapKey.AugeasMapping augeasMapping = MapKey.AugeasMapping.valueOf(augeasMappingName); + return new MapKey(name, augeasMapping); + } +} </span><span class="cx">Property changes on: rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasConfigurationComponent.java ___________________________________________________________________ </span></pre></div> <a id="svnmimetype"></a> <div class="addfile"><h4>Added: svn:mime-type ( => )</h4> <pre class="diff"> <span class="info">Added: svn:keywords + Date Author Id Revision HeadURL </span></pre></div> <a id="svneolstyle"></a> <div class="addfile"><h4>Added: svn:eol-style ( => )</h4> <pre class="diff"> <span class="info"> Modified: rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasPluginLifecycleListener.java </span><span class="cx">=================================================================== </span><span class="rem">--- rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasPluginLifecycleListener.java 2009-10-09 14:51:34 UTC (rev 5245) </span><span class="add">+++ rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasPluginLifecycleListener.java 2009-10-09 23:32:07 UTC (rev 5246) </span><span class="lines">@@ -18,6 +18,10 @@ </span><span class="cx"> */ package org.rhq.plugins.augeas; </span><span class="add">+import net.augeas.jna.Aug; + +import com.sun.jna.Native; + </span><span class="cx"> import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; </span><span class="lines">@@ -26,7 +30,7 @@ </span><span class="cx"> /** * This is a plugin lifecycle listener object for the abstract Augeas plugin. </span><span class="rem">- * It is used to unload the augeas library from memory. </span><span class="add">+ * It is used to load and unload the augeas shared library from memory. </span><span class="cx"> * * @author John Mazzitelli */ </span><span class="lines">@@ -34,10 +38,13 @@ </span><span class="cx"> private static final Log log = LogFactory.getLog(AugeasPluginLifecycleListener.class); public void initialize(PluginContext context) throws Exception { </span><span class="rem">- log.info("Augeas plugin initialized"); </span><span class="add">+ //Aug instance = Aug.INSTANCE; + log.info("Augeas native library loaded."); </span><span class="cx"> } public void shutdown() { </span><span class="rem">- log.info("Augeas plugin shutdown"); </span><span class="add">+ //Native.unregister(Aug.class); + log.info("Augeas native library unloaded."); + </span><span class="cx"> } } </span></pre></div> <a id="rhqtrunkmodulespluginsaugeassrcmainjavaorgrhqpluginsaugeashelperAugeasNodejava"></a> <div class="addfile"><h4>Added: rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/AugeasNode.java (0 => 5246)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/AugeasNode.java (rev 0) +++ rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/AugeasNode.java 2009-10-09 23:32:07 UTC (rev 5246) </span><span class="lines">@@ -0,0 +1,122 @@ </span><span class="add">+/* + * Jopr 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.plugins.augeas.helper; + +import java.net.URI; + +/** + * An abstract representation of a node in an Augeas configuration tree (e.g. /files/etc/hosts/3/canonical). + * + * @author Ian Springer + */ +public class AugeasNode { + public static final char SEPARATOR_CHAR = '/'; + public static final String SEPARATOR = new String(new char[] {SEPARATOR_CHAR}); + + private String path; + + public AugeasNode(String path) { + if (path == null) { + throw new IllegalArgumentException("'path' parameter must not be null."); + } + if (path.charAt(0) != SEPARATOR_CHAR) { + throw new IllegalArgumentException("Specified path (" + path + ") is not absolute."); + } + + // Remove redundant "." and ".." components and redundant slashes. + this.path = normalize(path); + } + + public AugeasNode(AugeasNode parent, String name) { + if (parent == null) { + throw new IllegalArgumentException("'parentNode' parameter must not be null."); + } + if (name == null) { + throw new IllegalArgumentException("'name' parameter must not be null."); + } + if (name.charAt(0) == SEPARATOR_CHAR) { + throw new IllegalArgumentException("Specified path (" + path + ") is not relative."); + } + + this.path = parent.getPath() + SEPARATOR_CHAR + name; + } + + public AugeasNode(String parentPath, String name) { + this(new AugeasNode(parentPath), name); + } + + private AugeasNode(AugeasNode child) { + String path = child.getPath(); + if (path.equals(SEPARATOR)) { + // special case - parent of "/" is "/". + this.path = path; + } else { + char lastChar = path.charAt(path.length() -1); + if (lastChar == SEPARATOR_CHAR) { + path = path.substring(0, path.length() - 1); + } + int lastSlashIndex = path.lastIndexOf(SEPARATOR_CHAR); + this.path = path.substring(0, lastSlashIndex); + } + } + + public String getName() { + int lastSlashIndex = this.path.lastIndexOf(SEPARATOR_CHAR); + return (lastSlashIndex == 0) ? this.path : this.path.substring(lastSlashIndex + 1); + } + + public String getPath() { + return this.path; + } + + public AugeasNode getParent() { + return new AugeasNode(this); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + + AugeasNode that = (AugeasNode)obj; + + if (this.path != null ? !this.path.equals(that.path) : that.path != null) return false; + + return true; + } + + @Override + public int hashCode() { + return this.path != null ? this.path.hashCode() : 0; + } + + @Override + public String toString() { + return this.path; + } + + private static String normalize(String path) { + URI uri = URI.create(path); + return uri.normalize().getPath(); + } +} </span><span class="cx">Property changes on: rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/AugeasNode.java ___________________________________________________________________ </span></pre></div> <a id="svnmimetype"></a> <div class="addfile"><h4>Added: svn:mime-type ( => )</h4> <pre class="diff"> <span class="info">Added: svn:keywords + Date Author Id Revision HeadURL </span></pre></div> <a id="svneolstyle"></a> <div class="addfile"><h4>Added: svn:eol-style ( => )</h4> <pre class="diff"> <span class="info"> Added: rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/AugeasUtility.java </span><span class="cx">=================================================================== </span><span class="rem">--- rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/AugeasUtility.java (rev 0) </span><span class="add">+++ rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/AugeasUtility.java 2009-10-09 23:32:07 UTC (rev 5246) </span><span class="lines">@@ -0,0 +1,51 @@ </span><span class="add">+/* + * Jopr 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.plugins.augeas.helper; + +import java.util.ArrayList; +import java.util.List; + +import net.augeas.Augeas; + +/** + * A collection of utility methods for working with {@link Augeas} instances. + * + * @author Ian Springer + */ +public class AugeasUtility { + public static List<String> matchFilter(Augeas augeas, String expression, String value) { + List<String> matches = new ArrayList<String>(); + List<String> paths = augeas.match(expression); + for (String path : paths) { + String pathValue = augeas.get(path); + if (pathValue.equals(value)) { + matches.add(path); + } + } + return matches; + } + + // Prevent instantiation. + private AugeasUtility() { + } +} </span></pre></div> <a id="rhqtrunkmodulespluginsaugeassrcmainjavaorgrhqpluginsaugeashelperAugeasUtilityjava"></a> <div class="propset"><h4>Property changes: rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/AugeasUtility.java</h4> <pre class="diff"> </pre></div> <a id="svnmimetype"></a> <div class="addfile"><h4>Added: svn:mime-type ( => )</h4> <pre class="diff"> <span class="info">Added: svn:keywords + Date Author Id Revision HeadURL </span></pre></div> <a id="svneolstyle"></a> <div class="addfile"><h4>Added: svn:eol-style ( => )</h4> <pre class="diff"> <span class="info"> Added: rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/MapKey.java </span><span class="cx">=================================================================== </span><span class="rem">--- rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/MapKey.java (rev 0) </span><span class="add">+++ rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/MapKey.java 2009-10-09 23:32:07 UTC (rev 5246) </span><span class="lines">@@ -0,0 +1,49 @@ </span><span class="add">+/* + * Jopr 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.plugins.augeas.helper; + +/** + * @author Ian Springer + */ +public class MapKey { + private String name; + private AugeasMapping augeasMapping; + + public MapKey(String name, AugeasMapping augeasMapping) { + this.name = name; + this.augeasMapping = augeasMapping; + } + + public String getName() { + return this.name; + } + + public AugeasMapping getAugeasMapping() { + return this.augeasMapping; + } + + public enum AugeasMapping { + MAP_NODE_NAME, + ENTRY_NODE_VALUE + } +} </span></pre></div> <a id="rhqtrunkmodulespluginsaugeassrcmainjavaorgrhqpluginsaugeashelperMapKeyjava"></a> <div class="propset"><h4>Property changes: rhq/trunk/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/helper/MapKey.java</h4> <pre class="diff"> </pre></div> <a id="svnmimetype"></a> <div class="addfile"><h4>Added: svn:mime-type ( => )</h4> <pre class="diff"> <span class="info">Added: svn:keywords + Date Author Id Revision HeadURL </span></pre></div> <a id="svneolstyle"></a> <div class="addfile"><h4>Added: svn:eol-style ( => )</h4> <pre class="diff"> <span class="info"> Modified: rhq/trunk/modules/plugins/augeas/src/main/resources/META-INF/rhq-plugin.xml </span><span class="cx">=================================================================== </span><span class="rem">--- rhq/trunk/modules/plugins/augeas/src/main/resources/META-INF/rhq-plugin.xml 2009-10-09 14:51:34 UTC (rev 5245) </span><span class="add">+++ rhq/trunk/modules/plugins/augeas/src/main/resources/META-INF/rhq-plugin.xml 2009-10-09 23:32:07 UTC (rev 5246) </span><span class="lines">@@ -1,10 +1,14 @@ </span><span class="cx"> <?xml version="1.0" encoding="UTF-8" ?> <plugin name="Augeas" </span><span class="rem">- displayName="Abstract Augeas" - description="Abstract plugin supporting concrete plugins that are based on Augeas, the open-source configuration library for Linux" </span><span class="add">+ displayName="Abstract Augeas Plugin" + description="An abstract plugin supporting concrete plugins that are based on Augeas, the open-source configuration library for Linux" </span><span class="cx"> package="org.rhq.plugins.augeas" pluginLifecycleListener="AugeasPluginLifecycleListener" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:xmlns:rhq-plugin"> </span><span class="rem">-</plugin> </span><span class="cx">\ No newline at end of file </span><span class="add">+ + <!-- TODO --> + +</plugin> + </span><span class="cx">\ No newline at end of file </span> </pre> </div> </div> </body> </html> |