/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ /* * This file contain the class SOSAlarmManager which is having all functions * that manage all alarms. this class contain a queue which is holding alarms that * are generated in that one hour. The functions takes the alarm type generated in * Bourne and returns the objects parameters understand by vCenter. */ package com.emc.storageos.vasa; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Set; import java.util.UUID; import org.apache.log4j.Logger; import com.emc.storageos.vasa.data.internal.Event; import com.emc.storageos.vasa.data.internal.StoragePool; import com.emc.storageos.vasa.data.internal.Volume; import com.emc.storageos.vasa.data.internal.Volume.AssociatedPool; import com.emc.storageos.vasa.data.internal.Volume.HighAvailabilityVolume; import com.emc.storageos.vasa.fault.SOSFailure; import com.emc.storageos.vasa.util.FaultUtil; import com.vmware.vim.vasa._1_0.StorageFault; import com.vmware.vim.vasa._1_0.data.xsd.AlarmStatusEnum; import com.vmware.vim.vasa._1_0.data.xsd.AlarmTypeEnum; import com.vmware.vim.vasa._1_0.data.xsd.EntityTypeEnum; import com.vmware.vim.vasa._1_0.data.xsd.NameValuePair; import com.vmware.vim.vasa._1_0.data.xsd.StorageAlarm; /** * Interface to access sos. */ public class SOSAlarmManager { public static final String MESSAGE_KEY = "msg"; public static final String STATE_KEY = "state"; public static final String ALARM_ID_KEY = "SOSAlarmId"; private Queue<StorageAlarm> alarmQ; private Calendar lastAlarmEnqTime; private Hashtable<String, String> thinlyProvisionedAlarmResourceStatusTable; private static Logger log = Logger.getLogger(SOSAlarmManager.class); public SOSAlarmManager() { alarmQ = new LinkedList<StorageAlarm>(); lastAlarmEnqTime = null; thinlyProvisionedAlarmResourceStatusTable = new Hashtable<String, String>(); } public StorageAlarm getAlarmRecord() { return alarmQ.peek(); } public boolean setAlaramRecord(StorageAlarm almObj) { this.alarmQ.add(almObj); return true; } public Queue<StorageAlarm> getAlarmQ() { return this.alarmQ; } public Calendar getLastAlarmEnqTime() { return lastAlarmEnqTime; } public void setLastAlarmEnqTime(Calendar lastAlarmEnqTime) { this.lastAlarmEnqTime = Calendar.getInstance(); this.lastAlarmEnqTime.setTimeInMillis(lastAlarmEnqTime .getTimeInMillis()); } public boolean isItAlarm(Event alarm) { if (alarm.getRecordType() != null & alarm.getRecordType().equals("Alert")) { return true; } return false; } public boolean isAlertRequired(String alarmType) { if (alarmType != null) { if (alarmType.startsWith("SystemError") || alarmType.startsWith("AlertIndication") || alarmType.startsWith("ArrayGeneric")) { return true; } } return false; } /* * Right now we are returning OBJECT_ALARM only. once bourne reports all * alarms for volume and file share capacity threshold, we should return * SPACE_CAPACITY_ALARM. For capability related alarms should return * CAPABILITY_ALARM. */ public String getVasaAlarmType(String alarmType) { if (alarmType == null) { return ""; } return "OBJECT_ALARM"; } /** * * @param alarmType * - type of alarm/event generated in StorageOS. * @return - object type string which is recognized by vCenter Server for * corresponding alarm type. */ public String getAlarmObjectType(String alarmType) { String objectTypeString = ""; if (alarmType.startsWith("SystemError")) { objectTypeString = "SystemError"; } else if (alarmType.startsWith("AlertIndication")) { objectTypeString = "AlertIndication"; } else if (alarmType.startsWith("FileShare") || alarmType.startsWith("FileSystem")) { objectTypeString = EntityTypeEnum.StorageFileSystem.getValue(); } else if (alarmType.startsWith("Volume") || alarmType.startsWith("storagevolume")) { objectTypeString = EntityTypeEnum.StorageLun.getValue(); } else if (alarmType.startsWith("StoragePort")) { objectTypeString = EntityTypeEnum.StoragePort.getValue(); } else if (alarmType.startsWith("ArrayGeneric")) { objectTypeString = "ArrayGeneric"; } else { log.warn("Unknown alarm type: " + alarmType + "in getAlarmObjectType()"); } return objectTypeString; } /** * It searches the given alarm in the Q. * * @return - true, if the alarm already exists in the Q, false, otherwise. * @param alarm * -The Event generated in StorageOS. in StorageOS all are * considered as events. * * */ public boolean isAlarmExistsInQueue(Event alarm) { Iterator<StorageAlarm> it = getAlarmQ().iterator(); while (it.hasNext()) { StorageAlarm storageAlarm = it.next(); NameValuePair nvpList[] = storageAlarm.getParameterList(); String alarmId = alarm.getEventId().toString(); for (NameValuePair nvp : nvpList) { if (nvp.getParameterName().equalsIgnoreCase("SOSAlarmId") && nvp.getParameterValue().equalsIgnoreCase(alarmId)) { return true; } } } return false; } public String getAlarmObjectTypeId(String alarmType) { String objectTypeIdString = ""; if (alarmType.startsWith("FileShare") || alarmType.startsWith("FileSystem")) { objectTypeIdString = EntityTypeEnum.StorageFileSystem.getValue(); } else if (alarmType.startsWith("Volume")) { objectTypeIdString = EntityTypeEnum.StorageLun.getValue(); } else if (alarmType.startsWith("Cos")) { objectTypeIdString = EntityTypeEnum.StorageCapability.getValue(); } else if (alarmType.startsWith("StorageArray")) { objectTypeIdString = EntityTypeEnum.StorageArray.getValue(); } else if (alarmType.startsWith("StorageProcessor")) { objectTypeIdString = EntityTypeEnum.StorageProcessor.getValue(); } else if (alarmType.startsWith("StoragePort")) { objectTypeIdString = EntityTypeEnum.StoragePort.getValue(); } else if (alarmType.startsWith("ArrayGeneric")) { objectTypeIdString = "ArrayGeneric"; } else { log.warn("Unknown alarm type: " + alarmType + "in getAlarmObjectTypeId()"); } return objectTypeIdString; } /** * * @param alarmType * - type of event/alarm generated in StorageOS. * @return - messageID for corresponding alarmType. this message should be * defined in catalog's alarm.mvsg file. */ public String getMessageIdForAlarm(String alarmType) { if (alarmType == null) { return ""; } return ("StorageOS." + alarmType); } public String getAlertStatus(String severity) { String status = "GREEN"; if (severity == null) { return "GREEN"; } if (severity.contains("MAJOR") || severity.contains("CRITICAL") || severity.contains("FATAL") || severity.contains("NOTICE") || severity.contains("EMERGENCY")) { status = "RED"; } else if (severity.contains("WARNING") || severity.contains("MINOR")) { status = "YELLOW"; } else if (severity.contains("UNKNOWN") || severity.contains("OTHER") || severity.contains("INFORMATION")) { status = "GREEN"; } else { log.warn("Unknown severity : " + severity + "in getAlertStatus()"); } return status; } public StorageAlarm getAlarmObject(long alarmId, String resourceId, String resourceType, String messageId, String alarmStatus, String alarmType, String msgKey, String msgText) { StorageAlarm alarm = new StorageAlarm(); alarm.setMessageId(messageId); alarm.setAlarmId(alarmId); alarm.setObjectId(resourceId); alarm.setStatus(alarmStatus); alarm.setAlarmType(alarmType); alarm.setObjectType(resourceType); GregorianCalendar gc = new GregorianCalendar(); gc.setTimeInMillis(new Date().getTime()); alarm.setAlarmTimeStamp(gc); NameValuePair pair = new NameValuePair(); pair.setParameterName(ALARM_ID_KEY); pair.setParameterValue(UUID.randomUUID().toString()); alarm.addParameterList(pair); pair = new NameValuePair(); pair.setParameterName(msgKey); pair.setParameterValue(msgText); alarm.addParameterList(pair); alarm.addParameterList(pair); return alarm; } private boolean isThinlyProvisionAlarmRequired(String resourceId, String status) { boolean isAlarmrequired = false; if (null == thinlyProvisionedAlarmResourceStatusTable.get(resourceId)) { thinlyProvisionedAlarmResourceStatusTable.put(resourceId, status); // Initially we report only non-Green status as alarms if (!AlarmStatusEnum.Green.getValue().equals(status)) { isAlarmrequired = true; } } else { if (status.equals(thinlyProvisionedAlarmResourceStatusTable .get(resourceId))) { isAlarmrequired = false; } else { // Any status change is reported as alarm thinlyProvisionedAlarmResourceStatusTable.put(resourceId, status); isAlarmrequired = true; } } return isAlarmrequired; } public String getThinlyProvisionedStatus(SyncManager manager, Volume volume) throws StorageFault { final String methodName = "getThinlyProvisioningStatus(): "; log.debug(methodName + "Called with input:" + volume); if (volume != null && volume.isThinlyProvisioned()) { if (volume.getAllocatedCapacityInGB() >= volume .getRequestedCapacityInGB()) { return AlarmStatusEnum.Green.getValue(); } try { if (volume.getHaVolumeList() != null && volume.getHaVolumeList().getHaVolumeList() != null) { // This is a VPlex volume return getThinlyProvisionStatusOfHAVolumes(manager, volume .getHaVolumeList().getHaVolumeList()); } else { // This is a normal volume AssociatedPool associatedPool = manager .fetchAssociatedPoolOfVolume(volume.getId()); StoragePool storagePool = manager .fetchStoragePoolByHref(associatedPool .getStoragepool().getLink().getHref()); return this .getThinlyProvisionStatusOfStoragePool(storagePool); } } catch (SOSFailure e) { log.error(methodName + "SOSFailure failure occured", e); throw FaultUtil.StorageFault(e); } } return AlarmStatusEnum.Green.getValue(); } private String getThinlyProvisionStatusOfHAVolumes(SyncManager manager, List<HighAvailabilityVolume> haVolList) throws StorageFault { final String methodName = "getThinlyProvisionStatusOfHAVolumes(): "; log.debug(methodName + "Entry with input: haVolList" + haVolList); String alarmStatus = null; StoragePool storagePool = null; Set<String> alarmSet = new HashSet<String>(); for (HighAvailabilityVolume haVol : haVolList) { try { AssociatedPool associatedPool = manager .fetchAssociatedPoolOfVolume(haVol.getId()); if (log.isTraceEnabled()) { log.trace(methodName + haVol.getId() + " is associated with " + associatedPool); } storagePool = manager.fetchStoragePoolByHref(associatedPool .getStoragepool().getLink().getHref()); alarmStatus = this .getThinlyProvisionStatusOfStoragePool(storagePool); alarmSet.add(alarmStatus); } catch (SOSFailure e) { log.error(methodName + "SOSFailure failure occured", e); throw FaultUtil.StorageFault(e); } } if (alarmSet.contains(AlarmStatusEnum.Red.getValue())) { log.debug(methodName + "Exit returning [RED]"); return AlarmStatusEnum.Red.getValue(); } if (alarmSet.contains(AlarmStatusEnum.Yellow.getValue())) { log.debug(methodName + "Exit returning [YELLOW]"); return AlarmStatusEnum.Yellow.getValue(); } log.debug(methodName + "Exit returning [GREEN]"); return AlarmStatusEnum.Green.getValue(); } private String getThinlyProvisionStatusOfStoragePool(StoragePool storagePool) { String status = AlarmStatusEnum.Green.getValue(); if (storagePool.getPercentSubscribed() < 100) { return AlarmStatusEnum.Green.getValue(); } if (storagePool.getPercentUsed() > 80) { return AlarmStatusEnum.Red.getValue(); } if (storagePool.getPercentUsed() > 50) { return AlarmStatusEnum.Yellow.getValue(); } return status; } public List<StorageAlarm> getThinProvisionAlarms(SyncManager manager, List<Volume> volumeList, long lastAlarmId) throws StorageFault { final String methodName = "getThinProvisionAlarms(): "; log.debug(methodName + " Entry with last alarm id[" + lastAlarmId + "]"); StorageAlarm alarm = null; List<StorageAlarm> alarmList = new ArrayList<StorageAlarm>(); String status = null; String resourceId = null; String resourceType = null; if (volumeList != null && !volumeList.isEmpty()) { for (Volume volume : volumeList) { resourceId = volume.getId(); resourceType = EntityTypeEnum.StorageLun.getValue(); status = this.getThinlyProvisionedStatus(manager, volume); if (isThinlyProvisionAlarmRequired(resourceId, status)) { alarm = this.getAlarmObject(++lastAlarmId, resourceId, resourceType, "Alarm.ThinProvisioned", status, AlarmTypeEnum.SpaceCapacity.getValue(), STATE_KEY, status); log.debug(methodName + "New alarm generated of id[" + lastAlarmId + "] status[" + status + "] on resource id[" + resourceId + "]"); alarmList.add(alarm); } } } log.debug(methodName + "Exit returning alarm list of size[" + alarmList.size() + "]"); return alarmList; } }