Java tutorial
/* Copyright (C) 2008 NTT DATA Corporation This program is free software; you can redistribute it and/or Modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ package com.clustercontrol.poller.impl; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.snmp4j.CommunityTarget; import org.snmp4j.PDU; import org.snmp4j.Snmp; import org.snmp4j.Target; import org.snmp4j.UserTarget; import org.snmp4j.mp.MPv3; import org.snmp4j.mp.SnmpConstants; import org.snmp4j.security.AuthMD5; import org.snmp4j.security.AuthSHA; import org.snmp4j.security.PrivAES128; import org.snmp4j.security.PrivDES; import org.snmp4j.security.SecurityLevel; import org.snmp4j.security.SecurityModels; import org.snmp4j.security.SecurityProtocols; import org.snmp4j.security.USM; import org.snmp4j.security.UsmUser; import org.snmp4j.smi.OID; import org.snmp4j.smi.OctetString; import org.snmp4j.smi.SMIConstants; import org.snmp4j.smi.UdpAddress; import org.snmp4j.smi.Variable; import org.snmp4j.smi.VariableBinding; import org.snmp4j.util.DefaultPDUFactory; import com.clustercontrol.bean.SnmpProtocolConstant; import com.clustercontrol.bean.SnmpSecurityLevelConstant; import com.clustercontrol.fault.SnmpResponseError; import com.clustercontrol.maintenance.util.HinemosPropertyUtil; import com.clustercontrol.nodemap.util.SearchConnectionProperties; import com.clustercontrol.poller.bean.PollerProtocolConstant; import com.clustercontrol.poller.util.DataTable; import com.clustercontrol.poller.util.TableEntry; import com.clustercontrol.poller.util.TableEntry.ErrorType; import com.clustercontrol.repository.util.SearchDeviceProperties; import com.clustercontrol.util.HinemosTime; import com.clustercontrol.util.MessageConstant; /** * snmp4j????snmp? * * v3???????????????? * https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/sect-System_Monitoring_Tools-Net-SNMP-Configuring.html */ public class Snmp4jPollerImpl { private final static Log log = LogFactory.getLog(Snmp4jPollerImpl.class); private static final String PROP_DELETE_LABEL = "monitor.resource.delete.label"; private final static String PROP_NON_REPEATERS = "monitor.poller.snmp.bulk.nonrepeaters"; private final static String PROP_MAX_REPETITIONS = "monitor.poller.snmp.bulk.maxrepetitions"; private final static String PROP_NOT_V3_SNMP_POOL_SIZE = "monitor.poller.snmp.not.v3.snmp.pool.size"; public final static String LABEL_REPLACE_KEY = "monitor.resource.label.replace"; public final static String LABEL_REPLACE_DEFAULT = " Label:\\S* Serial Number .*"; private final List<String> processOidList; private final Integer maxRepetitions = HinemosPropertyUtil .getHinemosPropertyNum(PROP_MAX_REPETITIONS, Long.valueOf(10)).intValue(); private final Integer nonRepeaters = HinemosPropertyUtil .getHinemosPropertyNum(PROP_NON_REPEATERS, Long.valueOf(0)).intValue(); private final boolean deleteLabel = HinemosPropertyUtil.getHinemosPropertyBool(PROP_DELETE_LABEL, true); private final int notV3SnmpPoolSize = HinemosPropertyUtil .getHinemosPropertyNum(PROP_NOT_V3_SNMP_POOL_SIZE, Long.valueOf(32)).intValue(); private List<Snmp> notV3SnmpPool = new ArrayList<Snmp>(notV3SnmpPoolSize); private int notV3SnmpPoolIndex = 0; private static Snmp4jPollerImpl instance = new Snmp4jPollerImpl(); private Snmp4jPollerImpl() { try { for (int i = 0; i < notV3SnmpPoolSize; i++) { notV3SnmpPool.add(createNotV3Snmp()); } } catch (IOException e) { log.warn("IOException message=" + e.getMessage()); } String oidName = ".1.3.6.1.2.1.25.4.2.1.2"; String oidParam = ".1.3.6.1.2.1.25.4.2.1.5"; String oidPath = ".1.3.6.1.2.1.25.4.2.1.4"; processOidList = new ArrayList<String>(); processOidList.add(oidName); processOidList.add(oidParam); processOidList.add(oidPath); } public static Snmp4jPollerImpl getInstance() { return instance; } /** * SNMP????DataTable???? * * @param ipAddress IP * @param port ?? * @param version ?0:SNMP V1 protocol, 1:SNMP V2 protocol, 3: SNMP V3 protocol * @param community * @param retries ???? * @param timeout ?? * @param oidSet OID? * @param securityLevel v3 * @param user ??v3 * @param authPassword ?v3 * @param privPassword ?v3 * @param authProtocol ?v3 * @param privProtocol ?v3 */ public DataTable polling(String ipAddress, int port, int version, String community, int retries, int timeout, Set<String> oidSet, String securityLevel, String user, String authPassword, String privPassword, String authProtocol, String privProtocol) { if (log.isDebugEnabled()) { String[][] nameValues = { { "ipAddress", ipAddress }, { "port", String.valueOf(port) }, { "version", String.valueOf(version) }, { "community", community }, { "retries", String.valueOf(retries) }, { "timeout", String.valueOf(timeout) }, { "securityLevel", securityLevel }, { "user", user }, { "authPassword", authPassword }, { "privPassword", privPassword }, { "authProtocol", authProtocol }, { "privProtocol", privProtocol } }; if (log.isDebugEnabled()) { StringBuilder sb = new StringBuilder(); for (String[] nameValue : nameValues) { sb.append(nameValue[0]).append("=").append(nameValue[1]).append(", "); } int i = 0; for (final String oid : oidSet) { sb.append("oidList[").append(i).append("]=").append(oid).append(", "); i++; } log.debug(sb.toString()); } } //retries?????hinemos????????????1? if (--retries < 0) { retries = 0; } DataTable dataTable = null; Snmp snmp = null; try { if (version == SnmpConstants.version3) { snmp = createV3Snmp(securityLevel, user, authPassword, privPassword, authProtocol, privProtocol); } else { snmp = getNotV3SnmpFromPool(); } oidSet = formalizeOidList(oidSet); DefaultPDUFactory factory = createPduFactory(oidSet, version); Target target = createTarget(ipAddress, port, version, community, retries, timeout, securityLevel, user); MultipleOidsUtils utils = new MultipleOidsUtils(snmp, factory); int maxRetry = HinemosPropertyUtil .getHinemosPropertyNum("monitor.poller.snmp.max.retry", Long.valueOf(3)).intValue(); boolean errorFlag = true; for (int i = 0; i < maxRetry; i++) { Collection<VariableBinding> vbs = utils.query(target, createColumnOidList(oidSet).toArray(new OID[0])); DataTable dataTableNotChecked = createDataTable(vbs); // ??? if (isDataTableValid(oidSet, dataTableNotChecked)) { dataTable = dataTableNotChecked; errorFlag = false; break; } } if (errorFlag) { log.warn("reach max retry(" + maxRetry + ")"); } } catch (IOException e) { // ???????OID???????? dataTable = new DataTable(); for (final String oid : oidSet) { final String entryOid = getEntryKey(oid) + ".0"; dataTable .putValue(new TableEntry(entryOid, HinemosTime.currentTimeMillis(), ErrorType.IO_ERROR, e)); } } finally { if (version == SnmpConstants.version3 && snmp != null) { try { snmp.close(); } catch (IOException e) { log.warn(e); } } } // ??????????????????????? for (final String oid : oidSet) { final String entryOid = getEntryKey(oid); if (dataTable.containStartWith(entryOid) == false) { dataTable.putValue(new TableEntry(entryOid + ".0", HinemosTime.currentTimeMillis(), ErrorType.RESPONSE_NOT_FOUND, new SnmpResponseError( MessageConstant.MESSAGE_RESPONSE_NOT_FOUND.getMessage(new String[] { oid })))); } } if (log.isDebugEnabled()) { log.debug("polling() : built DataTable"); log.debug(dataTable.toString()); } return dataTable; } public synchronized Snmp getNotV3SnmpFromPool() { if (notV3SnmpPoolIndex >= notV3SnmpPoolSize) { notV3SnmpPoolIndex = 0; } return notV3SnmpPool.get(notV3SnmpPoolIndex++); } private static int convertSecurityLevelToInt(String securityLevel) { if (SnmpSecurityLevelConstant.AUTH_NOPRIV.equals(securityLevel)) { return SecurityLevel.AUTH_NOPRIV; } else if (SnmpSecurityLevelConstant.AUTH_PRIV.equals(securityLevel)) { return SecurityLevel.AUTH_PRIV; } return SecurityLevel.NOAUTH_NOPRIV; } private List<OID> createColumnOidList(Set<String> oidSet) { List<OID> columnOIDList = new ArrayList<OID>(); for (String oid : oidSet) { columnOIDList.add(new OID(oid)); } return columnOIDList; } private DataTable createDataTable(Collection<VariableBinding> vbs) { DataTable dataTable = new DataTable(); long time = HinemosTime.currentTimeMillis(); for (VariableBinding binding : vbs) { if (binding == null) { continue; } String oidString = "." + binding.getOid().toDottedString(); dataTable.putValue(getEntryKey(oidString), time, getVariableValue(oidString, binding.getVariable())); } return dataTable; } private static Target createNotV3Target(String ipAddress, int port, int version, String community, int retries, int timeout) { CommunityTarget target = new CommunityTarget(); target.setAddress(new UdpAddress(String.format("%s/%d", ipAddress, port))); target.setCommunity(new OctetString(community)); target.setTimeout(timeout); target.setRetries(retries); target.setVersion(version); return target; } private DefaultPDUFactory createPduFactory(Set<String> oids, int version) { DefaultPDUFactory factory = new DefaultPDUFactory(); // SNMPv1????BULK if (isProcessOidList(oids) && version != SnmpConstants.version1) { factory.setPduType(PDU.GETBULK); factory.setMaxRepetitions(maxRepetitions); factory.setNonRepeaters(nonRepeaters); //?????v4.1??GETNEXT } else { factory.setPduType(PDU.GETNEXT); } return factory; } private Snmp createNotV3Snmp() throws IOException { Snmp snmp = new Snmp(new UdpTransportMappingImpl()); snmp.listen(); return snmp; } public Snmp createV3Snmp(String securityLevel, String user, String authPassword, String privPassword, String authProtocol, String privProtocol) throws IOException { Snmp snmp = new Snmp(new UdpTransportMappingImpl()); OctetString securityName = new OctetString(user); USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0); SecurityModels.getInstance().addSecurityModel(usm); OID authProtocolOid = AuthMD5.ID; if (SnmpProtocolConstant.SHA.equals(authProtocol)) { authProtocolOid = AuthSHA.ID; } OID privProtocolOid = PrivDES.ID; if (SnmpProtocolConstant.AES.equals(privProtocol)) { privProtocolOid = PrivAES128.ID; } UsmUser usmUser; if (convertSecurityLevelToInt(securityLevel) == SecurityLevel.NOAUTH_NOPRIV) { usmUser = new UsmUser(securityName, null, null, null, null); } else if (convertSecurityLevelToInt(securityLevel) == SecurityLevel.AUTH_NOPRIV) { usmUser = new UsmUser(securityName, authProtocolOid, new OctetString(authPassword), null, null); } else { usmUser = new UsmUser(securityName, authProtocolOid, new OctetString(authPassword), privProtocolOid, new OctetString(privPassword)); } snmp.getUSM().addUser(securityName, usmUser); snmp.listen(); return snmp; } public static Target createTarget(String ipAddress, int port, int version, String community, int retries, int timeout, String securityLevel, String user) { Target target = null; if (version == SnmpConstants.version3) { target = createV3Target(ipAddress, port, version, community, retries, timeout, securityLevel, user); } else { target = createNotV3Target(ipAddress, port, version, community, retries, timeout); } return target; } private static Target createV3Target(String ipAddress, int port, int version, String community, int retries, int timeout, String securityLevel, String user) { UserTarget target = new UserTarget(); target.setAddress(new UdpAddress(String.format("%s/%d", ipAddress, port))); target.setTimeout(timeout); target.setRetries(retries); target.setVersion(version); target.setSecurityLevel(convertSecurityLevelToInt(securityLevel)); target.setSecurityName(new OctetString(user)); return target; } private Set<String> formalizeOidList(Set<String> oids) { Set<String> newOids = new HashSet<String>(oids.size()); for (String oid : oids) { //snmp4j?getbulk???0??OID???????? //.XX.YY.0??OID.XX.YY?? if (oid.endsWith(".0")) { oid = oid.substring(0, oid.length() - 2); } newOids.add(oid); } return newOids; } /** * DataTable??????EntryKey? * * @param oidString OID */ private String getEntryKey(String oidString) { return PollerProtocolConstant.PROTOCOL_SNMP + "." + oidString; } private Serializable getVariableValue(String oidString, Variable variable) { switch (variable.getSyntax()) { case SMIConstants.SYNTAX_OCTET_STRING: OctetString octStr = (OctetString) variable; StringBuilder value = new StringBuilder(); byte[] bytes = octStr.getValue(); if ((oidString.startsWith(SearchDeviceProperties.getOidNicMacAddress()) || oidString.startsWith(SearchConnectionProperties.DEFAULT_OID_ARP) || oidString.startsWith(SearchConnectionProperties.DEFAULT_OID_FDB)) && bytes.length == 6) { // 6 byte?binary?OctetString // 00:0A:1F:5F:30 ??????? for (byte b : bytes) { String part = String.format("%02x", b).toUpperCase(); if (value.length() == 0) { value.append(part); } else { value.append(":" + part); } } } else { // Windows?NIC????0x00?????????? int length = bytes.length; for (int i = 0; i < bytes.length; i++) { if (bytes[i] == 0x00) { length = i; break; } } value.append(new String(bytes, 0, length)); } log.debug("SnmpPollerImpl deleteLabel=" + deleteLabel); // Windows????? // C:\ Label:ABC Serial Number 80f3e65c // // C:\ String ret = value.toString(); if (deleteLabel && oidString.startsWith(SearchDeviceProperties.getOidFilesystemName())) { ret = ret.replaceAll( HinemosPropertyUtil.getHinemosPropertyStr(LABEL_REPLACE_KEY, LABEL_REPLACE_DEFAULT), ""); } return ret; case SMIConstants.SYNTAX_OBJECT_IDENTIFIER: return "." + variable.toString(); default: return variable.toLong(); } } private boolean isDataTableValid(Set<String> oids, DataTable dataTable) { //???????oid???????????? if (isProcessOidList(oids)) { return isDataTableValidForProcess(oids, dataTable); } return true; } private boolean isDataTableValidForProcess(Set<String> oidSet, DataTable dataTable) { int lastCount = -1; ArrayList<ArrayList<String>> pidListList = new ArrayList<>(); // ?3??OID???????????PID?????????? for (String oid : oidSet) { ArrayList<String> pidList = new ArrayList<String>(); oid = getEntryKey(oid); int count = 0; for (String dataTableOid : dataTable.keySet()) { if (dataTableOid.startsWith(oid)) { count++; // PID?& String pid = dataTableOid.substring(dataTableOid.lastIndexOf(".")); pidList.add(pid); } } //List Collections.sort(pidList); pidListList.add(pidList); //??OID? if (lastCount == -1) { lastCount = count; continue; } //?OID?? if (lastCount != count) { return false; } } //PID List?????????? @SuppressWarnings("unchecked") ArrayList<String>[] pidListArray = new ArrayList[3]; for (int i = 0; oidSet.size() > i; i++) { pidListArray[i] = pidListList.get(i); } for (int i = 0; lastCount > i; i++) { String pid = null; for (int j = 0; pidListArray.length > j; j++) { //??PID if (pid == null) { pid = pidListArray[j].get(i); continue; } if (!pid.equals(pidListArray[j].get(i))) { log.warn("isDataTableValidForProcess don't match. pid = " + pid + " is not exit."); log.warn("isDataTableValidForProcess current list = " + pidListArray[j].toString()); return false; } else { if (log.isDebugEnabled()) { log.debug("isDataTableValidForProcess match. pid = " + pid + " is exit."); } } } } if (log.isDebugEnabled()) { log.debug("isDataTableValidForProcess success."); } return true; } private boolean isProcessOidList(Set<String> oids) { return oids.size() == processOidList.size() && oids.containsAll(processOidList); } }