/**
* Copyright (c) 2013--2014 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.rhn.frontend.xmlrpc.system.crash;
import com.redhat.rhn.common.conf.Config;
import com.redhat.rhn.common.conf.ConfigDefaults;
import com.redhat.rhn.domain.rhnpackage.PackageArch;
import com.redhat.rhn.domain.rhnpackage.PackageEvr;
import com.redhat.rhn.domain.rhnpackage.PackageEvrFactory;
import com.redhat.rhn.domain.rhnpackage.PackageFactory;
import com.redhat.rhn.domain.rhnpackage.PackageName;
import com.redhat.rhn.domain.server.Crash;
import com.redhat.rhn.domain.server.CrashCount;
import com.redhat.rhn.domain.server.CrashFactory;
import com.redhat.rhn.domain.server.CrashFile;
import com.redhat.rhn.domain.server.CrashNote;
import com.redhat.rhn.domain.server.Server;
import com.redhat.rhn.domain.user.User;
import com.redhat.rhn.frontend.xmlrpc.BaseHandler;
import com.redhat.rhn.frontend.xmlrpc.NoCrashesFoundException;
import com.redhat.rhn.frontend.xmlrpc.CrashFileDownloadException;
import com.redhat.rhn.frontend.xmlrpc.RhnXmlRpcServer;
import com.redhat.rhn.frontend.dto.CrashSystemsDto;
import com.redhat.rhn.frontend.dto.IdenticalCrashesDto;
import com.redhat.rhn.frontend.xmlrpc.system.XmlRpcSystemHelper;
import com.redhat.rhn.manager.download.DownloadManager;
import com.redhat.rhn.manager.system.CrashManager;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* CrashHandler
* @version $Rev$
* @xmlrpc.namespace system.crash
* @xmlrpc.doc Provides methods to access and modify software crash information.
*/
public class CrashHandler extends BaseHandler {
private static float freeMemCoeff = 0.9f;
private CrashCount getCrashCount(Server serverIn) {
CrashCount crashCount = serverIn.getCrashCount();
if (crashCount == null) {
throw new NoCrashesFoundException();
}
return crashCount;
}
/**
* Return crash count information
* @param loggedInUser The current user
* @param serverId Server ID
* @return Return crash count information
*
* @xmlrpc.doc Return date of last software crashes report for given system
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.param #param("int", "serverId")
* @xmlrpc.returntype
* #struct("Crash Count Information")
* #prop_desc("int", "total_count",
* "Total number of software crashes for a system")
* #prop_desc("int", "unique_count",
* "Number of unique software crashes for a system")
* #prop_desc("dateTime.iso8601", "last_report",
* "Date of the last software crash report")
* #struct_end()
*/
public Map getCrashCountInfo(User loggedInUser, Integer serverId) {
XmlRpcSystemHelper sysHelper = XmlRpcSystemHelper.getInstance();
Server server = sysHelper.lookupServer(loggedInUser, serverId);
Map returnMap = new HashMap();
CrashCount crashCount = null;
try {
crashCount = getCrashCount(server);
}
catch (NoCrashesFoundException e) {
returnMap.put("total_count", 0);
returnMap.put("unique_count", 0);
return returnMap;
}
returnMap.put("total_count", crashCount.getTotalCrashCount());
returnMap.put("unique_count", crashCount.getUniqueCrashCount());
returnMap.put("last_report", crashCount.getLastReport());
return returnMap;
}
/**
* Returns list of software crashes for a system.
* @param loggedInUser The current user
* @param serverId Server ID
* @return Returns list of software crashes for given system id.
*
* @xmlrpc.doc Return list of software crashes for a system.
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.param #param("int", "serverId")
* @xmlrpc.returntype
* #array()
* #struct("crash")
* #prop("int", "id")
* #prop("string", "crash")
* #prop("string", "path")
* #prop("int", "count")
* #prop("string", "uuid")
* #prop("string", "analyzer")
* #prop("string", "architecture")
* #prop("string", "cmdline")
* #prop("string", "component")
* #prop("string", "executable")
* #prop("string", "kernel")
* #prop("string", "reason")
* #prop("string", "username")
* #prop("date", "created")
* #prop("date", "modified")
* #struct_end()
* #array_end()
*/
public List listSystemCrashes(User loggedInUser, Integer serverId) {
XmlRpcSystemHelper sysHelper = XmlRpcSystemHelper.getInstance();
Server server = sysHelper.lookupServer(loggedInUser, serverId);
List returnList = new ArrayList();
for (Crash crash : server.getCrashes()) {
Map crashMap = new HashMap();
crashMap.put("id", crash.getId());
crashMap.put("crash", crash.getCrash());
crashMap.put("path", crash.getPath());
crashMap.put("count", crash.getCount());
crashMap.put("uuid",
StringUtils.defaultString(crash.getUuid()));
crashMap.put("analyzer",
StringUtils.defaultString(crash.getAnalyzer()));
crashMap.put("architecture",
StringUtils.defaultString(crash.getArchitecture()));
crashMap.put("cmdline",
StringUtils.defaultString(crash.getCmdline()));
crashMap.put("component",
StringUtils.defaultString(crash.getComponent()));
crashMap.put("executable",
StringUtils.defaultString(crash.getExecutable()));
crashMap.put("kernel",
StringUtils.defaultString(crash.getKernel()));
crashMap.put("reason",
StringUtils.defaultString(crash.getReason()));
crashMap.put("username",
StringUtils.defaultString(crash.getUsername()));
crashMap.put("created", crash.getCreated());
crashMap.put("modified", crash.getModified());
if (crash.getPackageNameId() != null) {
PackageName pname = PackageFactory.lookupPackageName(
crash.getPackageNameId());
crashMap.put("package_name", pname.getName());
}
if (crash.getPackageEvrId() != null) {
PackageEvr pevr = PackageEvrFactory.lookupPackageEvrById(
crash.getPackageEvrId());
crashMap.put("package_epoch", pevr.getEpoch());
crashMap.put("package_version", pevr.getVersion());
crashMap.put("package_release", pevr.getRelease());
}
if (crash.getPackageArchId() != null) {
PackageArch parch = PackageFactory.lookupPackageArchById(
crash.getPackageArchId());
crashMap.put("package_arch", parch.getLabel());
}
returnList.add(crashMap);
}
return returnList;
}
/**
* Returns list of crash files for a given crash id.
* @param loggedInUser The current user
* @param crashId Crash ID
* @return Returns list of crash files.
*
* @xmlrpc.doc Return list of crash files for given crash id.
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.param #param("int", "crashId")
* @xmlrpc.returntype
* #array()
* #struct("crashFile")
* #prop("int", "id")
* #prop("string", "filename")
* #prop("string", "path")
* #prop("int", "filesize")
* #prop("boolean", "is_uploaded")
* #prop("date", "created")
* #prop("date", "modified")
* #struct_end()
* #array_end()
*/
public List listSystemCrashFiles(User loggedInUser, Integer crashId) {
Crash crash = CrashManager.lookupCrashByUserAndId(loggedInUser,
new Long(crashId.longValue()));
List returnList = new ArrayList();
for (CrashFile crashFile : crash.getCrashFiles()) {
Map crashMap = new HashMap();
crashMap.put("id", crashFile.getId());
crashMap.put("filename", crashFile.getFilename());
crashMap.put("path", crashFile.getPath());
crashMap.put("filesize", crashFile.getFilesize());
crashMap.put("is_uploaded", crashFile.getIsUploaded());
crashMap.put("created", crashFile.getCreated());
crashMap.put("modified", crashFile.getModified());
returnList.add(crashMap);
}
return returnList;
}
/**
* Delete a crash with given crash id.
* @param loggedInUser The current user
* @param crashId Crash ID
* @return 1 In case of success, exception otherwise.
*
* @xmlrpc.doc Delete a crash with given crash id.
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.param #param("int", "crashId")
* @xmlrpc.returntype #return_int_success()
*/
public Integer deleteCrash(User loggedInUser, Integer crashId) {
CrashManager.deleteCrash(loggedInUser, new Long(crashId.longValue()));
return 1;
}
/**
* Get a crash file download url
* @param loggedInUser The current user
* @param crashFileId Crash File ID
* @return Return a download url string.
*
* @xmlrpc.doc Get a crash file download url.
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.param #param("int", "crashFileId")
* @xmlrpc.returntype string - The crash file download url
*/
public String getCrashFileUrl(User loggedInUser, Integer crashFileId) {
CrashFile crashFile = CrashManager.lookupCrashFileByUserAndId(loggedInUser,
new Long(crashFileId.longValue()));
return RhnXmlRpcServer.getProtocol() + "://" +
RhnXmlRpcServer.getServerName() +
DownloadManager.getCrashFileDownloadPath(crashFile, loggedInUser);
}
/**
* Download a base64 encoded crash file.
* @param loggedInUser The current user
* @param crashFileId Crash File ID
* @return Return a byte array of the crash file.
* @throws IOException if there is an exception
*
* @xmlrpc.doc Download a crash file.
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.param #param("int", "crashFileId")
* @xmlrpc.returntype base64 - base64 encoded crash file.
*/
public byte[] getCrashFile(User loggedInUser, Integer crashFileId) throws IOException {
CrashFile crashFile = CrashManager.lookupCrashFileByUserAndId(loggedInUser,
new Long(crashFileId.longValue()));
String path = Config.get().getString(ConfigDefaults.MOUNT_POINT) + "/" +
crashFile.getCrash().getStoragePath() + "/" +
crashFile.getFilename();
File file = new File(path);
if (file.length() > freeMemCoeff * Runtime.getRuntime().freeMemory()) {
throw new CrashFileDownloadException("api.crashfile.download.toolarge");
}
byte[] plainFile = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream br = new BufferedInputStream(fis);
if (br.read(plainFile) != file.length()) {
throw new CrashFileDownloadException("api.package.download.ioerror");
}
fis.close();
br.close();
return Base64.encodeBase64(plainFile);
}
/**
* @param loggedInUser The current user
* @param crashId Crash ID
* @param subject Crash note subject
* @param details Crash note details
* @return 1 on success
*
* @xmlrpc.doc Create a crash note
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.param #param("int", "crashId")
* @xmlrpc.param #param("string", "subject")
* @xmlrpc.param #param("string", "details")
* @xmlrpc.returntype #return_int_success()
*/
public int createCrashNote(User loggedInUser, Integer crashId,
String subject, String details) {
if (StringUtils.isBlank(subject)) {
throw new IllegalArgumentException("Crash note subject is required");
}
CrashNote cn = new CrashNote();
cn.setSubject(subject);
cn.setNote(details);
cn.setCreator(loggedInUser);
cn.setCrash(CrashManager.lookupCrashByUserAndId(loggedInUser,
crashId.longValue()));
CrashFactory.save(cn);
return 1;
}
/**
* @param loggedInUser The current user
* @param crashNoteId Crash note ID
* @return 1 on success
*
* @xmlrpc.doc Delete a crash note
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.param #param("int", "crashNoteId")
* @xmlrpc.returntype #return_int_success()
*/
public int deleteCrashNote(User loggedInUser, Integer crashNoteId) {
CrashNote cn = CrashManager.lookupCrashNoteByUserAndId(loggedInUser,
crashNoteId.longValue());
CrashFactory.delete(cn);
return 1;
}
/**
* @param loggedInUser The current user
* @param crashId Crash ID
* @return Crash notes for crash
*
* @xmlrpc.doc List crash notes for crash
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.param #param("int", "crashId")
* @xmlrpc.returntype
* #array()
* #struct("crashNote")
* #prop("int", "id")
* #prop("string", "subject")
* #prop("string", "details")
* #prop("string", "updated")
* #struct_end()
* #array_end()
*/
public List getCrashNotesForCrash(User loggedInUser, Integer crashId) {
Crash c = CrashManager.lookupCrashByUserAndId(loggedInUser,
crashId.longValue());
List returnList = new ArrayList();
for (CrashNote cn : c.getCrashNotes()) {
Map crashNotesMap = new HashMap();
crashNotesMap.put("id", cn.getId());
crashNotesMap.put("subject", cn.getSubject());
crashNotesMap.put("details", cn.getNote() == null ? "" : cn.getNote());
crashNotesMap.put("updated", cn.getModifiedString());
returnList.add(crashNotesMap);
}
return returnList;
}
/**
* @param loggedInUser The current user
* @return Software Crash Overview
*
* @xmlrpc.doc Get Software Crash Overview
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.returntype
* #array()
* #struct("crash")
* #prop_desc("string", "uuid", "Crash UUID")
* #prop_desc("string", "component",
* "Package component (set if unique and non empty)")
* #prop_desc("int", "crash_count", "Number of crashes occurred")
* #prop_desc("int", "system_count", "Number of systems affected")
* #prop_desc("dateTime.iso8601", "last_report", "Last crash occurence")
* #struct_end()
* #array_end()
*/
public List getCrashOverview(User loggedInUser) {
List returnList = new ArrayList();
for (IdenticalCrashesDto ic : CrashFactory.listIdenticalCrashesForOrg(loggedInUser,
loggedInUser.getOrg())) {
Map crashMap = new HashMap();
crashMap.put("uuid", ic.getUuid());
String component = ic.getComponent();
if (component != null) {
crashMap.put("component", component);
}
crashMap.put("crash_count", ic.getTotalCrashCount());
crashMap.put("system_count", ic.getSystemCount());
crashMap.put("last_report", ic.getLastCrashReport());
returnList.add(crashMap);
}
return returnList;
}
/**
* @param loggedInUser The current user
* @param uuid Crash UUID to search for
* @return List of crashes with given UUID
*
* @xmlrpc.doc List software crashes with given UUID
* @xmlrpc.param #param("string", "sessionKey")
* @xmlrpc.param #param("string", "uuid")
* @xmlrpc.returntype
* #array()
* #struct("crash")
* #prop_desc("int", "server_id",
* "ID of the server the crash occurred on")
* #prop_desc("string", "server_name",
* "Name of the server the crash occurred on")
* #prop_desc("int", "crash_id", "ID of the crash with given UUID")
* #prop_desc("int", "crash_count",
* "Number of times the crash with given UUID occurred")
* #prop_desc("string", "crash_component", "Crash component")
* #prop_desc("dateTime.iso8601", "last_report", "Last crash occurence")
* #struct_end()
* #array_end()
*/
public List getCrashesByUuid(User loggedInUser, String uuid) {
List returnList = new ArrayList();
for (CrashSystemsDto cs : CrashFactory.listCrashSystems(loggedInUser,
loggedInUser.getOrg(), uuid)) {
Map crashMap = new HashMap();
crashMap.put("server_id", cs.getServerId());
crashMap.put("server_name", cs.getServerName());
crashMap.put("crash_id", cs.getCrashId());
crashMap.put("crash_count", cs.getCrashCount());
crashMap.put("crash_component", cs.getCrashComponent());
crashMap.put("last_report", cs.getLastReport());
returnList.add(crashMap);
}
return returnList;
}
}