package com.wgcloud.controller; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.github.pagehelper.PageInfo; import com.wgcloud.config.CommonConfig; import com.wgcloud.entity.AccountInfo; import com.wgcloud.entity.ShellInfo; import com.wgcloud.entity.ShellState; import com.wgcloud.entity.SystemInfo; import com.wgcloud.service.LogInfoService; import com.wgcloud.service.ShellInfoService; import com.wgcloud.service.ShellStateService; import com.wgcloud.service.SystemInfoService; import com.wgcloud.util.*; import com.wgcloud.util.msg.WarnMailUtil; import com.wgcloud.util.staticvar.StaticKeys; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @version v3.3 * @ClassName:ShellInfoController.java * @author: http://www.wgstart.com * @date: 2021年8月19日 * @Description: 下发指令执行controller * @Copyright: 2019-2021 wgcloud. All rights reserved. */ @Controller @RequestMapping("/shellInfo") public class ShellInfoController { private static final Logger logger = LoggerFactory.getLogger(ShellInfoController.class); @Resource private ShellInfoService shellInfoService; @Resource private ShellStateService shellStateService; @Resource private LogInfoService logInfoService; @Resource private SystemInfoService systemInfoService; @Autowired private TokenUtils tokenUtils; @Autowired private CommonConfig commonConfig; /** * agent查询下发指令列表 * * @param model * @param request * @return */ @ResponseBody @RequestMapping(value = "agentList") public String agentList(@RequestBody String paramBean) { JSONObject agentJsonObject = (JSONObject) JSONUtil.parse(paramBean); if (!tokenUtils.checkAgentToken(agentJsonObject)) { logger.error(StaticKeys.TOKEN_ERROR); return ResDataUtils.resetErrorJson(StaticKeys.TOKEN_ERROR); } if (!StaticKeys.TRUE_VAL.equals(commonConfig.getShellToRun())) { return ResDataUtils.resetErrorJson("shellToRun is no open"); } Map params = new HashMap(); if (null == agentJsonObject.get("hostname") || StringUtils.isEmpty(agentJsonObject.get("hostname").toString())) { return ""; } params.put("hostname", agentJsonObject.get("hostname").toString()); try { params.put("state", StaticKeys.SHELL_RUN_STATE_1); params.put("shellTime", System.currentTimeMillis()); List shellStateList = shellStateService.selectAllByParams(params); //检测系统类型 begin SystemInfo systemInfo = systemInfoService.selectByHostname(agentJsonObject.get("hostname").toString()); String shellToRunBlock = commonConfig.getShellToRunLinuxBlock(); if (systemInfo != null) { String platForm = systemInfo.getPlatForm().toLowerCase(); if (platForm.contains("windows")) { shellToRunBlock = commonConfig.getShellToRunWinBlock(); } } //检测系统类型 end String blockKey = ""; for (ShellState state : shellStateList) { //检查是否含有敏感字符 blockKey = FormatUtil.haveBlockDanger(state.getShell(), shellToRunBlock, ""); if (!StringUtils.isEmpty(blockKey)) { logger.info(state.getShell() + "下发指令含有敏感字符" + blockKey + ",不进行下发"); shellStateList.remove(state); continue; } //更新状态为已下发 shellStateService.updateSendByIds(state.getId().split(",")); } return ResDataUtils.resetSuccessJson(shellStateList); } catch (Exception e) { logger.error("agent获取下发指令信息错误", e); logInfoService.save("agent获取下发指令信息错误", e.toString(), StaticKeys.LOG_XTCZ); return ResDataUtils.resetErrorJson(e.toString()); } } /** * agent执行指令完成,回调此处 * * @param paramBean * @return */ @ResponseBody @RequestMapping("/shellCallback") public String appCallback(@RequestBody String paramBean) { JSONObject agentJsonObject = (JSONObject) JSONUtil.parse(paramBean); logger.info("shellCallback-------------" + agentJsonObject.toString()); if (!tokenUtils.checkAgentToken(agentJsonObject)) { logger.error(StaticKeys.TOKEN_ERROR); return ResDataUtils.resetErrorJson(StaticKeys.TOKEN_ERROR); } try { String shellStateId = agentJsonObject.getStr("id"); if (StringUtils.isEmpty(shellStateId)) { logger.error("shellStateId is null"); return ResDataUtils.resetErrorJson("shellStateId is null"); } //执行结果错误信息 String shellState = agentJsonObject.getStr("state"); if (!StringUtils.isEmpty(shellState) && shellState.length() > 500) { shellState = shellState.substring(0, 500); } ShellState shellStateCall = shellStateService.selectById(shellStateId); shellStateCall.setState(shellState); shellStateCall.setCreateTime(new Date()); shellStateService.updateById(shellStateCall); return ResDataUtils.resetSuccessJson(null); } catch (Exception e) { logger.error("agent执行指令完成回调错误", e); return ResDataUtils.resetErrorJson(e.toString()); } } /** * 根据条件查询下发指令列表 * * @param model * @param request * @return */ @RequestMapping(value = "list") public String shellInfoList(ShellInfo ShellInfo, Model model, HttpServletRequest request) { Map params = new HashMap(); try { StringBuffer url = new StringBuffer(); String shellName = null; if (!StringUtils.isEmpty(ShellInfo.getShellName())) { shellName = ShellInfo.getShellName(); params.put("shellName", shellName.trim()); url.append("&shellName=").append(shellName); } if (!StringUtils.isEmpty(ShellInfo.getAccount())) { params.put("account", ShellInfo.getAccount()); url.append("&account=").append(ShellInfo.getAccount()); } if (!StringUtils.isEmpty(ShellInfo.getState())) { params.put("state", ShellInfo.getState()); url.append("&state=").append(ShellInfo.getState()); } //校验是否需要添加过滤用户查询条件 HostUtil.addAccountquery(request, params); PageInfo pageInfo = shellInfoService.selectByParams(params, ShellInfo.getPage(), ShellInfo.getPageSize()); //统计指令执行状态数量 begin Map paramsStateCount = new HashMap(); for (ShellInfo shellInfo1 : pageInfo.getList()) { paramsStateCount.clear(); paramsStateCount.put("shellId", shellInfo1.getId()); Integer stateAllCount = shellStateService.countByParams(paramsStateCount); paramsStateCount.put("state", StaticKeys.SHELL_RUN_STATE_1); Integer state1Count = shellStateService.countByParams(paramsStateCount); shellInfo1.setState1Count(state1Count); shellInfo1.setStateOtherCount(stateAllCount - state1Count); if (state1Count == 0) { shellInfo1.setState(StaticKeys.SHELL_STATE_3); } } //统计指令执行状态数量 end PageUtil.initPageNumber(pageInfo, model); //设置用户列表 HostUtil.addAccountListModel(model); model.addAttribute("pageUrl", "/shellInfo/list?1=1" + url.toString()); model.addAttribute("page", pageInfo); model.addAttribute("shellInfo", ShellInfo); model.addAttribute("shellToRun", commonConfig.getShellToRun()); } catch (Exception e) { logger.error("查询下发指令信息错误", e); logInfoService.save("查询下发指令信息错误", e.toString(), StaticKeys.LOG_XTCZ); } return "shellInfo/list"; } /** * 保存下发指令信息 * * @param ShellInfo * @param model * @param request * @return */ @RequestMapping(value = "save") public String saveShellInfo(ShellInfo shellInfo, Model model, HttpServletRequest request) { if (!StaticKeys.TRUE_VAL.equals(commonConfig.getShellToRun())) { return ResDataUtils.resetErrorJson("shellToRun is no open"); } try { //检测指令有无敏感字符 begin String blockKey = FormatUtil.haveBlockDanger(shellInfo.getShell(), commonConfig.getShellToRunLinuxBlock(), commonConfig.getShellToRunWinBlock()); if (!StringUtils.isEmpty(blockKey)) { model.addAttribute("shellInfo", shellInfo); String[] selectedHostnames = request.getParameterValues("hostnames"); model.addAttribute("selectedHosts", selectedHostnames); List systemInfoList = systemInfoService.selectAllByParams(new HashMap<>()); for (SystemInfo systemInfo : systemInfoList) { for (String selectedHost : selectedHostnames) { if (selectedHost.equals(systemInfo.getHostname())) { systemInfo.setSelected("selected"); } } } model.addAttribute("systemInfoList", systemInfoList); model.addAttribute("msg", "下发指令含有敏感字符" + blockKey + ",请检查"); //敏感字符组装 getBlockStr(model); return "shellInfo/add"; } //检测指令有无敏感字符 end //设置下发时间 begin if (StaticKeys.SHELL_TYPE_2.equals(shellInfo.getShellType()) && !StringUtils.isEmpty(shellInfo.getShellTime())) { shellInfo.setShellTime(shellInfo.getShellTime() + ":00"); } //设置下发时间 end if (StringUtils.isEmpty(shellInfo.getId())) { String[] hostnames = request.getParameterValues("hostnames"); if (null == hostnames || hostnames.length < 1) { return "redirect:/shellInfo/list"; } AccountInfo accountInfo = HostUtil.getAccountByRequest(request); if (null != accountInfo) { if (!StaticKeys.ROLE_ADMIN.equals(accountInfo.getRole())) { shellInfo.setAccount(accountInfo.getAccount()); } } shellInfoService.save(shellInfo, hostnames); //发送邮件提示 begin Runnable runnable = () -> { try { if (shellInfo != null) { WarnMailUtil.sendShellInfo(shellInfo, "开始下发指令"); } } catch (Exception e) { e.printStackTrace(); } }; ThreadPoolUtil.executor.execute(runnable); //发送邮件提示 end } else { shellInfoService.updateById(shellInfo); } } catch (Exception e) { logger.error("保存下发指令错误", e); logInfoService.save("保存下发指令错误", e.toString(), StaticKeys.LOG_XTCZ); } return "redirect:/shellInfo/list"; } /** * 添加 * * @param model * @param request * @return */ @RequestMapping(value = "edit") public String edit(Model model, HttpServletRequest request) { String errorMsg = "添加下发指令"; String id = request.getParameter("id"); ShellInfo ShellInfo = new ShellInfo(); try { //校验是否需要添加过滤用户查询条件 Map paramsAccount = new HashMap(); HostUtil.addAccountquery(request, paramsAccount); List systemInfoList = systemInfoService.selectAllByParams(paramsAccount); model.addAttribute("systemInfoList", systemInfoList); //敏感字符组装 getBlockStr(model); if (StringUtils.isEmpty(id)) { model.addAttribute("shellInfo", ShellInfo); return "shellInfo/add"; } ShellInfo = shellInfoService.selectById(id); model.addAttribute("ShellInfo", ShellInfo); } catch (Exception e) { logger.error(errorMsg, e); logInfoService.save(errorMsg, e.toString(), StaticKeys.LOG_XTCZ); } return "shellInfo/add"; } /** * 查看指令下发执行状态信息 * * @param model * @param request * @return */ @RequestMapping(value = "view") public String view(Model model, HttpServletRequest request) { String errorMsg = "查看指令下发执行状态信息错误"; String id = request.getParameter("id"); ShellInfo ShellInfo = new ShellInfo(); try { ShellInfo = shellInfoService.selectById(id); Map params = new HashMap(); params.put("shellId", id); List shellStateList = shellStateService.selectAllByParams(params); //提取主机备注 begin for (ShellState shellState1 : shellStateList) { shellState1.setHostname(shellState1.getHostname() + HostUtil.addRemark(shellState1.getHostname())); } //提取主机备注 end model.addAttribute("shellStateList", shellStateList); model.addAttribute("shellInfo", ShellInfo); } catch (Exception e) { logger.error(errorMsg, e); logInfoService.save(errorMsg, e.toString(), StaticKeys.LOG_XTCZ); } return "shellInfo/stateList"; } /** * 取消下发指令 * * @param id * @param model * @param request * @param redirectAttributes * @return */ @ResponseBody @RequestMapping(value = "cancel") public String cancel(Model model, HttpServletRequest request, RedirectAttributes redirectAttributes) { String errorMsg = "取消下发指令信息错误"; try { if (!StringUtils.isEmpty(request.getParameter("id"))) { ShellInfo shellInfo = shellInfoService.selectById(request.getParameter("id")); shellInfoService.cancelShell(request.getParameter("id")); //发送邮件提示 begin Runnable runnable = () -> { try { if (shellInfo != null) { WarnMailUtil.sendShellInfo(shellInfo, "取消下发指令"); } } catch (Exception e) { e.printStackTrace(); } }; ThreadPoolUtil.executor.execute(runnable); //发送邮件提示 end } } catch (Exception e) { logger.error(errorMsg, e); logInfoService.save(errorMsg, e.toString(), StaticKeys.LOG_XTCZ); } return ResDataUtils.resetSuccessJson(null); } /** * 删除下发执行信息,不删除执行状态数据 * * @param id * @param model * @param request * @param redirectAttributes * @return */ @RequestMapping(value = "del") public String delete(Model model, HttpServletRequest request, RedirectAttributes redirectAttributes) { String errorMsg = "删除下发执行信息错误"; try { if (!StringUtils.isEmpty(request.getParameter("id"))) { String[] ids = request.getParameter("id").split(","); for (String id : ids) { ShellInfo shellInfo = shellInfoService.selectById(id); //发送邮件提示 begin Runnable runnable = () -> { try { if (shellInfo != null) { WarnMailUtil.sendShellInfo(shellInfo, "删除下发指令"); } } catch (Exception e) { e.printStackTrace(); } }; ThreadPoolUtil.executor.execute(runnable); //发送邮件提示 end } shellInfoService.deleteById(ids); } } catch (Exception e) { logger.error(errorMsg, e); logInfoService.save(errorMsg, e.toString(), StaticKeys.LOG_XTCZ); } return "redirect:/shellInfo/list"; } /** * 提取已配置的敏感字符串 * * @return */ private void getBlockStr(Model model) { //敏感字符组装 begin String blockStr = ""; if (!StringUtils.isEmpty(commonConfig.getShellToRunLinuxBlock())) { blockStr = "[linux不能包含敏感字符:" + commonConfig.getShellToRunLinuxBlock() + "]"; } if (!StringUtils.isEmpty(commonConfig.getShellToRunLinuxBlock())) { blockStr += "[windows不能包含敏感字符:" + commonConfig.getShellToRunWinBlock() + "]"; } model.addAttribute("blockStr", blockStr); //敏感字符组装 end } }