/*
* Copyright (c) 2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.systemservices.impl.eventhandler.connectemc;
import java.io.*;
import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.StreamingOutput;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.transform.stream.StreamResult;
import com.emc.storageos.coordinator.common.impl.ServiceImpl;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.SysEvent;
import com.emc.storageos.security.authorization.BasePermissionsHelper;
import com.emc.storageos.services.util.AlertsLogger;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.emc.storageos.systemservices.impl.licensing.LicenseInfoExt;
import com.emc.storageos.systemservices.impl.logsvc.merger.LogNetworkStreamMerger;
import com.emc.storageos.systemservices.impl.logsvc.LogSvcPropertiesLoader;
import com.emc.storageos.systemservices.impl.resource.LogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.ema.EmaApi;
import com.emc.ema.EmaApiEventType;
import com.emc.ema.EmaApiIdentifierType;
import com.emc.ema.EmaException;
import com.emc.ema.event.objects.EventType;
import com.emc.storageos.model.event.EventParameters;
import com.emc.storageos.systemservices.impl.upgrade.CoordinatorClientExt;
import com.emc.vipr.model.sys.logging.LogRequest;
import static com.emc.storageos.systemservices.impl.eventhandler.connectemc.CallHomeConstants.*;
/**
* Class that builds alert event with all its attachments.
*/
public class SendAlertEvent extends SendEvent implements Runnable {
private static final Logger _log = LoggerFactory
.getLogger(SendAlertEvent.class);
private int _eventId;
private List<String> _logNames;
private int _severity;
private Date _start;
private Date _end;
private List<String> _nodeIds;
private String _msgRegex;
private int maxCount;
private EventParameters _eventParameters;
private final static List<String> sysEventlogFileNames = new ArrayList<String>() {
{
add("systemevents");
}
};
private URI sysEventId;
private String operationId;
protected DbClient dbClient;
private BasePermissionsHelper permissionsHelper;
private static final AlertsLogger alertsLog = AlertsLogger.getAlertsLogger();
public SendAlertEvent(ServiceImpl service, DbClient dbClient,
LogSvcPropertiesLoader logSvcPropertiesLoader, URI sysEventId,
String operationId, MediaType mediaType,
LicenseInfoExt licenseInfo, BasePermissionsHelper permissionsHelper,
CoordinatorClientExt coordinator) {
super(service, logSvcPropertiesLoader, mediaType,
licenseInfo, coordinator);
this.dbClient = dbClient;
this.sysEventId = sysEventId;
this.operationId = operationId;
this.permissionsHelper = permissionsHelper;
}
@Override
public void run() {
try {
super.callEMCHome();
dbClient.ready(SysEvent.class, sysEventId, operationId);
alertsLog.warn("Alert event initiated by " + _eventParameters.getContact() + " is sent successfully");
} catch (APIException api) {
dbClient.error(SysEvent.class, sysEventId, operationId, api);
alertsLog.error("Failed to send alert event initiated by " +
_eventParameters.getContact() + ". " + api.getMessage());
} finally {
SysEvent sysEvent = permissionsHelper.getObjectById(sysEventId, SysEvent.class);
dbClient.removeObject(sysEvent);
}
}
/**
* Generate the attachments for alerts event
* 1. ovf properties file
* 2. log file for the parameters given
* 3. system events file for the parameters given
*/
@Override
protected ArrayList<String> genAttachFiles() throws Exception {
_log.info("Start SendAlertEvent::genAttachFiles");
// Generate message file
ArrayList<String> fileList = new ArrayList<String>();
// Generate log file
ZipOutputStream outputStream = null;
try {
fileList.add(generateConfigFile());
fileList.add(generateSystemEventFile());
// Create the log request info bean from the request data.
String fileName = SYSTEM_LOGS_FILE_NAME + getFileExtension();
_log.debug("Logs zip entry name {}", fileName);
LogRequest logReqInfo = new LogRequest.Builder().nodeIds(_nodeIds)
.baseNames(_logNames).logLevel(_severity).startTime(_start)
.endTime(_end).regex(_msgRegex).maxCont(maxCount).build();
generateLogFile(logReqInfo, mediaType, SYSTEM_LOGS_FILE_PATH,
fileName);
fileList.add(SYSTEM_LOGS_FILE_PATH);
} finally {
if (outputStream != null) {
outputStream.close();
}
}
_log.info("Finish SendAlertEvent::genAttachFiles");
return fileList;
}
/**
* Gets system events for the parameters entered,
* loads the output to file with name SYSTEM_EVENT_FILE_NAME and returns it.
*/
private String generateSystemEventFile() throws IOException {
// Create the log request info bean from the request data.
LogRequest logReqInfo = new LogRequest.Builder().nodeIds(_nodeIds)
.baseNames(sysEventlogFileNames).logLevel(_severity).startTime(_start)
.endTime(_end).regex(_msgRegex).maxCont(maxCount).build();
String fileName = SYSTEM_EVENT_FILE_NAME + getFileExtension();
generateLogFile(logReqInfo, mediaType, SYSTEM_EVENT_FILE_PATH,
fileName);
return SYSTEM_EVENT_FILE_PATH;
}
/**
* Gets logs with request info provided and populates them to the file path
* specified, in zip format with fileName as zip entry.
*/
private synchronized void generateLogFile(LogRequest logReqInfo, MediaType mediaType,
String filePath, String fileName) throws IOException {
ZipOutputStream outputStream = null;
try {
_log.info("Populating logs to file: {} start", filePath);
logReqInfo.setMaxBytes(getAttachmentsMaxSizeMB() *
BYTE_TO_MB * logSvcPropertiesLoader.getZipFactor());
final LogNetworkStreamMerger logRequestMgr = new LogNetworkStreamMerger
(logReqInfo, mediaType, logSvcPropertiesLoader);
outputStream = new ZipOutputStream(new FileOutputStream(filePath));
StreamingOutput responseStream = new StreamingOutput() {
@Override
public void write(OutputStream outputStream) {
try {
LogService.runningRequests.incrementAndGet();
logRequestMgr.streamLogs(outputStream);
_log.info("Total streamed bytes: {}", logRequestMgr.streamedBytes);
} finally {
LogService.runningRequests.decrementAndGet();
}
}
};
ZipEntry ze = new ZipEntry(fileName);
outputStream.putNextEntry(ze);
responseStream.write(outputStream);
_log.info("Populating logs to file: {} end", filePath);
} finally {
if (outputStream != null) {
outputStream.close();
}
}
}
protected EventType getEventType() throws EmaException, JAXBException {
EventType event = new EventType();
event.setSymptomCode(getEventId() > 0 ? Integer.toString(getEventId()) :
SYMPTOM_CODE_REQUEST_LOGS);
event.setDescription(SEND_ALERT_DESCRIPTION);
event.setCategory(EmaApiEventType.EMA_EVENT_CATEGORY_UNKNOWN);
event.setSeverity(EmaApiEventType.EMA_EVENT_SEVERITY_DEBUG_STR);
event.setStatus(EmaApiEventType.EMA_EVENT_STATUS_UNKNOWN);
event.setCallHome(callHome);
event.setEventData(buildEventData());
return event;
}
/**
* Constructs String of query parameters used
*/
@Override
protected ArrayList<String> collectQueryParameters() {
ArrayList<String> params = new ArrayList<String>();
params.add("event_id=" + _eventId);
params.add("logNames=" + _logNames);
params.add("severity=" + _severity);
params.add("start=" + _start);
params.add("end=" + _end);
params.add("nodeIds=" + _nodeIds);
params.add("msgRegex=" + _msgRegex);
params.add("maxCount=" + maxCount);
return params;
}
/**
* build events data as marshalled string of xml data.
*
* @return
*/
private String buildEventData() throws JAXBException {
if (_eventParameters != null) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(EventParameters.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Writer outWriter = new StringWriter();
StreamResult result = new StreamResult(outWriter);
marshaller.marshal(_eventParameters, result);
return outWriter.toString();
} catch (JAXBException e) {
_log.error("Failed to generate user message file. "
+ e.getMessage());
throw e;
}
} else {
return null;
}
}
/**
* Set specific embed level for this event in CallHome Identifier section.
*/
@Override
protected void overrideIdentifierData(EmaApiIdentifierType identifier) throws
EmaException {
identifier.setEmbedLevel(EmaApi.EMA_EMBED_LEVEL_EXTERNAL_STR);
}
public int getEventId() {
return _eventId;
}
public void setEventId(int eventId) {
_eventId = eventId;
}
public void setLogNames(List<String> logNames) {
_logNames = logNames;
}
public void setSeverity(int severity) {
_severity = severity;
}
public void setStart(Date start) {
_start = start;
}
public void setEnd(Date end) {
_end = end;
}
public void setNodeIds(List<String> nodeIds) {
_nodeIds = nodeIds;
}
public void setMsgRegex(String msgRegex) {
_msgRegex = msgRegex;
}
public void setEventParameters(EventParameters eventParameters) {
_eventParameters = eventParameters;
}
public void setMaxCount(int maxCount) {
this.maxCount = maxCount;
}
}