/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004-2009], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.hq.appdef.server.session; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.annotation.PostConstruct; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.ObjectNotFoundException; import org.hyperic.hq.appdef.ConfigResponseDB; import org.hyperic.hq.appdef.Ip; import org.hyperic.hq.appdef.shared.AppdefEntityConstants; import org.hyperic.hq.appdef.shared.AppdefEntityID; import org.hyperic.hq.appdef.shared.AppdefEntityNotFoundException; import org.hyperic.hq.appdef.shared.AppdefEntityValue; import org.hyperic.hq.appdef.shared.AppdefInventorySummary; import org.hyperic.hq.appdef.shared.AppdefUtil; import org.hyperic.hq.appdef.shared.ConfigFetchException; import org.hyperic.hq.appdef.shared.ConfigManager; import org.hyperic.hq.appdef.shared.PlatformManager; import org.hyperic.hq.appdef.shared.PlatformNotFoundException; import org.hyperic.hq.appdef.shared.ServerNotFoundException; import org.hyperic.hq.appdef.shared.ServiceNotFoundException; import org.hyperic.hq.authz.server.session.AuthzSubject; import org.hyperic.hq.authz.server.session.Resource; import org.hyperic.hq.authz.shared.AuthzConstants; import org.hyperic.hq.authz.shared.PermissionException; import org.hyperic.hq.authz.shared.ResourceManager; import org.hyperic.hq.autoinventory.AICompare; import org.hyperic.hq.bizapp.server.session.ProductBossImpl; import org.hyperic.hq.bizapp.server.session.ProductBossImpl.ConfigSchemaAndBaseResponse; import org.hyperic.hq.bizapp.shared.AllConfigDiff; import org.hyperic.hq.bizapp.shared.AllConfigResponses; import org.hyperic.hq.context.Bootstrap; import org.hyperic.hq.measurement.server.session.MonitorableType; import org.hyperic.hq.measurement.server.session.MonitorableTypeDAO; import org.hyperic.hq.product.PlatformTypeInfo; import org.hyperic.hq.product.PluginException; import org.hyperic.hq.product.PluginManager; import org.hyperic.hq.product.PluginNotFoundException; import org.hyperic.hq.product.ProductPlugin; import org.hyperic.hq.product.ProductPluginManager; import org.hyperic.hq.product.ServerTypeInfo; import org.hyperic.hq.product.ServiceTypeInfo; import org.hyperic.hq.product.TypeInfo; import org.hyperic.hq.product.server.session.ProductPluginDeployer; import org.hyperic.hq.product.shared.ProductManager; import org.hyperic.sigar.NetFlags; import org.hyperic.util.Classifier; import org.hyperic.util.config.ConfigOption; import org.hyperic.util.config.ConfigResponse; import org.hyperic.util.config.ConfigSchema; import org.hyperic.util.config.EncodingException; import org.hyperic.util.config.StringConfigOption; import org.hyperic.util.timer.StopWatch; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; /** */ @org.springframework.stereotype.Service("ConfigManager") public class ConfigManagerImpl implements ConfigManager { private static final int MAX_VALIDATION_ERR_LEN = 512; protected final Log log = LogFactory.getLog(ConfigManagerImpl.class.getName()); private final MonitorableTypeDAO monitorableTypeDAO; private final ConfigResponseDAO configResponseDAO; private final ServiceDAO serviceDAO; private final ServerDAO serverDAO; private final PlatformDAO platformDAO; private final ResourceManager resourceManager; // private PlatformManager platformManager; // private ProductManager productManager; @Autowired public ConfigManagerImpl(ConfigResponseDAO configResponseDAO, ServiceDAO serviceDAO, ServerDAO serverDAO, PlatformDAO platformDAO, ResourceManager resourceManager, MonitorableTypeDAO monitorableTypeDAO) { this.configResponseDAO = configResponseDAO; this.serviceDAO = serviceDAO; this.serverDAO = serverDAO; this.platformDAO = platformDAO; this.resourceManager = resourceManager; this.monitorableTypeDAO = monitorableTypeDAO; } // @PostConstruct // public void init() { // this.platformManager = (PlatformManager) Bootstrap.getBean("PlatformManager"); // this.productManager = (ProductManager) Bootstrap.getBean("ProductManager"); // } /** * */ public ConfigResponseDB createConfigResponse(byte[] productResponse, byte[] measResponse, byte[] controlResponse, byte[] rtResponse) { ConfigResponseDB cr = configResponseDAO.create(); cr.setProductResponse(productResponse); cr.setMeasurementResponse(measResponse); cr.setControlResponse(controlResponse); cr.setResponseTimeResponse(rtResponse); return cr; } @Transactional(readOnly=true) public Map<Resource, ConfigResponse> getConfigResponses(Set<Resource> resources, boolean hideSecrets) { final boolean debug = log.isDebugEnabled(); final StopWatch watch = new StopWatch(); final Map<Integer, Collection<Resource>> resourcesByType = new Classifier<Resource, Integer, Resource>() { @Override public NameValue<Integer, Resource> classify(Resource r) { return new NameValue<Integer, Resource>(r.getResourceType().getId(), r); } }.classify(resources); final Map<Resource, ConfigResponseDB> tmp = new HashMap<Resource, ConfigResponseDB>(); final ProductPluginDeployer productPluginDeployer = Bootstrap.getBean(ProductPluginDeployer.class); if (debug) { watch.markTimeBegin("getResourceConfigs"); } for (final Entry<Integer, Collection<Resource>> entry : resourcesByType.entrySet()) { final Integer resourceTypeId = entry.getKey(); final List<Resource> list = new ArrayList<Resource>(entry.getValue()); if (resourceTypeId.equals(AuthzConstants.authzPlatform)) { tmp.putAll(configResponseDAO.getPlatformConfigs(list)); } else if (resourceTypeId.equals(AuthzConstants.authzServer)) { tmp.putAll(configResponseDAO.getServerConfigs(list)); } else if (resourceTypeId.equals(AuthzConstants.authzService)) { tmp.putAll(configResponseDAO.getServiceConfigs(list)); } } if (debug) { watch.markTimeEnd("getResourceConfigs"); } final List<MonitorableType> all = monitorableTypeDAO.findAll(); final Map<String, String> monitorableTypeMap = new Classifier<MonitorableType, String, String>() { @Override public NameValue<String, String> classify(MonitorableType key) { return new NameValue<String, String>(key.getName(), key.getPlugin()); } }.classifyUnique(all); final Map<Resource, ConfigResponse> rtn = new HashMap<Resource, ConfigResponse>(); for (final Entry<Resource, ConfigResponseDB> entry : tmp.entrySet()) { final Resource resource = entry.getKey(); if ((resource == null) || resource.isInAsyncDeleteState() || resource.isSystem()) { continue; } final ConfigResponseDB crdb = entry.getValue(); final ConfigResponse configResponse = new ConfigResponse(); final byte[] productResponse = crdb.getProductResponse(); final byte[] controlResponse = crdb.getControlResponse(); final byte[] measurementResponse = crdb.getMeasurementResponse(); rtn.put(resource, configResponse); if (resource.getResourceType().getId().equals(AuthzConstants.authzPlatform)) { final Platform platform = platformDAO.get(resource.getInstanceId()); if (platform == null) { continue; } configResponse.setValue(ProductPlugin.PROP_PLATFORM_NAME, platform.getName()); configResponse.setValue(ProductPlugin.PROP_PLATFORM_FQDN, platform.getFqdn()); configResponse.setValue(ProductPlugin.PROP_PLATFORM_TYPE, resource.getPrototype().getName()); configResponse.setValue(ProductPlugin.PROP_PLATFORM_IP, getIp(platform)); configResponse.setValue(ProductPlugin.PROP_PLATFORM_ID, String.valueOf(platform.getId())); } try { if ((measurementResponse != null) && (measurementResponse.length > 0)) { configResponse.merge(ConfigResponse.decode(measurementResponse), true); } if ((productResponse != null) && (productResponse.length > 0)) { configResponse.merge(ConfigResponse.decode(productResponse), true); } if ((controlResponse != null) && (controlResponse.length > 0)) { configResponse.merge(ConfigResponse.decode(controlResponse), true); } // This is the bottleneck of this method if (debug) { watch.markTimeBegin("mergeWithConfigSchema"); } mergeWithConfigSchema(resource, configResponse, monitorableTypeMap, hideSecrets, productPluginDeployer); if (debug) { watch.markTimeEnd("mergeWithConfigSchema"); } } catch (EncodingException e) { log.warn("could not decode config associated with resourceId=" + resource.getId()); log.debug(e,e); } } if (debug) { log.debug(watch); } return rtn; } @Transactional(readOnly=true) private ConfigSchema getConfigSchema(AuthzSubject subject, PlatformManager platformManager, ProductManager productManager, AppdefEntityID id, String type, ConfigResponse baseResponse) { String name; try { if (type.equals(ProductPlugin.TYPE_PRODUCT)) { name = this.getPluginName(id); } else { name = platformManager.getPlatformPluginName(id); } AppdefEntityValue aval = new AppdefEntityValue(id, subject); return productManager.getConfigSchema(type, name, aval, baseResponse); }catch(AppdefEntityNotFoundException e) { log.error(e,e); }catch(PermissionException e) { log.error(e,e); }catch(PluginException e) { log.error(e,e); } return null; } private void mergeWithConfigSchema(Resource r, ConfigResponse config, Map<String, String> monitorableTypeMap, boolean hideSecrets, ProductPluginDeployer productPluginDeployer) { final AppdefEntityID id = AppdefUtil.newAppdefEntityId(r); final Integer resourceTypeId = r.getResourceType().getId(); final String proto = r.getPrototype().getName(); final String plugin = monitorableTypeMap.get(proto); TypeInfo type = null; if (resourceTypeId.equals(AuthzConstants.authzPlatform)) { type = new PlatformTypeInfo(proto); } else if (resourceTypeId.equals(AuthzConstants.authzServer)) { type = new ServerTypeInfo(proto, "", ""); } else if (resourceTypeId.equals(AuthzConstants.authzService)) { final Service service = serviceDAO.get(r.getInstanceId()); final Server server = service.getServer(); final ServerType serverType = server.getServerType(); final ServerTypeInfo serverTypeInfo = new ServerTypeInfo(serverType.getName(), serverType.getDescription(), ""); type = new ServiceTypeInfo(proto, service.getServiceType().getDescription(), serverTypeInfo); } try { final ProductPluginManager productPluginManager = productPluginDeployer.getProductPluginManager(); final PluginManager measurementPluginManager = productPluginManager.getPluginManager("measurement"); final PluginManager controlPluginManager = productPluginManager.getPluginManager("control"); final List<ConfigOption> options = new ArrayList<ConfigOption>(); options.addAll(getConfigOptions(productPluginManager, plugin, type, config)); options.addAll(getConfigOptions(measurementPluginManager, proto, type, config)); options.addAll(getConfigOptions(controlPluginManager, proto, type, config)); final Set<String> keys = config.getKeys(); for (final ConfigOption o : options) { final String key = o.getName(); if (!keys.contains(key)) { config.setValue(key, o.getDefault()); } if ((o instanceof StringConfigOption) && ((StringConfigOption) o).isHidden()) { config.unsetValue(key); } else if (hideSecrets && (o instanceof StringConfigOption) && ((StringConfigOption) o).isSecret()) { config.setValue(key, "*********"); } } } catch (PluginException e) { log.warn(e); log.debug(e,e); } } private List<ConfigOption> getConfigOptions2(PluginManager pluginManager, String key, TypeInfo type, ConfigResponse config) { try { ConfigSchema configSchema = pluginManager.getConfigSchema(key, type, config); return configSchema.getOptions(); } catch (PluginNotFoundException e) { // normally log.debug with the stack is fine, but it is a very common scenario where a plugin // does not support a certain type. This api should probably return null instead of throwing // an exception. The stacktrace is really not helpful log.debug(e); log.trace(e,e); } return Collections.emptyList(); } private List<ConfigOption> getConfigOptions(PluginManager pluginManager, String key, TypeInfo type, ConfigResponse config) { try { ConfigSchema configSchema = pluginManager.getConfigSchema(key, type, config); return configSchema.getOptions(); } catch (PluginNotFoundException e) { // normally log.debug with the stack is fine, but it is a very common scenario where a plugin // does not support a certain type. This api should probably return null instead of throwing // an exception. The stacktrace is really not helpful log.debug(e); log.trace(e,e); } return Collections.emptyList(); } private String getIp(Platform platform) { Collection<Ip> ips = platform.getIps(); for (Ip ip : ips) { String address = ip.getAddress(); if (!address.equals(NetFlags.LOOPBACK_ADDRESS)) { return address; } } return null; } /** * * Get the ConfigResponse for the given ID, creating it if it does not * already exist. * */ @Transactional(readOnly=true) public ConfigResponseDB getConfigResponse(AppdefEntityID id) { ConfigResponseDB config = null; switch (id.getType()) { case AppdefEntityConstants.APPDEF_TYPE_PLATFORM: Platform platform = platformDAO.get(id.getId()); if(platform != null) { config = platform.getConfigResponse(); } break; case AppdefEntityConstants.APPDEF_TYPE_SERVER: Server server = serverDAO.get(id.getId()); if(server != null) { config = server.getConfigResponse(); } break; case AppdefEntityConstants.APPDEF_TYPE_SERVICE: Service service = serviceDAO.get(id.getId()); if(service != null) { config = service.getConfigResponse(); } break; case AppdefEntityConstants.APPDEF_TYPE_APPLICATION: default: throw new IllegalArgumentException("The resource[ " + id + "] does not support config " + "responses"); } // Platforms, servers, and services should have a config response record. // A null config response could indicate that the resource has been deleted. if (config == null) { throw new IllegalArgumentException( "No config response found for resource[" + id + "]"); } return config; } private Platform findPlatformById(Integer id) throws PlatformNotFoundException { Platform platform = platformDAO.get(id); if (platform == null) { throw new PlatformNotFoundException(id); } // Make sure that resource is loaded as to not get // LazyInitializationException platform.getName(); return platform; } /** * */ @Transactional(readOnly=true) public String getPluginName(AppdefEntityID id) throws AppdefEntityNotFoundException { Integer intID = id.getId(); String pname; switch (id.getType()) { case AppdefEntityConstants.APPDEF_TYPE_PLATFORM: Platform plat = findPlatformById(intID); pname = plat.getPlatformType().getPlugin(); break; case AppdefEntityConstants.APPDEF_TYPE_SERVER: Server serv = serverDAO.get(intID); if (serv == null) { throw new ServerNotFoundException(intID); } pname = serv.getServerType().getPlugin(); break; case AppdefEntityConstants.APPDEF_TYPE_SERVICE: org.hyperic.hq.appdef.server.session.Service service = serviceDAO.get(intID); if (service == null) { throw new ServiceNotFoundException(intID); } pname = service.getServiceType().getPlugin(); break; case AppdefEntityConstants.APPDEF_TYPE_APPLICATION: default: throw new IllegalArgumentException("The passed entity type " + "does not support config responses"); } return pname; } /** * Get a config response object merged through the hierarchy. All entities * are merged with the product's config response, and any entity lower than * them in the config stack. Config responses defining a specific attribute * will override the same attribute if it was declared lower in the * application stack. Only entities within the same plugin will be * processed, so the most likely situation is a simple service + server + * product or server + product merge. * * Example: Get the SERVICE MEASUREMENT merged response: PRODUCT[platform] + * MEASUREMENT[platform] PRODUCT[server] + MEASUREMENT[server] + * PRODUCT[service] + MEASUREMENT[service] * * Get the SERVER PRODUCT merged response: PRODUCT[platform] PRODUCT[server] * * Get the PLATFORM PRODUCT merged response: PRODUCT[platform] * * In addition to the configuration, some inventory properties are also * merged in to aid in auto-configuration done by autoinventory. * * For Servers and Services: The install path of the server is included * * For all Resources: The first non-loopback ip address, fqdn, platform name * and type. * * @param productType One of ProductPlugin.* * @param id An AppdefEntityID of the object to get config for * * @return the merged ConfigResponse * * * */ @Transactional(readOnly=true) public ConfigResponse getMergedConfigResponse(AuthzSubject subject, String productType, AppdefEntityID id, boolean required) throws AppdefEntityNotFoundException, ConfigFetchException, EncodingException, PermissionException { ConfigResponseDB configValue; AppdefEntityID platformId = null, serverId = null, serviceId = null; byte[][] responseList; // List of config responses to merge ConfigResponse res; int responseIdx; byte[] data; ServerConfigStuff server = null; PlatformConfigStuff platform = null; boolean origReq = required; boolean isServerOrService = false; boolean isProductType = productType.equals(ProductPlugin.TYPE_PRODUCT); if ((id.getType() != AppdefEntityConstants.APPDEF_TYPE_PLATFORM) && (id.getType() != AppdefEntityConstants.APPDEF_TYPE_SERVER) && (id.getType() != AppdefEntityConstants.APPDEF_TYPE_SERVICE)) { throw new IllegalArgumentException(id + " doesn't support " + "config merging"); } // Setup responseList = new byte[6][]; responseIdx = 0; if (id.getType() == AppdefEntityConstants.APPDEF_TYPE_SERVICE) { server = getServerStuffForService(id.getId()); if (server != null) { serverId = AppdefEntityID.newServerID(new Integer(server.id)); platform = getPlatformStuffForServer(serverId.getId()); if (platform != null) { platformId = AppdefEntityID.newPlatformID(new Integer(platform.id)); } serviceId = id; origReq = required; required = false; isServerOrService = true; } } else if (id.getType() == AppdefEntityConstants.APPDEF_TYPE_SERVER) { platform = getPlatformStuffForServer(id.getId()); if (platform != null) { platformId = AppdefEntityID.newPlatformID(new Integer(platform.id)); serverId = id; server = getServerStuffForServer(serverId.getId()); isServerOrService = true; } } else { // Just the platform platformId = id; platform = getPlatformStuffForPlatform(platformId.getId()); } // Platform config if (platformId != null) { // hardcode required=false for server/service types // e.g. unlikely that a platform will have control config boolean platformConfigRequired = isServerOrService ? false : required; configValue = getConfigResponse(platformId); data = getConfigForType(configValue, ProductPlugin.TYPE_PRODUCT, platformId, platformConfigRequired); responseList[responseIdx++] = data; if (!isProductType) { if (productType.equals(ProductPlugin.TYPE_RESPONSE_TIME)) { // Skip merging of response time configuration // since platforms don't have it. } else { data = getConfigForType(configValue, productType, platformId, platformConfigRequired); responseList[responseIdx++] = data; } } } // Server config (if necessary) if (serverId != null) { if (id.isServer()) { required = isProductType ? origReq : false; } configValue = getConfigResponse(serverId); data = getConfigForType(configValue, ProductPlugin.TYPE_PRODUCT, serverId, required); responseList[responseIdx++] = data; if (!isProductType) { required = id.isServer() && origReq; // Reset the required flag if (productType.equals(ProductPlugin.TYPE_RESPONSE_TIME)) { // Skip merging of response time configuration // since servers don't have it. } else { data = getConfigForType(configValue, productType, serverId, required); responseList[responseIdx++] = data; } } } // Service config (if necessary) if (serviceId != null) { required = isProductType ? origReq : false; configValue = getConfigResponse(id); data = getConfigForType(configValue, ProductPlugin.TYPE_PRODUCT, id, required); responseList[responseIdx++] = data; if (!isProductType) { required = origReq; // Reset the required flag data = getConfigForType(configValue, productType, id, required); responseList[responseIdx++] = data; } } // Merge everything together res = new ConfigResponse(); for (int i = 0; i < responseIdx; i++) { if ((responseList[i] == null) || (responseList[i].length == 0)) { continue; } res.merge(ConfigResponse.decode(responseList[i]), true); } // Set platform attributes for all resources try { if (platform != null) { res.setValue(ProductPlugin.PROP_PLATFORM_NAME, platform.name); res.setValue(ProductPlugin.PROP_PLATFORM_FQDN, platform.fqdn); res.setValue(ProductPlugin.PROP_PLATFORM_TYPE, platform.typeName); res.setValue(ProductPlugin.PROP_PLATFORM_IP, platform.ip); res.setValue(ProductPlugin.PROP_PLATFORM_ID, String.valueOf(platform.id)); } } catch (Exception exc) { log.warn("Error setting platform properies: " + exc, exc); } // Set installpath attribute for server and service types. if (isServerOrService && (server != null)) { try { res.setValue(ProductPlugin.PROP_INSTALLPATH, server.installPath); } catch (Exception exc) { log.warn("Error setting installpath property: " + exc, exc); } } return res; } /** * Clear the validation error string for a config response, indicating that * the current config is valid * */ public void clearValidationError(AuthzSubject subject, AppdefEntityID id) { ConfigResponseDB config = getConfigResponse(id); config.setValidationError(null); } /** * Method to merge configs, maintaining any existing values that are not * present in the AI config (e.g. log/config track enablement) * * @param existingBytes The existing configuration * @param newBytes The new configuration * @param overwrite TODO * @param force TODO * @return The newly merged configuration */ private static byte[] mergeConfig(byte[] existingBytes, byte[] newBytes, boolean overwrite, boolean force) { if (force || (existingBytes == null) || (existingBytes.length == 0 && newBytes != null )) { return newBytes; } if ((newBytes == null) || (newBytes.length == 0)) { // likely a manually created platform service where // inventory-properties are auto-discovered but config // is left unchanged. return existingBytes; } try { ConfigResponse existingConfig = ConfigResponse.decode(existingBytes); ConfigResponse newConfig = ConfigResponse.decode(newBytes); existingConfig.merge(newConfig, overwrite); return existingConfig.encode(); } catch (EncodingException e) { throw new IllegalArgumentException(e.getMessage()); } } /** * Update the validation error string for a config response * @param validationError The error string that occured during validation. * If this is null, that means that no error occurred and the config * is valid. * * */ @Transactional public void setValidationError(AuthzSubject subject, AppdefEntityID id, String validationError) { ConfigResponseDB config = getConfigResponse(id); if (validationError != null) { if (validationError.length() > MAX_VALIDATION_ERR_LEN) { validationError = validationError.substring(0, MAX_VALIDATION_ERR_LEN - 3) + "..."; } } configResponseDAO.setValidationError(config, validationError); } /** * Set the config response for an entity/type combination. * @param id ID of the object to set the repsonse fo * @param response The response * @param type One of ProductPlugin.TYPE_ * @return an array of entities which may be affected by the change in * configuration. For updates to platform and service configs, there * are no other entities other than the given ID returned. If a * server is updated, the associated services may require changes. * The passed entity will always be returned in the array. * * * */ @Transactional public AppdefEntityID setConfigResponse(AuthzSubject subject, AppdefEntityID id, ConfigResponse response, String type, boolean userManaged, boolean sendConfigEvent) throws ConfigFetchException, AppdefEntityNotFoundException, PermissionException, EncodingException { byte[] productBytes = null; byte[] measurementBytes = null; byte[] controlBytes = null; byte[] rtBytes = null; if (type.equals(ProductPlugin.TYPE_PRODUCT)) { productBytes = response.encode(); } else if (type.equals(ProductPlugin.TYPE_MEASUREMENT)) { measurementBytes = response.encode(); } else if (type.equals(ProductPlugin.TYPE_CONTROL)) { controlBytes = response.encode(); } else if (type.equals(ProductPlugin.TYPE_RESPONSE_TIME)) { rtBytes = response.encode(); } else if (type.equals(ProductPlugin.TYPE_AUTOINVENTORY)) { } else { throw new IllegalArgumentException("Unknown config type: " + type); } ConfigResponseDB existingConfig = getConfigResponse(id); boolean wasUpdated = configureResponse(subject, existingConfig, id, productBytes, measurementBytes, controlBytes, rtBytes, userManaged, false); if (sendConfigEvent) { Resource r = resourceManager.findResource(id); resourceManager.resourceHierarchyUpdated(subject, Collections.singletonList(r)); } return wasUpdated ? id : null; } /** * * */ @Transactional public boolean configureResponse(AuthzSubject subject, ConfigResponseDB existingConfig, AppdefEntityID appdefID, byte[] productConfig, byte[] measurementConfig, byte[] controlConfig, byte[] rtConfig, Boolean userManaged, boolean force) { boolean wasUpdated = false; byte[] configBytes; boolean overwrite = ((userManaged != null) && userManaged.booleanValue()) || // via // UI // or // CLI !existingConfig.isUserManaged(); // via AI, dont // overwrite // changes made via // UI or CLI configBytes = mergeConfig(existingConfig.getProductResponse(), productConfig, overwrite, force); if (!AICompare.configsEqual(configBytes, existingConfig.getProductResponse())) { existingConfig.setProductResponse(configBytes); wasUpdated = true; } configBytes = mergeConfig(existingConfig.getMeasurementResponse(), measurementConfig, overwrite, force); if (!AICompare.configsEqual(configBytes, existingConfig.getMeasurementResponse())) { existingConfig.setMeasurementResponse(configBytes); wasUpdated = true; } configBytes = mergeConfig(existingConfig.getControlResponse(), controlConfig, overwrite, false); if (!AICompare.configsEqual(configBytes, existingConfig.getControlResponse())) { existingConfig.setControlResponse(configBytes); wasUpdated = true; } configBytes = mergeConfig(existingConfig.getResponseTimeResponse(), rtConfig, overwrite, false); if (!AICompare.configsEqual(configBytes, existingConfig.getResponseTimeResponse())) { existingConfig.setResponseTimeResponse(configBytes); wasUpdated = true; } if ((userManaged != null) && (existingConfig.getUserManaged() != userManaged.booleanValue())) { existingConfig.setUserManaged(userManaged.booleanValue()); wasUpdated = true; } return wasUpdated; } class ConfigDiff implements ConfigManager.ConfigDiff{ protected boolean wasUpdated; protected AllConfigDiff allConfigResponses; public boolean isWasUpdated() { return wasUpdated; } public void setWasUpdated(boolean wasUpdated) { this.wasUpdated = wasUpdated; } public AllConfigDiff getAllConfigDiff() { return this.allConfigResponses; } public void setAllConfigDiff(AllConfigDiff allConfigResponses) { this.allConfigResponses=allConfigResponses; } } @Transactional public ConfigDiff configureResponseDiff(AuthzSubject subject, ConfigResponseDB existingConfig, AppdefEntityID appdefID, byte[] productConfig, byte[] measurementConfig, byte[] controlConfig, byte[] rtConfig, Boolean userManaged, boolean force) throws EncodingException { byte[] configBytes; boolean overwrite = ((userManaged != null) && userManaged.booleanValue()) || // via // UI // or // CLI !existingConfig.isUserManaged(); // via AI, dont // overwrite // changes made via // UI or CLI ConfigDiff diffs = new ConfigDiff(); AllConfigResponses allNewConfigResponses = new AllConfigResponses(); AllConfigResponses allChangedConfigResponses = new AllConfigResponses(); AllConfigResponses allDeletedConfigResponses = new AllConfigResponses(); configBytes = mergeConfig(existingConfig.getProductResponse(), productConfig, overwrite, force); AICompare.ConfigDiff productDiffs = AICompare.configsDiff(configBytes, existingConfig.getProductResponse()); if (((null == existingConfig.getProductResponse()) && (null != configBytes)) || ((productDiffs != null) && ((productDiffs.getNewConf().size() > 0) || (productDiffs.getChangedConf().size() > 0) || (productDiffs.getDeletedConf().size() > 0)))) { existingConfig.setProductResponse(configBytes); allNewConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_PRODUCT, productDiffs.getNewConf()); allChangedConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_PRODUCT, productDiffs.getChangedConf()); allDeletedConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_PRODUCT, productDiffs.getDeletedConf()); diffs.setWasUpdated(true); } configBytes = mergeConfig(existingConfig.getMeasurementResponse(), measurementConfig, overwrite, force); AICompare.ConfigDiff msmtDiffs = AICompare.configsDiff(configBytes, existingConfig.getMeasurementResponse()); if (((null == existingConfig.getMeasurementResponse()) && (null != configBytes)) || ((msmtDiffs != null) && ((msmtDiffs.getNewConf().size() > 0) || (msmtDiffs.getChangedConf().size() > 0) || (msmtDiffs.getDeletedConf().size() > 0)))) { existingConfig.setMeasurementResponse(configBytes); allNewConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_MEASUREMENT, msmtDiffs.getNewConf()); allChangedConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_MEASUREMENT, msmtDiffs.getChangedConf()); allDeletedConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_MEASUREMENT, msmtDiffs.getDeletedConf()); diffs.setWasUpdated(true); } configBytes = mergeConfig(existingConfig.getControlResponse(), controlConfig, overwrite, false); AICompare.ConfigDiff controlDiffs = AICompare.configsDiff(configBytes, existingConfig.getControlResponse()); if (((null == existingConfig.getControlResponse()) && (null != configBytes)) || ((controlDiffs != null) && ((controlDiffs.getNewConf().size() > 0) || (controlDiffs.getChangedConf().size() > 0) || (controlDiffs.getDeletedConf().size() > 0)))) { existingConfig.setControlResponse(configBytes); allNewConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_CONTROL, controlDiffs.getNewConf()); allChangedConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_CONTROL, controlDiffs.getChangedConf()); allDeletedConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_CONTROL, controlDiffs.getDeletedConf()); diffs.setWasUpdated(true); } configBytes = mergeConfig(existingConfig.getResponseTimeResponse(), rtConfig, overwrite, false); AICompare.ConfigDiff responseTimeDiffs = AICompare.configsDiff(configBytes, existingConfig.getResponseTimeResponse()); if (((null == existingConfig.getResponseTimeResponse()) && (null != configBytes)) || ((responseTimeDiffs != null) && ((responseTimeDiffs.getNewConf().size() > 0) || (responseTimeDiffs.getChangedConf().size() > 0) || (responseTimeDiffs.getDeletedConf() .size() > 0)))) { existingConfig.setResponseTimeResponse(configBytes); allNewConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_RESPONSE_TIME, responseTimeDiffs.getNewConf()); allChangedConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_RESPONSE_TIME, responseTimeDiffs.getChangedConf()); allDeletedConfigResponses.setConfig(ProductPlugin.CFGTYPE_IDX_RESPONSE_TIME, responseTimeDiffs.getDeletedConf()); diffs.setWasUpdated(true); } if ((userManaged != null) && (existingConfig.getUserManaged() != userManaged.booleanValue())) { existingConfig.setUserManaged(userManaged.booleanValue()); diffs.setWasUpdated(true); } diffs.setAllConfigDiff(new AllConfigDiff(allNewConfigResponses,allChangedConfigResponses,allDeletedConfigResponses)); return diffs; } private byte[] getConfigForType(ConfigResponseDB val, String productType, AppdefEntityID id, boolean fail) throws ConfigFetchException { byte[] res; if (productType.equals(ProductPlugin.TYPE_PRODUCT)) { res = val.getProductResponse(); } else if (productType.equals(ProductPlugin.TYPE_CONTROL)) { res = val.getControlResponse(); } else if (productType.equals(ProductPlugin.TYPE_MEASUREMENT)) { res = val.getMeasurementResponse(); } else if (productType.equals(ProductPlugin.TYPE_AUTOINVENTORY)) { res = val.getAutoInventoryResponse(); } else if (productType.equals(ProductPlugin.TYPE_RESPONSE_TIME)) { res = val.getResponseTimeResponse(); } else { throw new IllegalArgumentException("Unknown product type"); } if (((res == null) || (res.length == 0)) && fail) { throw new ConfigFetchException(productType, id); } return res; } private ServerConfigStuff getServerStuffForService(Integer id) throws AppdefEntityNotFoundException { // HQ-4096, need to catch ObjectNotFoundException try { org.hyperic.hq.appdef.server.session.Service service = serviceDAO.get(id); if (service == null) { return null; } Server server = service.getServer(); if (server == null) { return null; } return new ServerConfigStuff(server.getId().intValue(), server.getInstallPath()); } catch (ObjectNotFoundException e) { log.debug(e,e); return null; } } private ServerConfigStuff getServerStuffForServer(Integer id) throws AppdefEntityNotFoundException { try { Server server = serverDAO.findById(id); return new ServerConfigStuff(server.getId().intValue(), server.getInstallPath()); } catch (ObjectNotFoundException e) { log.debug(e,e); return null; } } private PlatformConfigStuff getPlatformStuffForServer(Integer id) throws AppdefEntityNotFoundException { try { Server server = serverDAO.findById(id); Platform platform = server.getPlatform(); if (platform == null) { return null; } PlatformConfigStuff pConfig = new PlatformConfigStuff(platform.getId(), platform.getName(), platform.getFqdn(), platform.getPlatformType().getName()); loadPlatformIp(platform, pConfig); return pConfig; } catch (ObjectNotFoundException e) { log.debug(e,e); return null; } } private PlatformConfigStuff getPlatformStuffForPlatform(Integer id) throws AppdefEntityNotFoundException { Platform platform = platformDAO.get(id); if (platform == null) { return null; } PlatformConfigStuff pConfig = new PlatformConfigStuff(platform.getId(), platform.getName(), platform.getFqdn(), platform.getPlatformType().getName()); loadPlatformIp(platform, pConfig); return pConfig; } private void loadPlatformIp(Platform platform, PlatformConfigStuff pConfig) throws AppdefEntityNotFoundException { Collection<Ip> ips = platform.getIps(); for (Ip ip : ips) { if (!ip.getAddress().equals("127.0.0.1")) { // First non-loopback address pConfig.ip = ip.getAddress(); break; } } } // Utility classes used by getMergedConfig class ServerConfigStuff { public int id; public String installPath; public ServerConfigStuff(int id, String installPath) { this.id = id; this.installPath = installPath; } } class PlatformConfigStuff { public int id; public String ip; public String name; public String fqdn; public String typeName; public PlatformConfigStuff(int id, String name, String fqdn, String typeName) { this.id = id; this.name = name; this.fqdn = fqdn; this.typeName = typeName; } } }