package com.intrbiz.bergamot.watcher.engine.snmp;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;
import org.apache.log4j.Logger;
import com.intrbiz.Util;
import com.intrbiz.bergamot.model.message.event.check.CheckEvent;
import com.intrbiz.bergamot.model.message.event.watcher.RegisterCheck;
import com.intrbiz.bergamot.model.message.event.watcher.UnregisterCheck;
import com.intrbiz.bergamot.model.message.result.ActiveResultMO;
import com.intrbiz.bergamot.model.message.result.ResultMO;
import com.intrbiz.snmp.SNMPContext;
import com.intrbiz.snmp.SNMPContextId;
import com.intrbiz.snmp.handler.trap.OnLinkChange;
public class LinkStateExecutor extends AbstractSNMPExecutor
{
private Logger logger = Logger.getLogger(LinkStateExecutor.class);
private ConcurrentMap<SNMPContextId, ConcurrentMap<String, LinkStateTrap>> traps = new ConcurrentHashMap<SNMPContextId, ConcurrentMap<String, LinkStateTrap>>();
@Override
public boolean accept(CheckEvent check)
{
return super.accept(check) && "link-state".equalsIgnoreCase(check.getExecutor());
}
private ConcurrentMap<String, LinkStateTrap> getContextTraps(SNMPContextId id)
{
ConcurrentMap<String, LinkStateTrap> current = new ConcurrentHashMap<String, LinkStateTrap>();
ConcurrentMap<String, LinkStateTrap> previous = this.traps.putIfAbsent(id, current);
return previous == null ? current : previous;
}
@Override
public void register(RegisterCheck check, Consumer<ResultMO> resultConsumer)
{
try
{
// validate the check
this.validate(check);
// the interface name
String interfaceName = check.getParameter("interface-name");
if (Util.isEmpty(interfaceName)) throw new RuntimeException("The interface-name must be defined!");
// open the context
SNMPContext<?> context = this.openContext(check);
final ConcurrentMap<String, LinkStateTrap> contextTraps = this.getContextTraps(context.getContextId());
// store the check
contextTraps.put(interfaceName, new LinkStateTrap(check, resultConsumer));
// setup the trap
context.registerTrapHandler("link-state", new OnLinkChange.LinkTrapAdapter((linkEvent) -> {
logger.info("Got link state change event: " + linkEvent.getEventType() + " " + linkEvent.getDescription() + " " + linkEvent.getAdminState() + " == " + linkEvent.getOperationalState());
// lookup the trap
LinkStateTrap trap = contextTraps.get(linkEvent.getDescription());
if (trap != null)
{
logger.debug("Mapped to trap: " + linkEvent.getDescription() + " => " + trap.check.getCheckType() + " " + trap.check.getCheckId());
ResultMO resultMO = new ActiveResultMO().fromCheck(trap.check);
// is the link ok or not?
if (linkEvent.getAdminState() == linkEvent.getOperationalState())
{
resultMO.ok("Link on " + linkEvent.getDescription() + " is " + linkEvent.getOperationalState());
}
else
{
resultMO.critical("Link on " + linkEvent.getDescription() + " is " + linkEvent.getOperationalState());
}
// publish
trap.resultConsumer.accept(resultMO);
}
else
{
logger.warn("Failed to map SNMP trap to Bergamot trap: " + context.getAgent() + " " + linkEvent.getDescription() + " " + linkEvent.getOperationalState());
}
}));
// TODO query the initial state?
}
catch (Exception e)
{
logger.error("Failed to register check for " + check.getCheckType() + " " + check.getCheckId(), e);
resultConsumer.accept(new ActiveResultMO().fromCheck(check).error(e));
}
}
@Override
public void unregister(UnregisterCheck check)
{
}
private class LinkStateTrap
{
public final RegisterCheck check;
public final Consumer<ResultMO> resultConsumer;
public LinkStateTrap(RegisterCheck check, Consumer<ResultMO> resultConsumer)
{
super();
this.check = check;
this.resultConsumer = resultConsumer;
}
}
}