-
Notifications
You must be signed in to change notification settings - Fork 354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Alert manager addition to dolphin framework #8
Changes from 4 commits
e759dcc
7f2c38e
adc8ce9
5b38ee6
ac1bcdf
6e4a47e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Copyright 2020 The SODA Authors. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http:#www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
|
||
# Default values for trap receiver ip address and port | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there are different groups of constants, it's better to make them class constants. For example, all MIB constants in class MIB and all Trap constants in class Trap. Advantage is the code readability and flow. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not moved to class currently There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any particular reason? |
||
DEF_TRAP_RECV_ADDR = '0.0.0.0' | ||
DEF_TRAP_RECV_PORT = 162 | ||
TRAP_RECEIVER_CLASS = 'dolphin.alert_manager.trap_receiver.TrapReceiver' | ||
|
||
# Temporary snmp community and user configurations | ||
SNMP_COMMUNITY_STR='public' | ||
SNMP_USM_USER='test1' | ||
SNMP_V3_AUTHKEY='abcd123456' | ||
SNMP_V3_PRIVKEY='abcd123456' | ||
SNMP_V3_AUTH_PROTOCOL='usmHMACMD5AuthProtocol' | ||
SNMP_V3_PRIV_PROTOCOL='usmDESPrivProtocol' | ||
SNMP_ENGINE_ID='800000d30300000e112245' | ||
|
||
# Temporary mib lod dir. This mechanism to be changed later | ||
SNMP_MIB_PATH = '/usr/local/lib/python3.6/dist-packages/pysnmp/smi/mibs' | ||
|
||
# SNMP dispatcher job id (static identifier) | ||
SNMP_DISPATCHER_JOB_ID = 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why dispatcher job id is static here? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
# Copyright 2020 The SODA Authors. | ||
# | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated |
||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http:#www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from oslo_log import log | ||
|
||
from pysnmp.entity import engine, config | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should pysnmp be added to requirements.txt, and what kind of license it used? |
||
from pysnmp.carrier.asyncore.dgram import udp | ||
from pysnmp.entity.rfc3413 import ntfrcv | ||
from pysnmp.proto.api import v2c | ||
from pysnmp.smi import builder, view, rfc1902, error | ||
|
||
from dolphin.alert_manager import constants | ||
|
||
LOG = log.getLogger(__name__) | ||
|
||
# Currently static mib file list is loaded, logic to be changed to load all mib file | ||
MIB_LOAD_LIST = ['SNMPv2-MIB','IF_MIB'] | ||
|
||
class TrapReceiver(object): | ||
"""Trap listening and processing functions""" | ||
|
||
def __init__(self, trap_receiver_address, trap_receiver_port, | ||
snmp_mib_path, mib_view_controller=None, snmp_engine=None): | ||
self.mib_view_controller = mib_view_controller | ||
self.snmp_engine = snmp_engine | ||
self.trap_receiver_address = trap_receiver_address | ||
self.trap_receiver_port = trap_receiver_port | ||
self.snmp_mib_path = snmp_mib_path | ||
|
||
def _mib_builder(self): | ||
"""Loads given set of mib files from given path.""" | ||
mib_builder = builder.MibBuilder() | ||
try: | ||
self.mib_view_controller = view.MibViewController(mib_builder) | ||
|
||
# set mib path to mib_builder object and load mibs | ||
mib_path = builder.DirMibSource(self.snmp_mib_path), | ||
mib_builder.setMibSources(*mib_path) | ||
if len(MIB_LOAD_LIST) > 0: | ||
mib_builder.loadModules(*MIB_LOAD_LIST) | ||
except error.MibNotFoundError: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this exception need to be throw out to the upper level? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, updated |
||
LOG.error("Mib load failed.") | ||
|
||
def _add_transport(self): | ||
"""Configures the transport parameters for the snmp engine.""" | ||
try: | ||
config.addTransport( | ||
self.snmp_engine, | ||
udp.domainName, | ||
udp.UdpTransport().openServerMode((self.trap_receiver_address, int(self.trap_receiver_port))) | ||
) | ||
except Exception: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here.. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, updated |
||
LOG.error("Port binding failed the provided port is in use.") | ||
|
||
def _cb_fun(self, state_reference, context_engine_id, context_name, | ||
var_binds, cb_ctx): | ||
"""Callback function to process the incoming trap.""" | ||
exec_context = self.snmp_engine.observer.getExecutionContext('rfc3412.receiveMessage:request') | ||
LOG.info( | ||
'#Notification from %s \n#ContextEngineId: "%s" \n#ContextName: "%s" \n#SNMPVER "%s" \n#SecurityName "%s"' % ( | ||
'@'.join([str(x) for x in exec_context['transportAddress']]), context_engine_id.prettyPrint(), | ||
context_name.prettyPrint(), exec_context['securityModel'], exec_context['securityName'])) | ||
for oid, val in var_binds: | ||
output = rfc1902.ObjectType(rfc1902.ObjectIdentity(oid), val).resolveWithMib( | ||
self.mib_view_controller).prettyPrint() | ||
LOG.info(output) | ||
|
||
def _snmp_v2v3_config(self): | ||
"""Configures snmp v2 and v3 user parameters.""" | ||
community_str = constants.SNMP_COMMUNITY_STR | ||
config.addV1System(self.snmp_engine, community_str, community_str) | ||
auth_priv_protocols = { | ||
'usmHMACMD5AuthProtocol': config.usmHMACMD5AuthProtocol, | ||
'usmHMACSHAAuthProtocol': config.usmHMACSHAAuthProtocol, | ||
'usmAesCfb128Protocol': config.usmAesCfb128Protocol, | ||
'usmAesCfb256Protocol': config.usmAesCfb256Protocol, | ||
'usmAesCfb192Protocol': config.usmAesCfb192Protocol, | ||
'usmDESPrivProtocol': config.usmDESPrivProtocol, | ||
'usmNoAuthProtocol': config.usmNoAuthProtocol, | ||
'usmNoPrivProtocol': config.usmNoPrivProtocol | ||
} | ||
config.addV3User( | ||
self.snmp_engine, userName=constants.SNMP_USM_USER, | ||
authKey=constants.SNMP_V3_AUTHKEY, privKey=constants.SNMP_V3_PRIVKEY, | ||
authProtocol=auth_priv_protocols.get( | ||
constants.SNMP_V3_AUTH_PROTOCOL, config.usmNoAuthProtocol), | ||
privProtocol=auth_priv_protocols.get( | ||
constants.SNMP_V3_PRIV_PROTOCOL, config.usmNoPrivProtocol), | ||
securityEngineId=v2c.OctetString( | ||
hexValue=constants.SNMP_ENGINE_ID)) | ||
|
||
return | ||
|
||
def start(self): | ||
"""Starts the snmp trap receiver with necessary prerequisites.""" | ||
snmp_engine = engine.SnmpEngine() | ||
self.snmp_engine = snmp_engine | ||
|
||
# Load all the mibs and do snmp config | ||
self._mib_builder() | ||
|
||
self._snmp_v2v3_config() | ||
|
||
# Register callback for notification receiver | ||
ntfrcv.NotificationReceiver(snmp_engine, self._cb_fun) | ||
|
||
# Add transport info(ip, port) and start the listener | ||
self._add_transport() | ||
|
||
snmp_engine.transportDispatcher.jobStarted(constants.SNMP_DISPATCHER_JOB_ID) | ||
try: | ||
LOG.info("Starting trap receiver.") | ||
snmp_engine.transportDispatcher.runDispatcher() | ||
|
||
except Exception: | ||
LOG.error("Failed to start trap listener.") | ||
snmp_engine.transportDispatcher.closeDispatcher() | ||
|
||
def stop(self): | ||
"""Brings down the snmp trap receiver.""" | ||
# Go ahead with shutdown, ignore if any errors happening during the process as it is shutdown | ||
if self.snmp_engine: | ||
self.snmp_engine.transportDispatcher.closeDispatcher() | ||
LOG.info("Trap receiver stopped.") |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ | |
from dolphin import exception | ||
from dolphin import rpc | ||
from dolphin import coordination | ||
from dolphin.alert_manager import constants | ||
|
||
LOG = log.getLogger(__name__) | ||
|
||
|
@@ -63,6 +64,15 @@ | |
default=False, | ||
help='Wraps the socket in a SSL context if True is set. ' | ||
'A certificate file and key file must be specified.'), | ||
cfg.HostAddressOpt('trap_receiver_address', | ||
default=constants.DEF_TRAP_RECV_ADDR, | ||
help='IP address at which trap receiver listens.'), | ||
cfg.PortOpt('trap_receiver_port', | ||
default=constants.DEF_TRAP_RECV_PORT, | ||
help='Port at which trap receiver listens.'), | ||
cfg.StrOpt('snmp_mib_path', | ||
default=constants.SNMP_MIB_PATH, | ||
help='Path at which mib files to be loaded are placed.'), | ||
] | ||
|
||
CONF = cfg.CONF | ||
|
@@ -208,6 +218,37 @@ def periodic_tasks(self, raise_on_error=False): | |
ctxt = context.get_admin_context() | ||
self.manager.periodic_tasks(ctxt, raise_on_error=raise_on_error) | ||
|
||
class AlertMngrService(service.Service): | ||
"""Service object for triggering trap receiver functionalities. | ||
""" | ||
|
||
def __init__(self, trap_receiver_address=None, | ||
trap_receiver_port=None, snmp_mib_path=None, trap_receiver_class=None): | ||
super(AlertMngrService, self).__init__() | ||
|
||
if not trap_receiver_address: | ||
trap_receiver_address = CONF.trap_receiver_address | ||
if not trap_receiver_port: | ||
trap_receiver_port = CONF.trap_receiver_port | ||
if not snmp_mib_path: | ||
snmp_mib_path = CONF.snmp_mib_path | ||
if not trap_receiver_class: | ||
trap_receiver_class = CONF.trap_receiver_class | ||
manager_class = importutils.import_class(trap_receiver_class) | ||
self.manager = manager_class(trap_receiver_address, | ||
trap_receiver_port, snmp_mib_path) | ||
|
||
def start(self): | ||
"""Trigger trap receiver creation""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these comments or doc strings? usually doc strings are put under """ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doc strings for each functions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
self.manager.start() | ||
|
||
def kill(self): | ||
"""Destroy the service object in the datastore.""" | ||
self.stop() | ||
|
||
def stop(self): | ||
"""Calls the shutdown flow of the service.""" | ||
self.manager.stop() | ||
|
||
class WSGIService(service.ServiceBase): | ||
"""Provides ability to launch API from a 'paste' configuration.""" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2020 The SODA Authors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any part of the code which is taken from some other place? If yes, then maybe it's not a good idea to change the copyright..We need to be careful here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copyright updated. Does not contain copied code