changeset 1123:9517e4cb9bd7

SnmpService in progress
author Devel 2
date Fri, 05 Jun 2020 09:41:41 +0200
parents b33418b1f310
children 83c771436e55
files stress-tester/pom.xml stress-tester/src/main/java/com/passus/st/snmp/SnmpOIDInfo.java stress-tester/src/main/java/com/passus/st/snmp/SnmpService.java stress-tester/src/main/java/com/passus/st/snmp/SnmpTargetSettings.java stress-tester/src/main/java/com/passus/st/snmp/SnmpUtils.java stress-tester/src/main/java/com/passus/st/snmp/SystemMetric.java
diffstat 6 files changed, 553 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/stress-tester/pom.xml	Wed Jun 03 13:30:11 2020 +0200
+++ b/stress-tester/pom.xml	Fri Jun 05 09:41:41 2020 +0200
@@ -187,6 +187,12 @@
         </dependency>
 
         <dependency>
+            <groupId>org.snmp4j</groupId>
+            <artifactId>snmp4j</artifactId>
+            <version>2.8.4</version>
+        </dependency>
+
+        <dependency>
             <groupId>org.testng</groupId>
             <artifactId>testng</artifactId>
             <version>6.9.10</version>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/snmp/SnmpOIDInfo.java	Fri Jun 05 09:41:41 2020 +0200
@@ -0,0 +1,101 @@
+package com.passus.st.snmp;
+
+import org.snmp4j.smi.OID;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+public final class SnmpOIDInfo {
+
+    public static final SnmpOIDInfo OID_CPU_LOAD_1M = new SnmpOIDInfo(".1.3.6.1.4.1.2021.10.1.3.1", "cpuLoad1M");
+    public static final SnmpOIDInfo OID_CPU_LOAD_5M = new SnmpOIDInfo(".1.3.6.1.4.1.2021.10.1.3.2", "cpuLoad5M");
+    public static final SnmpOIDInfo OID_CPU_LOAD_15M = new SnmpOIDInfo(".1.3.6.1.4.1.2021.10.1.3.3", "cpuLoad15M");
+    public static final SnmpOIDInfo OID_CPU_USER = new SnmpOIDInfo(".1.3.6.1.4.1.2021.11.9.0", "cpuUser");
+    public static final SnmpOIDInfo OID_CPU_IDLE = new SnmpOIDInfo(".1.3.6.1.4.1.2021.11.11.0", "cpuIdle");
+    public static final SnmpOIDInfo OID_RAM_FREE = new SnmpOIDInfo(".1.3.6.1.4.1.2021.4.6.0", "ramFree");
+    public static final SnmpOIDInfo OID_RAM_TOTAL = new SnmpOIDInfo(".1.3.6.1.4.1.2021.4.5.0", "ramTotal");
+    public static final SnmpOIDInfo OID_SWAP_FREE = new SnmpOIDInfo(".1.3.6.1.4.1.2021.4.4.0", "swapFree");
+    public static final SnmpOIDInfo OID_SWAP_TOTAL = new SnmpOIDInfo(".1.3.6.1.4.1.2021.4.3.0", "swapTotal");
+
+    public static final Set<SnmpOIDInfo> OIDS;
+
+    static {
+        Set<SnmpOIDInfo> oidsTmp = new HashSet<>();
+        oidsTmp.add(OID_CPU_LOAD_1M);
+        oidsTmp.add(OID_CPU_LOAD_5M);
+        oidsTmp.add(OID_CPU_LOAD_15M);
+        oidsTmp.add(OID_CPU_USER);
+        oidsTmp.add(OID_CPU_IDLE);
+        oidsTmp.add(OID_RAM_FREE);
+        oidsTmp.add(OID_RAM_TOTAL);
+        oidsTmp.add(OID_SWAP_FREE);
+        oidsTmp.add(OID_SWAP_TOTAL);
+        OIDS = Collections.unmodifiableSet(oidsTmp);
+    }
+
+    private final OID oid;
+
+    private final String name;
+
+    public SnmpOIDInfo(String oid, String name) {
+        this(new OID(oid), name);
+    }
+
+    public SnmpOIDInfo(OID oid, String name) {
+        this.oid = oid;
+        this.name = name;
+    }
+
+    public OID oid() {
+        return oid;
+    }
+
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(oid);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        SnmpOIDInfo that = (SnmpOIDInfo) o;
+        return Objects.equals(oid, that.oid);
+    }
+
+    @Override
+    public String toString() {
+        return "SnmpOIDInfo{" +
+                "oid=" + oid +
+                ", name='" + name + '\'' +
+                '}';
+    }
+
+    public static Set<OID> getAllOIDs() {
+        Set<OID> out = new HashSet<>(OIDS.size());
+        OIDS.forEach(o -> out.add(o.oid));
+        return out;
+    }
+
+    public static SnmpOIDInfo findByOID(String oid) {
+        return findByOID(new OID(oid));
+    }
+
+    public static SnmpOIDInfo findByOID(OID oid) {
+        for (SnmpOIDInfo info : OIDS) {
+            if (info.oid.equals(oid)) {
+                return info;
+            }
+        }
+
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/snmp/SnmpService.java	Fri Jun 05 09:41:41 2020 +0200
@@ -0,0 +1,254 @@
+package com.passus.st.snmp;
+
+import com.passus.commons.Assert;
+import com.passus.commons.service.Service;
+import com.passus.commons.service.ServiceException;
+import com.passus.commons.time.DefaultScheduledTimerService;
+import com.passus.commons.time.ScheduledTimerService;
+import com.passus.st.Log4jConfigurationFactory;
+import com.passus.st.metric.MetricSource;
+import com.passus.st.metric.MetricsContainer;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.snmp4j.*;
+import org.snmp4j.event.ResponseEvent;
+import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.smi.*;
+import org.snmp4j.transport.DefaultUdpTransportMapping;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+public class SnmpService implements Service, MetricSource {
+
+    private static final Logger LOGGER = LogManager.getLogger(SnmpService.class);
+
+    private Snmp snmp;
+
+    private volatile boolean started;
+
+    private final List<SnmpTarget> targets = new ArrayList<>();
+
+    private ScheduledTimerService scheduledTimerService;
+
+    private long interval = 30_000;
+
+    private Set<OID> oids = SnmpOIDInfo.getAllOIDs();
+
+    public long getInterval() {
+        return interval;
+    }
+
+    public void setInterval(long interval) {
+        Assert.greaterThanZero(interval, "interval");
+        this.interval = interval;
+    }
+
+    public void addTarget(SnmpTargetSettings settings) {
+        Assert.notNull(settings, "settings");
+        SnmpTarget snmpTarget = new SnmpTarget(settings);
+        targets.add(snmpTarget);
+    }
+
+    @Override
+    public boolean isStarted() {
+        return started;
+    }
+
+    @Override
+    public void start() {
+        if (started) {
+            return;
+        }
+
+        try {
+            TransportMapping transport = new DefaultUdpTransportMapping();
+            transport.listen();
+            snmp = new Snmp(transport);
+
+            targets.forEach(t -> {
+                if (!t.init) {
+                    t.init();
+                }
+            });
+
+            scheduledTimerService = new DefaultScheduledTimerService("SnmpService.Scheduler", interval, this::sendAll);
+            scheduledTimerService.start();
+            started = true;
+        } catch (IOException e) {
+            throw new ServiceException("Unable to start service. " + e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public void stop() {
+        if (!started) {
+            return;
+        }
+
+        scheduledTimerService.stop();
+
+        try {
+            snmp.close();
+        } catch (IOException ignore) {
+
+        }
+
+        started = false;
+    }
+
+    @Override
+    public boolean isCollectMetrics() {
+        return true;
+    }
+
+    @Override
+    public void setCollectMetrics(boolean collectMetrics) {
+
+    }
+
+    @Override
+    public void writeMetrics(MetricsContainer container) {
+        targets.forEach(t -> {
+            synchronized (t.metric) {
+                container.update(t.metric);
+                t.metric.reset();
+            }
+        });
+    }
+
+    private void sendAll() {
+        targets.forEach(t -> send(t, oids));
+    }
+
+    private void updateMetric(List<? extends VariableBinding> vars, SystemMetric metric) {
+        synchronized (metric) {
+            for (VariableBinding varBind : vars) {
+                SnmpOIDInfo oidInfo = SnmpOIDInfo.findByOID(varBind.getOid());
+                if (oidInfo != null) {
+                    Variable var = varBind.getVariable();
+                    switch (oidInfo.name()) {
+                        case "cpuLoad1M": {
+                            float value = Float.parseFloat(var.toString());
+                            metric.updateLoad1M(value);
+                            break;
+                        }
+                        case "cpuLoad5M": {
+                            float value = Float.parseFloat(var.toString());
+                            metric.updateLoad5M(value);
+                            break;
+                        }
+                        case "cpuLoad15M": {
+                            float value = Float.parseFloat(var.toString());
+                            metric.updateLoad15M(value);
+                            break;
+                        }
+                        case "cpuUser": {
+                            metric.updateCpuUser(var.toInt());
+                            break;
+                        }
+                        case "cpuIdle": {
+                            metric.updateCpuIdle(var.toInt());
+                            break;
+                        }
+                        case "ramFree": {
+                            metric.updateRamFree(var.toLong());
+                            break;
+                        }
+                        case "ramTotal": {
+                            metric.updateRamTotal(var.toLong());
+                            break;
+                        }
+                        case "swapFree": {
+                            metric.updateSwapFree(var.toLong());
+                            break;
+                        }
+                        case "swapTotal": {
+                            metric.updateSwapTotal(var.toLong());
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void send(SnmpTarget target, Collection<OID> oids) {
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("[{}] SNMP sending request.", target.target.getAddress());
+        }
+
+        PDU pdu = new PDU();
+        for (OID oid : oids) {
+            pdu.add(new VariableBinding(oid));
+        }
+
+        try {
+            ResponseEvent event = snmp.get(pdu, target.target);
+            if (event == null) {
+                LOGGER.warn("[{}] SNMP request timeout.", target.target.getAddress());
+            } else {
+                PDU respPdu = event.getResponse();
+                if (respPdu == null) {
+                    LOGGER.warn("[{}] SNMP request error. Response PDU is null.", target.target.getAddress());
+                } else if (respPdu.getErrorStatus() == PDU.noError) {
+                    List<? extends VariableBinding> vars = respPdu.getVariableBindings();
+                    updateMetric(vars, target.metric);
+                    if (LOGGER.isDebugEnabled()) {
+                        LOGGER.debug("[{}] Metric updated. {}", target.target.getAddress(), target.metric);
+                    }
+                } else {
+                    LOGGER.warn("[{}] SNMP request error. Index: {}, Status: {}, Text: {}.", target.target.getAddress(),
+                            respPdu.getErrorIndex(), respPdu.getErrorIndex(), respPdu.getErrorStatusText());
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.warn("[{}] SNMP sending error. {}", target.target.getAddress(), e.getMessage(), e);
+        }
+    }
+
+    private Target createTargetV2(SnmpTargetSettings settings) {
+        Address targetAddress = new UdpAddress(settings.getAddress());
+        if (targetAddress == null) {
+            throw new IllegalArgumentException("Invalid address '" + settings.getAddress() + "'.");
+        }
+
+        CommunityTarget target = new CommunityTarget();
+        target.setCommunity(new OctetString(settings.getCommunity()));
+        target.setAddress(targetAddress);
+        target.setRetries(settings.getRetries());
+        target.setTimeout(settings.getTimeout());
+        target.setVersion(SnmpConstants.version2c);
+        return target;
+    }
+
+    private class SnmpTarget {
+
+        private final SnmpTargetSettings settings;
+
+        private Target target;
+
+        private SystemMetric metric;
+
+        private boolean init;
+
+        private SnmpTarget(SnmpTargetSettings settings) {
+            this.settings = settings;
+        }
+
+        private void init() {
+            target = createTargetV2(settings);
+            metric = new SystemMetric(SystemMetric.DEFAULT_NAME + "." + target.getAddress());
+            init = true;
+        }
+
+        @Override
+        public String toString() {
+            return target.getAddress().toString();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/snmp/SnmpTargetSettings.java	Fri Jun 05 09:41:41 2020 +0200
@@ -0,0 +1,52 @@
+package com.passus.st.snmp;
+
+import com.passus.commons.Assert;
+
+import static com.passus.st.snmp.SnmpUtils.*;
+
+public final class SnmpTargetSettings {
+
+    private String address = DEFAULT_ADDRESS;
+
+    private long timeout = DEFAULT_TIMEOUT;
+
+    private int retries = DEFAULT_RETRIES;
+
+    private String community = DEFAULT_COMMUNITY;
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        Assert.notNull(address, "address");
+        this.address = address;
+    }
+
+    public long getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout(long timeout) {
+        Assert.greaterThanZero(timeout, "timeout");
+        this.timeout = timeout;
+    }
+
+    public int getRetries() {
+        return retries;
+    }
+
+    public void setRetries(int retries) {
+        Assert.greaterThanZero(retries, "retries");
+        this.retries = retries;
+    }
+
+    public String getCommunity() {
+        return community;
+    }
+
+    public void setCommunity(String community) {
+        Assert.notNull(community, "community");
+        this.community = community;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/snmp/SnmpUtils.java	Fri Jun 05 09:41:41 2020 +0200
@@ -0,0 +1,12 @@
+package com.passus.st.snmp;
+
+public final class SnmpUtils {
+
+    public static final String DEFAULT_ADDRESS = "localhost";
+    public static final long DEFAULT_TIMEOUT = 1500;
+    public static final int DEFAULT_RETRIES = 1;
+    public static final String DEFAULT_COMMUNITY = "passus";
+
+    private SnmpUtils() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/snmp/SystemMetric.java	Fri Jun 05 09:41:41 2020 +0200
@@ -0,0 +1,128 @@
+package com.passus.st.snmp;
+
+import com.passus.commons.metric.Metric;
+import com.passus.st.client.GenericMetric;
+import org.apache.commons.lang3.mutable.MutableFloat;
+import org.apache.commons.lang3.mutable.MutableInt;
+import org.apache.commons.lang3.mutable.MutableLong;
+
+public class SystemMetric extends GenericMetric {
+
+    public static final String DEFAULT_NAME = "system";
+
+    private MutableFloat cpuLoad1M = new MutableFloat();
+
+    private MutableFloat cpuLoad5M = new MutableFloat();
+
+    private MutableFloat cpuLoad15M = new MutableFloat();
+
+    private MutableInt cpuUser = new MutableInt();
+
+    private MutableInt cpuIdle = new MutableInt();
+
+    private MutableLong ramFree = new MutableLong();
+
+    private MutableLong ramTotal = new MutableLong();
+
+    private MutableLong swapFree = new MutableLong();
+
+    private MutableLong swapTotal = new MutableLong();
+
+    public SystemMetric() {
+        super(DEFAULT_NAME);
+    }
+
+    public SystemMetric(String name) {
+        super(name);
+        attrs.put("cpuLoad1M", cpuLoad1M);
+        attrs.put("cpuLoad5M", cpuLoad5M);
+        attrs.put("cpuLoad15M", cpuLoad15M);
+        attrs.put("cpuUser", cpuUser);
+        attrs.put("cpuIdle", cpuIdle);
+        attrs.put("ramFree", ramFree);
+        attrs.put("ramTotal", ramTotal);
+        attrs.put("swapFree", swapFree);
+        attrs.put("swapTotal", swapTotal);
+    }
+
+    public void updateLoad1M(float value) {
+        max(cpuLoad1M, value);
+    }
+
+    public void updateLoad5M(float value) {
+        max(cpuLoad5M, value);
+    }
+
+    public void updateLoad15M(float value) {
+        max(cpuLoad15M, value);
+    }
+
+    public void updateCpuUser(int value) {
+        max(cpuUser, value);
+    }
+
+    public void updateCpuIdle(int value) {
+        max(cpuIdle, value);
+    }
+
+    public void updateRamFree(long value) {
+        max(ramFree, value);
+    }
+
+    public void updateRamTotal(long value) {
+        max(ramTotal, value);
+    }
+
+    public void updateSwapFree(long value) {
+        max(swapFree, value);
+    }
+
+    public void updateSwapTotal(long value) {
+        max(swapTotal, value);
+    }
+
+    @Override
+    public void update(Metric metric) {
+        SystemMetric sm = (SystemMetric) metric;
+        cpuLoad1M = Metric.max(cpuLoad1M, sm.cpuLoad1M);
+        cpuLoad5M = Metric.max(cpuLoad5M, sm.cpuLoad5M);
+        cpuLoad15M = Metric.max(cpuLoad15M, sm.cpuLoad15M);
+        cpuUser = Metric.max(cpuUser, sm.cpuUser);
+        cpuIdle = Metric.max(cpuIdle, sm.cpuIdle);
+        ramFree = Metric.max(ramFree, sm.ramFree);
+        ramTotal = Metric.max(ramTotal, sm.ramTotal);
+        swapFree = Metric.max(swapFree, sm.swapFree);
+        swapTotal = Metric.max(swapTotal, sm.swapTotal);
+    }
+
+    @Override
+    public void reset() {
+        cpuLoad1M.setValue(0);
+        cpuLoad5M.setValue(0);
+        cpuLoad15M.setValue(0);
+        cpuUser.setValue(0);
+        cpuIdle.setValue(0);
+        ramFree.setValue(0);
+        ramTotal.setValue(0);
+        swapFree.setValue(0);
+        swapTotal.setValue(0);
+    }
+
+    private static void max(MutableFloat val1, float val2) {
+        if (val1.floatValue() < val2) {
+            val1.setValue(val2);
+        }
+    }
+
+    private static void max(MutableInt val1, int val2) {
+        if (val1.intValue() < val2) {
+            val1.setValue(val2);
+        }
+    }
+
+    private static void max(MutableLong val1, long val2) {
+        if (val1.longValue() < val2) {
+            val1.setValue(val2);
+        }
+    }
+}