DowntimeServer.java 12.3 KB
package com.sitech.ismp.check.downtime;

import com.sitech.ismp.app.event.KPI2Event;
import com.sitech.ismp.coll.basic.TblATO_EVENT;
import com.sitech.util.Base62Util;
import com.sitech.util.RandomGUID;
import com.sitech.util.upload.RomoteController;
import com.sitech.util.upload.SSHThread;
import com.sitech.util.upload.TelnetThread;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

/**
 * @author frank  zmm@honggroup.com.cn
 * @Description:  宕机检测MBean对应Server类。
 *                ping的布尔结果 true:能ping通, false:ping不通
 *                ssh连接的布尔结果 true:能ssh连接, false:ssh连接异常
 * @Package com.sitech.ismp.check.downtime
 * @ClassName: com.sitech.ismp.check.downtime.DowntimeServer
 * @date 2017年04月12日 16:22
 */
public class DowntimeServer implements Runnable{

    private static Logger log=Logger.getLogger(DowntimeServer.class);
    private DowntimeBean bean;
    DowntimeHistoryDao historyDao=new DowntimeHistoryDao();

    public DowntimeServer(DowntimeBean bean){
        this.bean=bean;
    }

    /**
     * 1 对表中的主机进行ping操作。
     * 2 对表中的主机进行SSH登录认证。
     * 3 发送告警信息。
     */
    @Override
    public void run(){
        getPingResult(bean);
        getSshResult(bean);
        sendEvent2Workstation(bean);
    }

    /**
     * 将每个IP ping后的结果设置到pingState属性上。
     * @param bean
     * @return
     */
    public void getPingResult(DowntimeBean bean){
        String ipAddr=null;
        log.info("============================== ping all parames ======================");
        log.info(bean.toString());
        ipAddr=bean.getDEVICE_IP();
        boolean temp=pingIpAddress(ipAddr);
        bean.setPingState(temp);

    }

    /**
     * 进行SSH连接,并设置对应告警的内容。
     * @param bean
     * @return
     */
    public void getSshResult(DowntimeBean bean){
        boolean pingState=bean.isPingState(); // true:能ping通, false:ping不通
        log.info("========== pingState=== "+pingState+"==========");
        boolean sshState=contentWithSsh(bean);
        log.info("========== sshState=== "+sshState+"==========");
        if(!pingState){ // ping 不通 false
            if(!sshState){ // ssh 不能连接 严重告警
                bean.setWarningLevel(1);
                bean.setWarningResult(bean.getDEVICE_IP()+" 的主机连接异常,请检查网络是否正常或主机宕机!");
                log.info("========== bean.setWarningResult sshState ="+sshState+",=ip is ["+bean.getDEVICE_IP()+"] host connect error");
            }
        }else{ //能ping 通
            if(!sshState){ // ssh 不能连接 重要告警
                bean.setWarningLevel(2);
                bean.setWarningResult(bean.getDEVICE_IP()+" 的主机不能进行登录,请检查用户名或密码!!");
                log.info("========== bean.setWarningResult sshState ="+sshState+",=ip is["+bean.getDEVICE_IP()+"] host login error");
            }
        }
    }

    /**
     * 将告警信息发送到Workstation。
     * 当ping的结果为false的时候才发送。
     * @param bean
     */
    private void sendEvent2Workstation(DowntimeBean bean){
        log.info("******************************************************");
        log.info("*************** sendEvent2Workstation ****************");
        log.info("******************************************************");
        log.info(bean.toString());
        if(!bean.isSshState()){
            KPI2Event event=new KPI2Event();
            TblATO_EVENT tblato_event = new TblATO_EVENT();
            String eventId= RandomGUID.getRandomGUID();
            try {
                tblato_event.setEVENT_ID(eventId); // 随即生成一个GUID作为唯一键
                tblato_event.setUNIT_ID(bean.getUnitId());  // UNIT_ID在页面显示的为平台类型。
                tblato_event.setKPI_ID("FM-00-01-001-999");
                tblato_event.setKPI_VALUE(bean.getWarningResult());
                tblato_event.setEVENT_TITLE(bean.getWarningResult());
                tblato_event.setEVENT_CLASS(bean.getWarningLevel()); // 告警级别
                tblato_event.setCLL_TIME(new java.util.Date());
                tblato_event.setGENERANT_TIME(new java.util.Date());
                tblato_event.setCFG_GUID(RandomGUID.getRandomGUID());
                log.info("hava finish set values to TblATO_EVENT!");
            } catch (ParseException e) {
                log.error("set values to TblATO_EVENT hava error!",e);
            }
            try {
                event.sendEvent2Workstation(tblato_event);
                addDowntimeHistory(bean);
                log.info("have write object(TblATO_EVENT) to Workstation!");
            } catch (Exception e) {
                log.error("have write object(TblATO_EVENT) to Workstation have error!",e);
            }
        }
    }


    private void addDowntimeHistory(DowntimeBean bean){
        DowntimeHistoryBean historyBean=new DowntimeHistoryBean();
        historyBean.setDEVICE_ID(bean.getDEVICE_ID());
        historyBean.setDEVICE_IP(bean.getDEVICE_IP());
        SimpleDateFormat formaF=new SimpleDateFormat("yyyy-MM-dd");
        String date=formaF.format(new Date())+"";
        date=date.substring(0,10);
        historyBean.setCREATE_DATE(date);
        historyDao.addDowntimeHistory(historyBean);
    }


    /**
     * 获取ping 后的结果,是否可以平通指定的IP。
     * @param ipAddr
     * @return
     */
    private boolean pingIpAddress(String ipAddr){
        int pingErrorCount=0; // ping 不通的次数,ping3次。
        int interval=8; // 时间间隔8秒。
        boolean flag=false;
        boolean temp=false;
        for(int i=0;i<3;i++){
            temp=executeCommand(ipAddr); // ping不通返回false。
            log.info("["+ipAddr+"]ping result is ["+temp+"],(true:can connect;false:can't connect)");
            if(!temp){
                pingErrorCount++;
            }
            try {
                Thread.sleep(interval*1000);
                log.info("ping ["+ipAddr+"] trread sleep "+interval+" secound........");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if(pingErrorCount == 3){
            log.info("["+ipAddr+"] can't connect 3 times.");
        }else{
            flag=true;
            log.info("["+ipAddr+"] can connect.");
        }
        return flag;
    }


    /**
     * 进行ssh连接,判断是否可以连接成功。
     * windows操作系统使用 TelnetThread类连接。 Windows的客户端需要配置并开启Telnet相关的服务。
     * @return
     */
    private boolean contentWithSsh(DowntimeBean bean){
        String protocol=bean.getPROTOCOL();
        String ipAddr=bean.getDEVICE_IP();
        String deviceAlias=bean.getDEVICE_ALIAS();
        int protocolPort=bean.getPROTOCOL_PORT();
        String userName=bean.getUSER_NAME();
        String password=bean.getPASSWORD();
        bean.setUnitId(getUnitId(deviceAlias));
        log.info("execute contentWithSsh method ......");
        boolean temp=false;
        RomoteController tt = null;
        log.info("host params is: ipAddr="+ipAddr+",protocol="+protocol+",protocolPort="+protocolPort+",userName="+userName);
        if(loginParamterIsOk(protocol,ipAddr,protocolPort,userName,password,deviceAlias)){
            try {
                if (protocol != null && protocol.equalsIgnoreCase("telnet")) {
                    tt = new TelnetThread(ipAddr, protocolPort, userName, password);
                } else if (protocol != null && protocol.equalsIgnoreCase("ssh")) {
                    tt = new SSHThread(ipAddr, protocolPort, userName, password);
                }else{
                    log.error("===================== unknown protocol =====================");
                }
            }catch (Exception e){
                log.error(protocol+"connect have exception!");
            }
            tt.initial();
            boolean flag=tt.isAuthorized();
            log.info("******************* tt.isAuthorized() result is "+flag);
            if (flag){ // 认证通过
                log.info(ipAddr+" SSH connect,Authorized result is true authorized success!");
                temp=true;
                bean.setSshState(true);
            }else{
                log.info(ipAddr+" SSH connect,Authorized result is false authorized fail!!");
                bean.setSshState(false);
            }
        }
        return temp;
    }


    /**
     * 判断所有的参数是否为空。
     * @param protocol 协议类型
     * @param ipAddr IP地址
     * @param protocolPort 协议端口
     * @param userName 用户名
     * @param password 密码
     * @param deviceAlias 主机别名
     * @return
     */
    private boolean loginParamterIsOk(String protocol,String ipAddr,int protocolPort,String userName,
                                      String password,String deviceAlias){
        boolean flag=true;
        if(StringUtils.isEmpty(protocol)){
            flag=false;
        }
        if(StringUtils.isEmpty(ipAddr)){
            flag=false;
        }
        if(StringUtils.isEmpty(protocolPort+"")){
            flag=false;
        }
        if(StringUtils.isEmpty(userName)){
            flag=false;
        }
        if(StringUtils.isEmpty(password)){
            flag=false;
        }
        if(StringUtils.isEmpty(deviceAlias)){
            flag=false;
        }
        return flag;
    }


    private String getUnitId(String deviceAlias){
        StringBuffer bf=new StringBuffer("10-10-99-98:");
        bf.append(deviceAlias).append("_").append(getEncryptStr());
        return bf.toString();
    }

    /**
     * 返回加密后的一个唯一字符串。
     * @return
     */
    private String getEncryptStr(){
        SimpleDateFormat forma=new SimpleDateFormat("yyMMddHHmmss");
        Random rr= new Random();
        String str=rr.nextInt(999)+forma.format(new Date())+rr.nextInt(999);
        return Base62Util.encode(Long.parseLong(str));
    }


    /**
     * 返回ping后的结果。
     * @param ipAddr ip 地址。
     * @return
     */
    private boolean executeCommand(String ipAddr){
        String command = "/bin/ping -c 3 -w 3 " + ipAddr;;
        // 执行command 命令。
        boolean flag=false;
        String line = null;
        StringBuilder sb = new StringBuilder();
        Runtime runtime = Runtime.getRuntime();
        Process process = null;
        long startTime = new Date().getTime();
        try {
            process = runtime.exec(command);
        } catch (IOException e) {
            log.error("execute command ["+command+"] has some error!");
        }
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        try {
            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            log.error("======== bufferedReader.readLine() has some error!");
        }

        String pingResult=sb.toString();
        /**
         *  当执行结果出现下面字符说明已经执行完成。
         *  ping 通的时候 结果包含【min/avg/max/mdev】
         *  ping 不通的时候 结果包含【100% packet loss】
         */
        if(pingResult.contains("100% packet loss") || (pingResult.contains("min/avg/max/mdev"))){
            process.destroy();
            log.info("execute command ["+command+"] finish!");
        }


        String os = System.getProperty("os.name").toLowerCase();
        log.info("------------ operator system is :" + os);

        // 解析command命令结果,包含【100% packet loss】 意味着ping不通,返回 false。
        if(os.indexOf("linux") >= 0){
            if (!StringUtils.isEmpty(pingResult)) {
                if(!pingResult.contains("100% packet loss")){
                    flag = true;
                }
            }
        }
        return flag;
    }


    /**
     * 添加已经发送的告警信息。
     * @param bean,取出对象中的ID与IP,外加时间(年月日)
     */
    public void addSendedEvent(DowntimeBean bean){

    }

}