/* * * RHQ Sync Tool * Copyright (C) 2012-2013 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 Lesser General Public License, * version 2.1, 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.jboss.rhq.sync.tool.actions.impl; import static org.jboss.rhq.sync.tool.util.PasswordUtil.decode; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.jboss.rhq.sync.tool.actions.AgentDiscoveryListener; import org.jboss.rhq.sync.tool.actions.JonActionResult; import org.jboss.rhq.sync.tool.query.JbossAsResourceQuery; import org.jboss.rhq.sync.tool.query.ResourceQueryImpl; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.Property; import org.rhq.core.domain.configuration.PropertyMap; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.resource.InventoryStatus; import org.rhq.core.domain.resource.Resource; import org.rhq.core.util.collection.ArrayUtils; import org.rhq.enterprise.server.configuration.ConfigurationManagerRemote; /** * Created by IntelliJ IDEA. * User: uuxgbig * Date: 20.04.11 * Time: 16:48 * To change this template use File | Settings | File Templates. */ public class MassConnectionUpdateAction extends AbstractJONAction implements AgentDiscoveryListener { private final ConfigurationManagerRemote configurationManagerRemote; private static Logger logger = Logger.getLogger(MassConnectionUpdateAction.class); private static final String[] LOG_PLACEHOLDERS = {"log.enabled", "log.logFilePath", "log.minimumSeverity", "log.includesPattern", "log.dateFormat"}; /** * Action. describe if something should be imported or just updated * todo. split the action into two seperate interfaces methods. no need to have this configurable */ private final String version; private Map<String, String> excludedPlatforms; protected JonActionResult actionResult; protected Map<String, PropertyMap> logCongfigurations = new HashMap<String, PropertyMap>(); public MassConnectionUpdateAction() { super(); this.configurationManagerRemote = baseRemote.getConfigurationManagerRemote(); actionResult = new JonActionResult(); /** * get the version to manage */ version = (String) props.get("jon.jboss.version"); } @Override protected JonActionResult.JonActionResultType perform(Map<String, String> values) throws RuntimeException { String platformName = (String) values.get(PLATFORM_NAME); String profileName = (String) values.get(PROFILE_NAME); String action = (String) values.get(ACTION); logger.info(" configuring platform [" + platformName + "] profileName=" + profileName); if (action == null || action.length() == 0) { throw new IllegalArgumentException("NO ACTION DEFINED. property 'jon.jboss.action' should be either IMPORT or UPDATE"); } String[] platformNames = determinePlatforms(platformName); for (String platformName1 : platformNames) { // the exclude list takes priority if (!isExcludedPlatform(platformName1)) { logger.info("####################### Configuring Platform: " + platformName1 + " ######################"); perform(platformName1.trim(), profileName, action); } else logger.warn("Platform " + platformName1 + " is found in excluded list. Will not update. "); } return JonActionResult.JonActionResultType.SUCCESS; } private boolean isExcludedPlatform(String platformName) { if (excludedPlatforms == null) { excludedPlatforms = new HashMap<String, String>(); // get comman sperated eexcluded list String exludedString = props.getProperty("jon.platform.exclude"); if (exludedString != null) { String[] platformlist = exludedString.split(","); //ad to map for quick access for (String aPlatformlist : platformlist) { excludedPlatforms.put(aPlatformlist, aPlatformlist); } } } return excludedPlatforms.containsKey(platformName); } private void perform(String platformName, String profileName, String action) { JbossAsResourceQuery query = new ResourceQueryImpl(); List<Resource> jbossList; if (ConstantPool.IMPORT.equalsIgnoreCase(action)) { logger.info("peforming import. only profiles in the auto discovery queue will be imported and configured"); jbossList = query.getAllNewJBossAS(platformName, profileName, version); logger.info("found " + jbossList.size() + " jboss profiles to import"); List<Integer> importIds = new ArrayList<Integer>(); for (Resource jbossResource : jbossList) { logger.info(" IMPORTING jboss profile resource '" + jbossResource.getName() + "' to be imported "); addDependency(jbossResource, importIds); /** * need to check its parent is added.only adding if its new. other status could be ignored etc. we want and exception if its anything other than new */ } if (importIds.size() > 0) { logger.info(" Performing import of all new resources discovered "); baseRemote.getDiscoveryBossRemote().importResources(getSubject(), ArrayUtils.unwrapCollection(importIds)); } else { logger.debug(" no resource to import "); } } else if (ConstantPool.UPDATE.equalsIgnoreCase(action)) { logger.debug("performing update of resources "); jbossList = query.getAllInventoriedJBossAS(platformName, profileName, version); } else if (ConstantPool.DELETE.equalsIgnoreCase(action)) { jbossList = query.getAllInventoriedJBossAS(platformName, profileName, version); int[] idArray = new int[jbossList.size()]; for (int i = 0; i < jbossList.size(); i++) { Resource resource = jbossList.get(i); logger.debug("Delete resource " + resource.getName()); int id = resource.getId(); idArray[i] = id; } baseRemote.getResourceManager().uninventoryResources(getSubject(), idArray); } else throw new IllegalArgumentException("NO VALID ACTION DEFINED(" + action + "). property 'jon.jboss.action' should be either IMPORT or UPDATE"); logger.info("The list of jboss profiles has been determined. Beginning reconfiguration of profiles. number of profiles[" + jbossList.size() + "]"); for ( Resource jbossResource : jbossList) { jbossResource = baseRemote.getResourceManager().getResource(getSubject(), jbossResource.getId()); Resource parentPlatformResource = baseRemote.getResourceManager().getResource(getSubject(), jbossResource.getParentResource().getId()); logger.info("Checking if this platform is to be excluded from processing."); if (isExcludedPlatform(parentPlatformResource.getName())) { logger.warn("Oh no, Platform[" + parentPlatformResource.getName() + "] is to be excluded from update"); logger.warn(" -- Excluding: profile=" + jbossResource.getName() + " on platform=" + parentPlatformResource.getName()); } else { logger.info(" platform[" + parentPlatformResource.getName() + "] has not been excluded. Proceeding with inventory configuration update"); logger.debug(" updating inventory configuration:" + jbossResource.getName() + ", platform " + parentPlatformResource.getName()); alterInventoryConfigurations(jbossResource); logger.debug("Finished inventory configuration update: profile=" + jbossResource.getName() + ", platform=" + parentPlatformResource.getName()); } } } private String[] determinePlatforms(String platformName) { if (platformName == null || platformName.trim().length() == 0) { logger.debug("No platfrom name defined: looking up system property:jon.platform.name"); String systemAgent = System.getProperty("jon.platform.name"); if (systemAgent == null || systemAgent.trim().length() == 0) { logger.debug("no system property defined: lookingup property file using key 'jon.platform.name' "); systemAgent = props.getProperty("jon.platform.name"); if (systemAgent == null || systemAgent.trim().length() == 0) { logger.debug("no value has been defined for jon.platform.name: using system getCanonicalHostName() "); try { logger.debug("Looking up host-name on system..."); InetAddress address = InetAddress.getLocalHost(); platformName = address.getCanonicalHostName(); logger.debug("Host-name is: " + platformName); logger.debug("platform name found: " + platformName); } catch (UnknownHostException e) { // TODO Auto-generated catch block logger.error(e); logger.debug("Could not find correct host name, please try to start again with VM-parameter jon.platform.name"); throw new RuntimeException(e); } } else { logger.debug("Using property file value as parameter :" + systemAgent); if (systemAgent.equals("ALL")) platformName = ""; else platformName = systemAgent.trim(); logger.debug("Host-name is: " + platformName); } } else { logger.debug("Using host-name from vm-parameter ... "); platformName = systemAgent.trim(); logger.debug("Host-name is: " + platformName); } } return platformName.split(","); } /** * method alters the configurartion of the passed jboss profile. Each profile must already be imported in jon otherwise it will do nothing (apart from a logging a warning) * * @param jboss */ private void alterInventoryConfigurations(Resource jboss) { /** * ONLY ALTER COMMITED DATA. */ try { logger.debug(" ... alterInventoryConfigurations "); if (jboss.getInventoryStatus().equals(InventoryStatus.COMMITTED)) { logger.debug("inventory-status: committed"); Configuration config = configurationManagerRemote.getPluginConfiguration(getSubject(), jboss.getId()); /** * */ loadFromProperties(config); logger.debug("trying to update ... "); configurationManagerRemote.updatePluginConfiguration(getSubject(), jboss.getId(), config); logger.debug("Update successful finished"); } else { logger.warn("cannot config resource. resource is not commited"); } } catch (Exception exc) { logger.error(exc); } } @SuppressWarnings({"unchecked", "rawtypes"}) private void loadFromProperties(Configuration jbossConfig) { Enumeration<Object> keys = props.keys(); List logConfigs = jbossConfig.getList("logEventSources").getList(); // logConfigs.clear(); while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); saveProperty(jbossConfig, key, (String) props.get(key)); } // only clear the log configuration if new ones are found if (logCongfigurations.size() > 0) { logConfigs.clear(); } for (PropertyMap propertyMap : logCongfigurations.values()) { PropertyMap next = propertyMap; logConfigs.add(next); } } private void addDependency(Resource resource, List<Integer> ids) { logger.debug(" checking if resource has any parent resources that are required to be imported "); Resource parent = baseRemote.getResourceManager().getResource(getSubject(), resource.getId()).getParentResource(); if (parent != null) { logger.debug(" parent resource found [" + parent.getName() + "]"); parent = baseRemote.getResourceManager().getResource(getSubject(), parent.getId()); if (parent.getInventoryStatus().equals(InventoryStatus.NEW)) { logger.info(" parent resource[" + resource.getName() + "] is uninventoried. perform parent check before import "); addDependency(parent, ids); } } logger.info(" adding resource to be imported [" + resource.getName() + "]"); ids.add(resource.getId()); } private void saveProperty(Configuration jbossConfig, String key, String value) { try { if (key.startsWith("jboss")) { String propertyName = key.substring(key.indexOf(".") + 1); if (propertyName.equals("credentials")) { value = decode(value); } if (jbossConfig.getSimple(propertyName) != null) { logger.info("Setting [" + propertyName + "] with value [" + value + "]"); jbossConfig.getSimple(propertyName).setStringValue(value); } else { logger.warn("IGNORING PROPERTY: Property is not mapped in configuration property in jon.'" + propertyName + " does is not a configuration property.' property[" + propertyName + "], value[" + value + "]. "); } } else if (key.startsWith("log")) { /** * update the logs that will be monitored for events */ for (String s : LOG_PLACEHOLDERS) { if (key.startsWith(s)) { if (s.equals("log.logFilePath") && !value.startsWith("/")) { //user to be serverHomeDir. this was tested on fresh eap 5 installation. a test on eap 4.3 result in a null pointer exception. this property was not valid for 4.3 installations // debug shows the property configurationPath is also valid PropertySimple serverConfig = jbossConfig.getSimple("configurationPath"); if (serverConfig != null) { // handles previous 2.3 jboss plugins value = jbossConfig.getSimple("configurationPath").getStringValue() + "/" + value; } else { // handles previous 2.4 jboss plugins value = jbossConfig.getSimple("serverHomeDir").getStringValue() + "/" + value; } } // todo add method here to dump the new logs into a hash map String myid = key.substring(s.length() + 1); String propertyName = key.substring(key.indexOf(".") + 1, key.lastIndexOf(".")); addToLogConfigurations(myid, createSimpleLogProperty(propertyName, value)); // setLogProperty(key, value, logConfigs); } } logger.debug("Saving properties finished"); } } catch (Exception e) { // neeedd to fail gracefully with a warning when something is null throw new RuntimeException("Could not save property: key=" + key + ", value=" + value + ", jboss config [" + jbossConfig.getAllProperties() + "]", e); } } private void addToLogConfigurations(String id, Property propertySimple) { PropertyMap map = logCongfigurations.get(id); if (map == null) { map = new PropertyMap(); map.setName("logEventSource"); } Map<String, Property> prpmap = map.getMap(); if (prpmap == null) { prpmap = new HashMap<String, Property>(); } prpmap.put(propertySimple.getName(), propertySimple); map.setMap(prpmap); logCongfigurations.put(id, map); //logCongfigurations.get(id).getMap().put(propertySimple.getName(),propertySimple); } @SuppressWarnings("unused") private void setLogProperty(String prop, String value, List<PropertyMap> logConfigs) { String logName = prop.substring(prop.lastIndexOf(".") + 1); String propertyName = prop.substring(prop.indexOf(".") + 1, prop.lastIndexOf(".")); for (PropertyMap property : logConfigs) { property.setName("logEventSource"); if (property.getSimple("logFilePath") != null && property.getSimple("logFilePath").getStringValue().endsWith("server.log")) { logger.debug("Log property name = " + property.getName()); if (property.getName().equals(logName)) { if (property.getSimple(propertyName) != null) { logger.debug(propertyName + " setting " + property.toString()); property.getSimple(propertyName).setStringValue(value); logger.debug(propertyName + " after" + property.toString()); } } } } } private PropertySimple createSimpleLogProperty(String name, String value) { PropertySimple simpleProp = new PropertySimple(); simpleProp.setStringValue(value); simpleProp.setName(name); return simpleProp; // my.put("logFilePath",logFilePath); } @Override public void discoveredResources(String platformName) { logger.debug("Class back listener:" + this.getClass().getName()); /** * we ha ve no idea the name of the profiles that were discoveryed so we can only scan the platform and pick up and profiles found. * as we are executing rom a discovery event we need to override 'operation'the default in the configuration (UPDATE OR IMPORT) * this must be set to IMPORT */ Map<String, String> values = new HashMap<String, String>(); values.put(ACTION, ConstantPool.IMPORT); values.put(PROFILE_NAME, platformName); perform(platformName, null, ConstantPool.IMPORT); } }