/* * This file is part of LCMC written by Rasto Levrinc. * * Copyright (C) 2016, Rastislav Levrinc. * * The LCMC is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your option) * any later version. * * The LCMC 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 LCMC; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ package lcmc.crm.ui.resource.update; import com.google.common.base.Optional; import com.google.common.collect.Lists; import lcmc.cluster.ui.ClusterBrowser; import lcmc.common.domain.Application; import lcmc.crm.domain.ClusterStatus; import lcmc.crm.domain.CrmXml; import lcmc.crm.domain.ResourceAgent; import lcmc.crm.domain.RscSetConnectionData; import lcmc.crm.ui.CrmGraph; import lcmc.crm.ui.resource.CloneInfo; import lcmc.crm.ui.resource.ConstraintPHInfo; import lcmc.crm.ui.resource.CrmServiceFactory; import lcmc.crm.ui.resource.DrbddiskInfo; import lcmc.crm.ui.resource.FilesystemRaInfo; import lcmc.crm.ui.resource.GroupInfo; import lcmc.crm.ui.resource.LinbitDrbdInfo; import lcmc.crm.ui.resource.PcmkRscSetsInfo; import lcmc.crm.ui.resource.ServiceInfo; import lcmc.crm.ui.resource.ServicesInfo; import lcmc.logger.Logger; import lcmc.logger.LoggerFactory; import lombok.Getter; import lombok.RequiredArgsConstructor; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; import javax.swing.tree.DefaultMutableTreeNode; import java.awt.geom.Point2D; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @Named public class ResourceUpdater { private static final Logger LOG = LoggerFactory.getLogger(ResourceUpdater.class); private ClusterBrowser browser; private ClusterStatus clusterStatus; private Application.RunMode runMode; private ServicesInfo servicesInfo; @Inject private Provider<ConstraintPHInfo> constraintPHInfoProvider; @Inject private Provider<PcmkRscSetsInfo> pcmkRscSetsInfoProvider; @Inject private Application application; @Inject private CrmServiceFactory crmServiceFactory; private CrmGraph crmGraph; private Set<String> allGroupsAndClones; private List<ServiceInfo> groupServiceIsPresent = Lists.newArrayList(); private List<ServiceInfo> serviceIsPresent = Lists.newArrayList(); /** * This functions goes through all services, constrains etc. in * clusterStatus and updates the internal structures and graph. */ public void updateAllResources(final ServicesInfo servicesInfo, final ClusterBrowser browser, final ClusterStatus clusterStatus, final Application.RunMode runMode) { this.servicesInfo = servicesInfo; this.browser = browser; this.clusterStatus = clusterStatus; this.runMode = runMode; allGroupsAndClones = clusterStatus.getAllGroupsAndClones(); crmGraph = browser.getCrmGraph(); for (final String groupOrClone : allGroupsAndClones) { updateGroupOrClone(groupOrClone); } crmGraph.clearKeepColocationList(); crmGraph.clearKeepOrderList(); /* resource sets */ final List<RscSetConnectionData> newRscSetConnections = clusterStatus.getRscSetConnections(); if (newRscSetConnections != null) { final RscSetUpdater rscSetUpdater = new RscSetUpdater(runMode, browser, constraintPHInfoProvider, pcmkRscSetsInfoProvider); rscSetUpdater.update(newRscSetConnections); serviceIsPresent.addAll(rscSetUpdater.getServiceIsPresent()); } updateColocations(); updateOrders(); servicesInfo.cleanupServiceMenu(groupServiceIsPresent); crmGraph.updateRemovedElements(serviceIsPresent); } private void updateOrders() { final Map<String, List<CrmXml.OrderData>> orderMap = clusterStatus.getOrderRscMap(); for (final Map.Entry<String, List<CrmXml.OrderData>> orderEntry : orderMap.entrySet()) { final String orderId = orderEntry.getKey(); final List<CrmXml.OrderData> orderData = orderEntry.getValue(); final OrderUpdater orderUpdater = new OrderUpdater(crmGraph, browser, clusterStatus); orderUpdater.updateOrder(orderId, orderData); } } private void updateColocations() { final Map<String, List<CrmXml.ColocationData>> colocationMap = clusterStatus.getColocationRscMap(); for (final Map.Entry<String, List<CrmXml.ColocationData>> colocationEntry : colocationMap.entrySet()) { final List<CrmXml.ColocationData> withs = colocationEntry.getValue(); for (final CrmXml.ColocationData colocationData : withs) { final String withRscId = colocationData.getWithRsc(); final ServiceInfo withSi = this.browser.getServiceInfoFromCRMId(withRscId); final ServiceInfo siP = this.browser.getServiceInfoFromCRMId(colocationEntry.getKey()); crmGraph.addColocation(colocationData.getId(), siP, withSi); } } } private void updateGroupOrClone(final String groupOrClone) { GroupInfo newGi = null; CloneInfo newCi = null; if (clusterStatus.isClone(groupOrClone)) { /* clone */ newCi = setCreateCloneInfo(groupOrClone); serviceIsPresent.add(newCi); } else if (!"none".equals(groupOrClone)) { /* group */ final GroupInfo gi = (GroupInfo) this.browser.getServiceInfoFromCRMId(groupOrClone); if (gi != null && gi.getCloneInfo() != null) { /* cloned group is already done */ groupServiceIsPresent.add(gi); return; } newGi = setCreateGroupInfo(groupOrClone, null); serviceIsPresent.add(newGi); } setGroupResources(groupOrClone, newGi, newCi); } /** * Sets clone info object. */ private CloneInfo setCreateCloneInfo(final String cloneId) { CloneInfo newCi = (CloneInfo) browser.getServiceInfoFromCRMId(cloneId); if (newCi == null) { newCi = createNewClone(cloneId); } else { updateExistingClone(newCi); } newCi.setNew(false); return newCi; } private void updateExistingClone(final CloneInfo newCi) { final Map<String, String> resourceNode = clusterStatus.getParamValuePairs(newCi.getHeartbeatId(runMode)); newCi.setParameters(resourceNode); if (Application.isLive(runMode)) { newCi.setUpdated(false); browser.repaint(); } } private CloneInfo createNewClone(final String cloneId) { CloneInfo newCi; final Point2D p = null; newCi = (CloneInfo) servicesInfo.addServicePanel(browser.getCloneResourceAgent(), p, false, cloneId, null, runMode); browser.addToHeartbeatIdList(newCi); final Map<String, String> resourceNode = clusterStatus.getParamValuePairs(newCi.getHeartbeatId(runMode)); newCi.setParameters(resourceNode); return newCi; } private GroupInfo setCreateGroupInfo(final String group, final CloneInfo newCi) { GroupInfo newGi = (GroupInfo) browser.getServiceInfoFromCRMId(group); if (newGi == null) { newGi = createNewGroup(group, newCi); } else { updateExistingGroup(newGi); } newGi.setNew(false); return newGi; } private void updateExistingGroup(final GroupInfo newGi) { final Map<String, String> resourceNode = clusterStatus.getParamValuePairs(newGi.getHeartbeatId(runMode)); newGi.setParameters(resourceNode); if (Application.isLive(runMode)) { newGi.setUpdated(false); browser.repaint(); } } private GroupInfo createNewGroup(final String group, final CloneInfo newCi) { GroupInfo newGi; final Point2D p = null; newGi = (GroupInfo) servicesInfo.addServicePanel(browser.getGroupResourceAgent(), p, false, group, newCi, runMode); final Map<String, String> resourceNode = clusterStatus.getParamValuePairs(newGi.getHeartbeatId(runMode)); newGi.setParameters(resourceNode); if (newCi != null) { newCi.addCloneServicePanel(newGi); } return newGi; } private void setGroupResources(final String grpOrCloneId, final GroupInfo newGi, final CloneInfo newCi) { final Map<ServiceInfo, Map<String, String>> setParametersHash = new HashMap<ServiceInfo, Map<String, String>>(); if (newCi != null) { setParametersHash.put(newCi, clusterStatus.getParamValuePairs(grpOrCloneId)); } else if (newGi != null) { setParametersHash.put(newGi, clusterStatus.getParamValuePairs(grpOrCloneId)); } final Optional<List<String>> groupResources = clusterStatus.getGroupResources(grpOrCloneId, runMode); if (!groupResources.isPresent()) { return; } boolean newService = false; int pos = 0; for (final String hbId : groupResources.get()) { final GroupServiceUpdater groupServiceUpdater = new GroupServiceUpdater(newGi, newCi, setParametersHash, newService, pos, hbId); groupServiceUpdater.update(); newService = groupServiceUpdater.isNewService(); pos = groupServiceUpdater.getPos(); } for (final Map.Entry<ServiceInfo, Map<String, String>> setEntry : setParametersHash.entrySet()) { setEntry.getKey().setParameters(setEntry.getValue()); if (Application.isLive(runMode)) { setEntry.getKey().setUpdated(false); } } if (newService) { servicesInfo.reloadNode(); } browser.repaint(); } private class GroupServiceUpdater { private final GroupInfo newGi; private final CloneInfo newCi; private final Map<ServiceInfo, Map<String, String>> setParametersHash; private boolean newService; @Getter private int pos; private final String hbId; public GroupServiceUpdater(final GroupInfo newGi, final CloneInfo newCi, final Map<ServiceInfo, Map<String, String>> setParametersHash, final boolean newService, final int pos, final String hbId) { this.newGi = newGi; this.newCi = newCi; this.setParametersHash = setParametersHash; this.newService = newService; this.pos = pos; this.hbId = hbId; } public boolean isNewService() { return newService; } public void update() { if (clusterStatus.isOrphaned(hbId) && application.isHideLRM()) { return; } ServiceInfo newServiceInfo; if (allGroupsAndClones.contains(hbId)) { /* clone group */ newServiceInfo = setClonedGroup(); } else { final ResourceAgent newResourceAgent = clusterStatus.getResourceType(hbId); if (newResourceAgent == null) { /* This is bad. There is a service but we do not have * the heartbeat script of this service or the we look * in the wrong places. */ LOG.appWarning("setGroupResources: " + hbId + ": could not find resource agent"); } newServiceInfo = browser.getServiceInfoFromCRMId(hbId); final Map<String, String> resourceNode = clusterStatus.getParamValuePairs(hbId); if (newServiceInfo == null) { newServiceInfo = createNewService(newResourceAgent, resourceNode); } else { updateService(newServiceInfo, resourceNode); } newServiceInfo.setNew(false); serviceIsPresent.add(newServiceInfo); if (newGi != null || newCi != null) { groupServiceIsPresent.add(newServiceInfo); } } updateServicePosition(newServiceInfo); } private void updateServicePosition(ServiceInfo newServiceInfo) { final DefaultMutableTreeNode node = newServiceInfo.getNode(); if (node != null) { servicesInfo.moveNodeToPosition(pos, node); pos++; } } private void updateService(final ServiceInfo newServiceInfo, final Map<String, String> resourceNode) { browser.addNameToServiceInfoHash(newServiceInfo); setParametersHash.put(newServiceInfo, resourceNode); } private ServiceInfo createNewService(ResourceAgent newResourceAgent, Map<String, String> resourceNode) { ServiceInfo newServiceInfo; newService = true; newServiceInfo = crmServiceFactory.createServiceWithParameters( hbId, newResourceAgent, resourceNode, browser); newServiceInfo.setCrmId(hbId); browser.addToHeartbeatIdList(newServiceInfo); if (newGi != null) { newGi.addGroupServicePanel(newServiceInfo, false); } else if (newCi != null) { newCi.addCloneServicePanel(newServiceInfo); } else { final Point2D p = null; servicesInfo.addServicePanel(newServiceInfo, p, false, false, runMode); } return newServiceInfo; } private GroupInfo setClonedGroup() { final GroupInfo gi = setCreateGroupInfo(hbId, newCi); setGroupResources(hbId, gi, null); return gi; } } @RequiredArgsConstructor private static class OrderUpdater { private final CrmGraph crmGraph; private final ClusterBrowser browser; private final ClusterStatus clusterStatus; public void updateOrder(final String orderId, final List<CrmXml.OrderData> orderData) { for (final CrmXml.OrderData data : orderData) { final String rscThenId = data.getRscThen(); final ServiceInfo service = browser.getServiceInfoFromCRMId(rscThenId); final String dataId = data.getId(); if (service != null) { /* not yet complete */ final ServiceInfo parent = browser.getServiceInfoFromCRMId(orderId); if (parent != null && parent.getResourceAgent() != null) { updateDanglinOrdersAndColocations(orderId, rscThenId, service, dataId, parent); } } } } private void updateDanglinOrdersAndColocations(final String orderId, final String rscThenId, final ServiceInfo service, final String dataId, final ServiceInfo parent) { if (isDrbdFilesystem(service, parent)) { handleFilesystemWithDrbd(rscThenId, service, orderId, parent); } crmGraph.addOrder(dataId, parent, service); } private boolean isDrbdFilesystem(final ServiceInfo service, final ServiceInfo parent) { return (parent.getResourceAgent().isDrbddisk() || parent.getResourceAgent().isLinbitDrbd()) && "Filesystem".equals(service.getName()); } private void handleFilesystemWithDrbd(final String rscThenId, final ServiceInfo service, final String orderId, final ServiceInfo parent) { final List<CrmXml.ColocationData> cds = clusterStatus.getColocationDatas(orderId); if (cds != null) { for (final CrmXml.ColocationData cd : cds) { if (cd.getWithRsc().equals(rscThenId)) { setFilesystemWithDrbd(parent, service); } } } } /** * Check if this connection is filesystem with drbd ra and if so, set it. */ private void setFilesystemWithDrbd(final ServiceInfo siP, final ServiceInfo si) { if (siP.getResourceAgent().isLinbitDrbd()) { /* linbit::drbd -> Filesystem */ ((FilesystemRaInfo) si).setLinbitDrbdInfo((LinbitDrbdInfo) siP); } else { /* drbddisk -> Filesystem */ ((FilesystemRaInfo) si).setDrbddiskInfo((DrbddiskInfo) siP); } } } }