/* * This file is part of DRBD Management Console by LINBIT HA-Solutions GmbH * written by Rasto Levrinc. * * Copyright (C) 2009, LINBIT HA-Solutions GmbH. * Copyright (C) 2011-2012, Rastislav Levrinc. * * DRBD Management Console 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. * * DRBD Management Console 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 drbd; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ package lcmc.crm.domain; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; import lcmc.common.domain.Application; import lcmc.common.domain.Value; import lcmc.cluster.ui.ClusterBrowser; import lcmc.crm.ui.resource.ServiceInfo; import lcmc.cluster.ui.widget.Widget; import lcmc.logger.Logger; import lcmc.logger.LoggerFactory; /** * This class describes a resource agent with its name and class. * This is important in otder to distinguish services that have the same name * int the heartbeat, ocf, service or lsb classes. */ public class ResourceAgent { private static final Logger LOG = LoggerFactory.getLogger(ResourceAgent.class); public static final String SERVICE_CLASS_NAME = "service"; public static final String UPSTART_CLASS_NAME = "upstart"; public static final String SYSTEMD_CLASS_NAME = "systemd"; /** Name of lsb style resource (/etc/init.d/*). */ public static final String LSB_CLASS_NAME = "lsb"; public static final Collection<String> SERVICE_CLASSES = new ArrayList<String>(); /** Name of heartbeat style resource (heartbeat 1). */ public static final String HEARTBEAT_CLASS_NAME = "heartbeat"; /** Name of ocf style resource (heartbeat 2). */ public static final String OCF_CLASS_NAME = "ocf"; public static final String STONITH_CLASS_NAME = "stonith"; public static final String HEARTBEAT_PROVIDER = "heartbeat"; static { SERVICE_CLASSES.add(SERVICE_CLASS_NAME); /* contains upstart and systemd */ SERVICE_CLASSES.add(UPSTART_CLASS_NAME); SERVICE_CLASSES.add(SYSTEMD_CLASS_NAME); SERVICE_CLASSES.add(LSB_CLASS_NAME); /* deprecated */ } private final String serviceName; /** Name of the provider like "linbit". */ private final String provider; /** Class of the service, like ocf. */ private final String resourceClass; private String serviceVersion; /** Long description of the hb service. */ private String serviceLongDesc; private String serviceShortDesc; /** Hash code. */ private final int hash; private final List<String> masterSlaveParameters = new ArrayList<String>(); private final List<String> parameters = new ArrayList<String>(); private final Collection<String> requiredParams = new HashSet<String>(); private final Collection<String> metaAttrParams = new HashSet<String>(); private final Map<String, String> paramLongDescriptions = new HashMap<String, String>(); private final Map<String, String> paramShortDescriptions = new HashMap<String, String>(); private final Map<String, String> paramTypes = new HashMap<String, String>(); private final Map<String, String> paramDefaults = new HashMap<String, String>(); private final Map<String, String> paramPreferredValues = new HashMap<String, String>(); private final Map<String, Value[]> paramPossibleChoices = new HashMap<String, Value[]>(); private final Map<String, Value[]> paramPossibleChoicesMS = new HashMap<String, Value[]>(); private final String pullDownMenuName; private final Table<String ,String, Value> nameParameterToDefaultOperations = HashBasedTable.create(); private final Collection<String> operationNames = new LinkedHashSet<String>(); private boolean probablyMasterSlave = false; private boolean probablyClone = false; /** Sections for some parameters. */ private final Map<String, String> paramSections = new HashMap<String, String>(); private final Map<String, Widget.Type> fieldTypes = new HashMap<String, Widget.Type>(); private final boolean pingService; /** Whether to ignore defaults, show them, but don't assume they are defaults. */ private boolean ignoreDefaults = false; private boolean metaDataLoaded = false; public ResourceAgent(final String serviceName, final String provider, final String resourceClass) { this.serviceName = serviceName; this.provider = provider; this.resourceClass = resourceClass; operationNames.addAll(Arrays.asList(ClusterBrowser.CRM_OPERATIONS)); hash = (serviceName == null ? 0 : serviceName.hashCode() * 31) + (resourceClass == null ? 0 : resourceClass.hashCode()); if (HEARTBEAT_PROVIDER.equals(provider)) { pullDownMenuName = serviceName; } else { pullDownMenuName = provider + ':' + serviceName; } /* info fields */ String section = "Resource"; if (isClone()) { section = "Set"; } else if (isGroup()) { section = "Group"; } pingService = "ping".equals(serviceName) || "pingd".equals(serviceName); addParameter(ServiceInfo.GUI_ID); paramSections.put(ServiceInfo.GUI_ID, section); requiredParams.add(ServiceInfo.GUI_ID); paramShortDescriptions.put(ServiceInfo.GUI_ID, "Name"); paramLongDescriptions.put(ServiceInfo.GUI_ID, "Name"); addInfoParameter(section, ServiceInfo.PCMK_ID, "new...", "Id", "Id"); if (!isClone() && !isGroup()) { addInfoParameter("Resource", ServiceInfo.RA_PARAM, getRAString(), "Resource Agent", "Resource Agent"); } } private void addInfoParameter(final String section, final String name, final String defaultValue, final String shortName, final String longName) { addParameter(name); if (defaultValue != null) { paramDefaults.put(name, defaultValue); } paramSections.put(name, section); requiredParams.add(name); paramShortDescriptions.put(name, shortName); paramLongDescriptions.put(name, longName); fieldTypes.put(name, Widget.Type.LABELFIELD); } public String getServiceName() { return serviceName; } public String getProvider() { return provider; } /** * Returns the hb name as it should appear in the pull down menus. This * actually only because of "Filesytem / DRBD". */ public String getPullDownMenuName() { return pullDownMenuName; } public String getResourceClass() { return resourceClass; } @Override public int hashCode() { return hash; } /** * Returns whether two service equal. They have the same name and are from * the same hb class. */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null || !getClass().isInstance(obj)) { return false; } final ResourceAgent other = getClass().cast(obj); return (serviceName == null ? other.serviceName == null : serviceName.equals(other.serviceName)) && (resourceClass == null ? other.resourceClass == null : resourceClass.equals(other.resourceClass)); } void setServiceVersion(final String serviceVersion) { this.serviceVersion = serviceVersion; } String getServiceVersion() { return serviceVersion; } void setServiceLongDesc(final String serviceLongDesc) { this.serviceLongDesc = serviceLongDesc; } String getServiceLongDesc() { return serviceLongDesc; } void setServiceShortDesc(final String serviceShortDesc) { this.serviceShortDesc = serviceShortDesc; } String getServiceShortDesc() { return serviceShortDesc; } void addMasterParameter(final String param) { masterSlaveParameters.add(param); } void addParameter(final String param) { masterSlaveParameters.add(param); parameters.add(param); } List<String> getParameters(final boolean master) { if (master) { return masterSlaveParameters; } else { return parameters; } } /** * Prints an error if some info was required for a parameter that does not * exist. This should never happen. */ private void wrongParameterError(final String param) { LOG.appError("wrongParameterError: param: " + param); } void setParamRequired(final String param, final boolean required) { if (!masterSlaveParameters.contains(param)) { wrongParameterError(param); return; } if (required) { requiredParams.add(param); } else { requiredParams.remove(param); } } /** Returns whether the parameter is required. */ boolean isRequired(final String param) { return requiredParams.contains(param); } void setParamLongDesc(final String param, final String longDesc) { if (!masterSlaveParameters.contains(param)) { wrongParameterError(param); return; } paramLongDescriptions.put(param, longDesc); } void setParamShortDesc(final String param, final String shortDesc) { if (!masterSlaveParameters.contains(param)) { wrongParameterError(param); return; } paramShortDescriptions.put(param, shortDesc); } void setParamType(final String param, final String type) { if (!masterSlaveParameters.contains(param)) { wrongParameterError(param); return; } paramTypes.put(param, type); } /** Gets the type of the parameter. */ String getParamType(final String param) { return paramTypes.get(param); } /** Sets the default value of the parameter. */ void setParamDefault(final String param, final String defaultValue) { if (!masterSlaveParameters.contains(param)) { wrongParameterError(param); return; } paramDefaults.put(param, defaultValue); } String getDefaultValue(final String param) { return paramDefaults.get(param); } void setParamPreferred(final String param, final String preferredValue) { if (!masterSlaveParameters.contains(param)) { wrongParameterError(param); return; } paramPreferredValues.put(param, preferredValue); } String getPreferredValue(final String param) { return paramPreferredValues.get(param); } void setParamPossibleChoices(final String param, final Value[] choices) { if (!masterSlaveParameters.contains(param)) { wrongParameterError(param); return; } paramPossibleChoices.put(param, choices); } void setParamPossibleChoicesMS(final String param, final Value[] choices) { if (!masterSlaveParameters.contains(param)) { wrongParameterError(param); return; } paramPossibleChoicesMS.put(param, choices); } Value[] getComboBoxChoices(final String param) { return paramPossibleChoices.get(param); } Value[] getComboBoxChoicesMasterSlave(final String param) { final Value[] ret = paramPossibleChoicesMS.get(param); if (ret == null) { return getComboBoxChoices(param); } return ret; } String getShortDesc(final String param) { return paramShortDescriptions.get(param); } String getLongDesc(final String param) { return paramLongDescriptions.get(param); } public boolean isFilesystem() { return "Filesystem".equals(serviceName) && isOCFClass(); } public boolean isDrbddisk() { return "drbddisk".equals(serviceName) && isHeartbeatClass(); } public boolean isLinbitDrbd() { return "drbd".equals(serviceName) && "linbit".equals(provider); } public boolean isHbDrbd() { return "drbd".equals(serviceName) && HEARTBEAT_PROVIDER.equals(provider); } void setParamIsMetaAttr(final String param, final boolean isMetaAttr) { if (!masterSlaveParameters.contains(param)) { wrongParameterError(param); return; } if (isMetaAttr) { metaAttrParams.add(param); } else { metaAttrParams.remove(param); } } boolean isParamMetaAttr(final String param) { return metaAttrParams.contains(param); } public boolean isIPaddr() { return isOCFClass() && ("IPaddr".equals(serviceName) || "IPaddr2".equals(serviceName)); } public boolean isVirtualDomain() { return isOCFClass() && "VirtualDomain".equals(serviceName); } public boolean isGroup() { return Application.PACEMAKER_GROUP_NAME.equals(serviceName) && "group".equals(resourceClass); } public boolean isClone() { return Application.PM_CLONE_SET_NAME.equals(serviceName) && "clone".equals(resourceClass); } public boolean isStonith() { return STONITH_CLASS_NAME.equals(resourceClass); } public boolean isHeartbeatClass() { return HEARTBEAT_CLASS_NAME.equals(resourceClass); } public boolean isOCFClass() { return OCF_CLASS_NAME.equals(resourceClass); } /** * Adds default value for operation like 'start' and param like 'timeout' * to the hash. */ void addOperationDefault(final String name, final String param, final Value defaultValue) { if (defaultValue != null) { nameParameterToDefaultOperations.put(name, param, defaultValue); } operationNames.add(name); } public Value getOperationDefault(final String name, final String param) { return nameParameterToDefaultOperations.get(name, param); } public Iterable<String> getOperationNames() { return operationNames; } void setProbablyMasterSlave(final boolean probablyMasterSlave) { this.probablyMasterSlave = probablyMasterSlave; } public boolean isProbablyMasterSlave() { return probablyMasterSlave; } void setProbablyClone(final boolean probablyClone) { this.probablyClone = probablyClone; } public boolean isProbablyClone() { return probablyClone; } String getSection(final String param) { return paramSections.get(param); } void setSection(final String param, final String section) { paramSections.put(param, section); } public Widget.Type getFieldType(final String param) { return fieldTypes.get(param); } public String getRAString() { if (HEARTBEAT_PROVIDER.equals(provider)) { return resourceClass + ':' + serviceName; } return resourceClass + ':' + provider + ':' + serviceName; } public boolean isPingService() { return pingService; } public void setIgnoreDefaults(final boolean ignoreDefaults) { this.ignoreDefaults = ignoreDefaults; } public boolean isIgnoreDefaults() { return ignoreDefaults; } public boolean isMetaDataLoaded() { return metaDataLoaded; } public void setMetaDataLoaded(final boolean metaDataLoaded) { this.metaDataLoaded = metaDataLoaded; } public boolean hasParameter(final String param) { return parameters.contains(param); } }