/** * NOTE: This copyright does *not* cover user programs that use Hyperic * 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) [2009-2010], VMware, Inc. * This file is part of Hyperic. * * Hyperic 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.autoinventory.server.session; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperic.hq.appdef.server.session.Server; import org.hyperic.hq.appdef.server.session.Service; import org.hyperic.hq.appdef.server.session.ServiceType; import org.hyperic.hq.appdef.shared.AIServiceValue; import org.hyperic.hq.appdef.shared.AppdefEntityID; import org.hyperic.hq.appdef.shared.CPropManager; import org.hyperic.hq.appdef.shared.ConfigManager; import org.hyperic.hq.appdef.shared.ServerManager; import org.hyperic.hq.appdef.shared.ServiceManager; import org.hyperic.hq.authz.server.session.AuthzSubject; import org.hyperic.hq.authz.server.session.Resource; import org.hyperic.hq.authz.shared.AuthzSubjectManager; import org.hyperic.hq.authz.shared.PermissionException; import org.hyperic.hq.authz.shared.ResourceManager; import org.hyperic.hq.autoinventory.server.session.RuntimeReportProcessor.ServiceMergeInfo; import org.hyperic.hq.common.ApplicationException; import org.hyperic.hq.measurement.shared.SRNManager; import org.hyperic.hq.zevents.ZeventManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; /** * Merges in services which have been discovered via runtime AI. * * This class also has the responsibility of keeping state about which services * are in the queue, waiting to be processed, and notifying the agent that it * still needs to get a runtime service scan. */ @Component public class ServiceMergerImpl implements ServiceMerger { private final Log log = LogFactory.getLog(ServiceMergerImpl.class); private CPropManager cPropManager; private ServiceManager serviceManager; private ServerManager serverManager; private ConfigManager configManager; private ResourceManager resourceManager; private AuthzSubjectManager authzSubjectManager; private SRNManager srnManager; @Autowired public ServiceMergerImpl(CPropManager cPropManager, ServiceManager serviceManager, ServerManager serverManager, ConfigManager configManager, ResourceManager resourceManager, SRNManager srnManager, AuthzSubjectManager authzSubjectManager) { this.cPropManager = cPropManager; this.serviceManager = serviceManager; this.serverManager = serverManager; this.configManager = configManager; this.resourceManager = resourceManager; this.authzSubjectManager = authzSubjectManager; this.srnManager = srnManager; } @Transactional public void mergeServices(List<ServiceMergeInfo> mergeInfos) throws PermissionException, ApplicationException { final boolean debug = log.isDebugEnabled(); final Set<Resource> updatedResources = new HashSet<Resource>(); final Set<AppdefEntityID> toSchedule = new HashSet<AppdefEntityID>(); AuthzSubject creator = null; for (ServiceMergeInfo sInfo : mergeInfos) { // this is hacky, but mergeInfos will never be called with multiple // subjects // and hence the method probably shouldn't be written the way it is // anyway. AIServiceValue aiservice = sInfo.aiservice; Server server = serverManager.getServerById(sInfo.serverId); if (server == null || server.getResource() == null || server.getResource().isInAsyncDeleteState()) { continue; } // HHQ-4646: The owner of the service should be the same // as the owner of the server creator = authzSubjectManager.findSubjectByName(server.getModifiedBy()); if(log.isDebugEnabled()){ log.debug("Checking for existing service: " + aiservice.getName()); } // this is a propagation of a bug that nobody really runs into. // Occurs when a set of services under a server have the same name // and therefore the AIID is also the same. In a perfect world the // AIIDs will be unique, but there is nothing else that comes from // the agent that can uniquely identify a service under a server. // The get(0), instead of operating on the whole list, enables // us to make the least amount of code changes in a messy code path // thus reducing the amount of potential problems. final List<Service> tmp = serviceManager.getServicesByAIID(server, aiservice.getName()); Service service = (tmp.size() > 0) ? (Service) tmp.get(0) : null; boolean update = false; if (service == null) { // CREATE SERVICE log.info("Creating new service: " + aiservice.getName()); String typeName = aiservice.getServiceTypeName(); ServiceType serviceType = serviceManager.findServiceTypeByName(typeName); service = serviceManager.createService(creator, server, serviceType, aiservice.getName(), aiservice.getDescription(), "", null); log.debug("New service created: " + service); } else { final String aiSvcName = aiservice.getName(); final String svcName = service.getName(); final String aiid = service.getAutoinventoryIdentifier(); // if aiid.equals(svcName) this means that the name has // not been manually changed. Therefore it is ok to change // the current resource name if (aiSvcName != null && !aiSvcName.equals(svcName) && aiid.equals(svcName)) { // UPDATE SERVICE update = true; if(log.isDebugEnabled()){ log.debug("Updating service: " + service.getName()); } service.setName(aiservice.getName().trim()); service.getResource().setName(service.getName()); } if (aiservice.getDescription() != null) service.setDescription(aiservice.getDescription().trim()); } // CONFIGURE SERVICE final boolean wasUpdated = configManager.configureResponse(creator, service.getConfigResponse(), service.getEntityId(), aiservice.getProductConfig(), aiservice.getMeasurementConfig(), aiservice.getControlConfig(), aiservice.getResponseTimeConfig(), null, false); if (update && wasUpdated) { updatedResources.add(service.getResource()); } // SET CUSTOM PROPERTIES FOR SERVICE if (aiservice.getCustomProperties() != null) { int typeId = service.getServiceType().getId().intValue(); cPropManager.setConfigResponse(service.getEntityId(), typeId, aiservice.getCustomProperties()); } } if (!toSchedule.isEmpty()) { resourceManager.resourceHierarchyUpdated(creator, updatedResources); srnManager.scheduleInBackground(toSchedule, true, true); } } public String toString() { return "RuntimeAIServiceMerger"; } public void scheduleServiceMerges(final String agentToken, final List<ServiceMergeInfo> serviceMerges) { List<MergeServiceReportZevent> evts = new ArrayList<MergeServiceReportZevent>(serviceMerges .size()); for (ServiceMergeInfo sInfo : serviceMerges) { if (log.isDebugEnabled()) { log.debug("Enqueueing service merge for " + sInfo.aiservice.getName() + " on server id=" + sInfo.serverId); } evts.add(new MergeServiceReportZevent(sInfo)); } ZeventManager.getInstance().enqueueEventsAfterCommit(evts); } }