package org.hyperic.hq.web.admin.managers;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.appdef.Agent;
import org.hyperic.hq.appdef.server.session.AgentPluginStatus;
import org.hyperic.hq.appdef.server.session.AgentPluginStatusEnum;
import org.hyperic.hq.appdef.server.session.Platform;
import org.hyperic.hq.appdef.shared.AgentManager;
import org.hyperic.hq.auth.shared.SessionNotFoundException;
import org.hyperic.hq.auth.shared.SessionTimeoutException;
import org.hyperic.hq.authz.server.session.AuthzSubject;
import org.hyperic.hq.authz.shared.PermissionException;
import org.hyperic.hq.authz.shared.ResourceManager;
import org.hyperic.hq.bizapp.shared.AppdefBoss;
import org.hyperic.hq.bizapp.shared.AuthzBoss;
import org.hyperic.hq.common.shared.HQConstants;
import org.hyperic.hq.common.shared.ServerConfigManager;
import org.hyperic.hq.product.PlatformDetector;
import org.hyperic.hq.product.Plugin;
import org.hyperic.hq.product.shared.PluginDeployException;
import org.hyperic.hq.product.shared.PluginManager;
import org.hyperic.hq.product.shared.PluginTypeEnum;
import org.hyperic.hq.ui.KeyConstants;
import org.hyperic.hq.web.BaseController;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
@RequestMapping("/admin/managers/plugin")
public class PluginManagerController extends BaseController implements ApplicationContextAware {
private static final Log log = LogFactory.getLog(PluginManagerController.class);
private static final String HELP_PAGE_MAIN = "Administration.Plugin.Manager";
private final PluginManager pluginManager;
private final AgentManager agentManager;
private final ResourceManager resourceManager;
private ApplicationContext applicationContext;
private final ServerConfigManager serverConfigManager;
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm aa zzz");
@Autowired
public PluginManagerController(AppdefBoss appdefBoss, AuthzBoss authzBoss,
PluginManager pluginManager, AgentManager agentManager, ResourceManager resourceManager,
ServerConfigManager serverConfigManager) {
super(appdefBoss, authzBoss);
this.pluginManager = pluginManager;
this.agentManager = agentManager;
this.resourceManager = resourceManager;
this.serverConfigManager = serverConfigManager;
}
@RequestMapping(method = RequestMethod.GET)
public String index(Model model) {
model.addAttribute("info",getAgentInfo());
model.addAttribute("mechanismOn", pluginManager.isPluginSyncEnabled());
if (pluginManager.isPluginSyncEnabled()){
model.addAttribute("instruction", "admin.managers.plugin.instructions");
}else{
model.addAttribute("instruction", "admin.managers.plugin.mechanism.off");
}
model.addAttribute("customDir", pluginManager.getCustomPluginDir().getAbsolutePath());
model.addAttribute(KeyConstants.PAGE_TITLE_KEY, HELP_PAGE_MAIN);
return "admin/managers/plugin";
}
/**
* Get the resource count for each plugin. (The count will be shown in delete confirmation dialog.)
* @param deleteIds
* @return
*/
@RequestMapping(method = RequestMethod.GET, value="/resource/count", headers="Accept=application/json")
public @ResponseBody List<Map<String, String>> getResourceCount(@RequestParam("deleteIds") String deleteIds){
Map<String,String> nameIdMapping = new HashMap<String,String>();
String[] tempDeleteIds = deleteIds.split(",");
List<Plugin> plugins = new ArrayList<Plugin>();
for (int i= 0; i<tempDeleteIds.length;i++){
Plugin plugin = pluginManager.getPluginById(Integer.parseInt(tempDeleteIds[i]));
if(plugin!=null){
plugins.add(plugin);
nameIdMapping.put(plugin.getName(), String.valueOf(plugin.getId()));
}
}
List<Map<String,String>> result = new ArrayList<Map<String,String>>();
Map<String, Long> counts = resourceManager.getResourceCountByPlugin(plugins);
Iterator it = counts.entrySet().iterator();
while(it.hasNext()){
Map.Entry<String, Long> pair = (Map.Entry<String, Long>) it.next();
Map<String,String> count = new HashMap<String, String>();
count.put("pluginId", nameIdMapping.get(pair.getKey()));
count.put("count", String.valueOf(pair.getValue()));
result.add(count);
}
return result;
}
@RequestMapping(method = RequestMethod.GET, value="/list", headers="Accept=application/json")
public @ResponseBody List<Map<String, Object>> getPluginSummaries() {
List<Map<String, Object>> pluginSummaries = new ArrayList<Map<String,Object>>();
List<Map<String, Object>> inProgressPluginSummaries = new ArrayList<Map<String,Object>>();
List<Map<String, Object>> finalPluginSummaries = new ArrayList<Map<String,Object>>();
List<Plugin> plugins = pluginManager.getAllPlugins();
if(plugins!=null){
Comparator<Plugin> sortByPluginName = new Comparator<Plugin>() {
public int compare(Plugin o1, Plugin o2) {
return o1.getName().compareTo(o2.getName());
}
};
Collections.sort(plugins, sortByPluginName);
Map<Integer, Map<AgentPluginStatusEnum, Integer>> allPluginStatus =
pluginManager.getPluginRollupStatus();
for (Plugin plugin : plugins) {
int pluginId = plugin.getId();
Map<String, Object> pluginSummary = new HashMap<String, Object>();
Map<AgentPluginStatusEnum, Integer> pluginStatus =
allPluginStatus.get(pluginId);
pluginSummary.put("id", pluginId);
pluginSummary.put("name", plugin.getName());
pluginSummary.put("jarName", plugin.getPath());
pluginSummary.put("initialDeployDate", formatter.format(plugin.getCreationTime()));
int successAgentCount =0;
int errorAgentCount =0;
int inProgressAgentCount =0;
if (pluginStatus!=null){
successAgentCount = pluginStatus.get(AgentPluginStatusEnum.SYNC_SUCCESS);
errorAgentCount = pluginStatus.get(AgentPluginStatusEnum.SYNC_FAILURE);
inProgressAgentCount = pluginStatus.get(AgentPluginStatusEnum.SYNC_IN_PROGRESS);
}
int allAgentCount = successAgentCount + errorAgentCount +inProgressAgentCount;
boolean isInProgress = false;
if (inProgressAgentCount>0){
isInProgress = true;
}
pluginSummary.put("inProgressAgentCount", inProgressAgentCount);
pluginSummary.put("allAgentCount",allAgentCount);
pluginSummary.put("successAgentCount",successAgentCount);
pluginSummary.put("errorAgentCount",errorAgentCount);
pluginSummary.put("inProgress",isInProgress);
pluginSummary.put("updatedDate", formatter.format(plugin.getModifiedTime()));
pluginSummary.put("version", plugin.getVersion());
pluginSummary.put("disabled", plugin.isDisabled());
pluginSummary.put("deleted", plugin.isDeleted());
boolean isCustom = false;
boolean isServer = false;
Collection<PluginTypeEnum> pluginType = pluginManager.getPluginType(plugin);
if(pluginType!=null){
for(PluginTypeEnum type:pluginType){
switch(type){
case SERVER_PLUGIN:
isServer = true;
break;
case CUSTOM_PLUGIN:
isCustom = true;
break;
default:
break;
}
}
}
pluginSummary.put("isCustomPlugin",isCustom);
pluginSummary.put("isServerPlugin", isServer);
if(errorAgentCount>0){
finalPluginSummaries.add(pluginSummary);
}else if(inProgressAgentCount>0){
inProgressPluginSummaries.add(pluginSummary);
}else{
pluginSummaries.add(pluginSummary);
}
}
finalPluginSummaries.addAll(inProgressPluginSummaries);
finalPluginSummaries.addAll(pluginSummaries);
}
return finalPluginSummaries;
}
@RequestMapping(method = RequestMethod.GET, value="/info", headers="Accept=application/json")
public @ResponseBody Map<String, Object> getAgentInfo() {
Map<String, Object> info = new HashMap<String,Object>();
int agentErrorCount=0;
Map<Integer, AgentPluginStatus> failureAgents = pluginManager.getStatusesByAgentId(AgentPluginStatusEnum.SYNC_FAILURE);
if(failureAgents!=null && failureAgents.size()>0){
agentErrorCount = failureAgents.size();
}
info.put("agentErrorCount", agentErrorCount);
long numAgentsTotal = agentManager.getAgentCountUsed();
long numAutoUpdatingAgents = agentManager.getNumAutoUpdatingAgents();
info.put("syncableAgentCount", numAutoUpdatingAgents);
info.put("totalAgentCount", numAgentsTotal);
String serverVersion = getServerVersion();
info.put("serverVersion", serverVersion);
return info;
}
@RequestMapping(method = RequestMethod.GET, value="/agent/summary", headers="Accept=application/json")
public @ResponseBody List<String> getAgentStatusSummary() {
List<String> agentNames = new ArrayList<String>();
Map<Integer, AgentPluginStatus> failureAgents = pluginManager.getStatusesByAgentId(AgentPluginStatusEnum.SYNC_FAILURE);
for (Map.Entry<Integer, AgentPluginStatus> failedAgent : failureAgents.entrySet()){
AgentPluginStatus status = failedAgent.getValue();
agentNames.add(getAgentName(status.getAgent()));
}
Collections.sort(agentNames);
return agentNames;
}
private List<Map<String,String>> createAgentVersionList(Collection<Agent> agents)
{
List<Map<String,String>> res = new ArrayList<Map<String,String>>(agents.size());
for (Agent agent : agents) {
Map<String,String> agentInfoMap = new HashMap<String, String>(2);
String version = agent.getVersion();
agentInfoMap.put("version", version);
String agentName = getAgentName(agent);
agentInfoMap.put("agentName", agentName);
res.add(agentInfoMap);
}
return res;
}
@RequestMapping(method = RequestMethod.GET, value="/agent/old/summary", headers="Accept=application/json")
public @ResponseBody List<Map<String,String>> getOldAgentStatusSummary() {
List<Agent> oldAgents = agentManager.getOldAgentsUsed();
return (createAgentVersionList(oldAgents));
}
@RequestMapping(method = RequestMethod.GET, value="/agent/unsynchable/cur/summary", headers="Accept=application/json")
public @ResponseBody List<Map<String,String>> getCurrentNonSyncAgentStatusSummary() {
List<Agent> curUnsynchableAgents = agentManager.getCurrentNonSyncAgents();
return (createAgentVersionList(curUnsynchableAgents));
}
@RequestMapping(method = RequestMethod.GET, value="/status/{pluginId}", headers="Accept=application/json")
public @ResponseBody List<Map<String, Object>> getAgentStatus(@PathVariable int pluginId,
@RequestParam("searchWord") String searchWord, @RequestParam("status") String status) {
List<Map<String,Object>> resultAgents = new ArrayList<Map<String,Object>>();
Collection<AgentPluginStatus> agentStatusList ;
if("error".equals(status)){
agentStatusList = pluginManager.getStatusesByPluginId(pluginId, AgentPluginStatusEnum.SYNC_FAILURE);
}else if("inprogress".equals(status)){
agentStatusList = pluginManager.getStatusesByPluginId(pluginId, AgentPluginStatusEnum.SYNC_IN_PROGRESS);
}else{
return resultAgents;
}
for (AgentPluginStatus agentStatus : agentStatusList){
String agentName = getAgentName(agentStatus.getAgent());
if ("".equals(searchWord) || agentName.contains(searchWord)){
Map<String,Object> errorAgent = new HashMap<String,Object>();
errorAgent.put("agentName", agentName);
if(agentStatus.getLastSyncAttempt()!=0){
errorAgent.put("syncDate", formatter.format(agentStatus.getLastSyncAttempt()));
}else{
errorAgent.put("syncDate", "");
}
errorAgent.put("status", status);
resultAgents.add(errorAgent);
}
}
return resultAgents;
}
/**
* @param agent
* @return the address of Agent
*/
private String getAgentName(Agent agent){
Collection <Platform> platforms = agent.getPlatforms();
if(platforms!=null){
for (Platform platform: platforms){
if(PlatformDetector.isSupportedPlatform(platform.getPlatformType().getName())){
return platform.getFqdn();
}
}
}
return agent.getAddress();
}
@RequestMapping(method = RequestMethod.DELETE, value="/delete")
public @ResponseBody String deletePlugin(@RequestParam(RequestParameterKeys.DELETE_ID)
String[] deleteIds, HttpSession session){
AuthzSubject subject;
try {
subject = getAuthzSubject(session);
Collection<String> pluginFilenames = new ArrayList<String>();
for (int i = 0 ; i< deleteIds.length;i++){
Plugin plugin = pluginManager.getPluginById(Integer.parseInt(deleteIds[i]));
pluginFilenames.add(plugin.getPath());
}
pluginManager.removePluginsInBackground(subject, pluginFilenames);
return "success";
} catch (SessionNotFoundException e) {
log.error(e,e);
} catch (SessionTimeoutException e) {
log.error(e,e);
} catch (PermissionException e) {
log.error(e,e);
} catch (PluginDeployException e) {
log.error(e,e);
}
return "error";
}
@RequestMapping(method = RequestMethod.POST, value="/upload")
public String uploadProductPlugin(@RequestParam MultipartFile[] plugins, HttpSession session, Model model) {
boolean success = false;
String messageKey = "";
List<String> filename = new ArrayList<String>() ;
AuthzSubject subject;
Map<String, byte[]> pluginInfo = new HashMap<String, byte[]>();
String[] messageParams = new String[3];
try{
for (int i= 0 ; i<plugins.length;i++){
MultipartFile plugin = plugins[i];
String name = "";
name = plugin.getOriginalFilename();
filename.add(name);
pluginInfo.put(name, plugin.getBytes());
}
} catch (IOException e) {
e.printStackTrace();
messageKey = "admin.managers.plugin.message.io.failure";
}
try {
subject = getAuthzSubject(session);
if (plugins.length>0) {
pluginManager.deployPluginIfValid(subject, pluginInfo);
success = true;
messageKey = "admin.managers.plugin.message.success";
} else {
messageKey = "admin.managers.plugin.message.io.failure";
}
} catch (SessionNotFoundException e) {
log.error(e,e);
messageKey = "admin.managers.plugin.message.io.failure";
} catch (SessionTimeoutException e) {
log.error(e,e);
messageKey = "admin.managers.plugin.message.io.failure";
} catch (PermissionException e) {
log.error(e,e);
messageKey = "admin.managers.plugin.message.io.failure";
} catch (PluginDeployException e){
messageKey = e.getMessage();
Map<Integer, String> param = e.getParameters();
if(param!=null){
for(int i = 0; i<param.size();i++){
messageParams[i]=param.get(i);
}
}
log.error(e,e);
}
model.addAttribute("params", messageParams);
model.addAttribute("success", success);
model.addAttribute("messageKey", messageKey);
return "admin/managers/plugin/upload/status";
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private String getServerVersion() {
String serverVersion = serverConfigManager.getPropertyValue(HQConstants.ServerVersion);
return serverVersion;
}
}