class Module(Shadow): __shadowclass__ = manage.Module __lookups__ = [('netbox', 'device'), ('netbox', 'name')] event = EventFactory('ipdevpoll', 'eventEngine', 'moduleState') @classmethod def prepare_for_save(cls, containers): cls._resolve_actual_duplicate_names(containers) return super(Module, cls).prepare_for_save(containers) @classmethod def _resolve_actual_duplicate_names(cls, containers): """Attempts to resolve an issue where multiple collected modules are reported as having the same name, by adding the module's serial number to its name before it's stored into the db. This may happen in some devices, but is not supported by NAV's data model. """ if cls not in containers: return by_name = defaultdict(list) for module in containers[cls].values(): by_name[module.name].append(module) duped = [name for name in by_name if len(by_name[name]) > 1] for name in duped: cls._logger.warning("Device reports %d modules by the name %r", len(by_name[name]), name) for module in by_name[name]: serial = module.device.serial if module.device else None if serial: module.name = '{} ({})'.format(name, serial) def prepare(self, containers): self._fix_binary_garbage() self._fix_missing_name() self._resolve_duplicate_names() def _fix_binary_garbage(self): """Fixes string attributes that appear as binary garbage.""" if utils.is_invalid_database_string(self.model): self._logger.warning("Invalid value for model: %r", self.model) self.model = repr(self.model) def _fix_missing_name(self): if not self.name and self.device and self.device.serial: self.name = "S/N %s" % self.device.serial def _resolve_duplicate_names(self): """Attempts to solve module naming conflicts inside the same chassis. If two modules physically switch slots in a chassis, they will be recognized by their serial numbers, but their names will likely be swapped. Module names must be unique within a chassis, so if another module on this netbox has the same name as us, we need to do something about the other module's name before our own to avoid a database integrity error. """ other = self._find_name_duplicates() if other: self._logger.warning( "modules appear to have been swapped inside same chassis (%s): " "%s (%s) <-> %s (%s)", other.netbox.sysname, self.name, self.device.serial, other.name, other.device.serial) other.name = u"%s (%s)" % (other.name, other.device.serial) other.save() def _find_name_duplicates(self): myself_in_db = self.get_existing_model() same_name_modules = manage.Module.objects.filter( netbox__id=self.netbox.id, name=self.name) if myself_in_db: same_name_modules = same_name_modules.exclude(id=myself_in_db.id) other = same_name_modules.select_related('device', 'netbox') return other[0] if other else None @classmethod def _handle_missing_modules(cls, containers): """Handles modules that have gone missing from a device.""" netbox = containers.get(None, Netbox) all_modules = manage.Module.objects.filter(netbox__id=netbox.id) modules_up = all_modules.filter(up=manage.Module.UP_UP) modules_down = all_modules.filter(up=manage.Module.UP_DOWN) collected_modules = containers[Module].values() collected_module_pks = [m.id for m in collected_modules if m.id] missing_modules = modules_up.exclude(id__in=collected_module_pks) reappeared_modules = modules_down.filter(id__in=collected_module_pks) if missing_modules: shortlist = ", ".join(m.name for m in missing_modules) cls._logger.info("%d modules went missing on %s (%s)", netbox.sysname, len(missing_modules), shortlist) for module in missing_modules: cls.event.start(module.device, module.netbox, module.id).save() if reappeared_modules: shortlist = ", ".join(m.name for m in reappeared_modules) cls._logger.info("%d modules reappeared on %s (%s)", netbox.sysname, len(reappeared_modules), shortlist) for module in reappeared_modules: cls.event.end(module.device, module.netbox, module.id).save() @classmethod def cleanup_after_save(cls, containers): cls._handle_missing_modules(containers) return super(Module, cls).cleanup_after_save(containers)
"""ipdevpoll plugin to monitor the state of known field-replaceable power supply and fan units. """ import datetime from twisted.internet import defer from nav.event2 import EventFactory from nav.ipdevpoll import Plugin, db from nav.models.manage import PowerSupplyOrFan from .psu import get_mibretrievers_from_vendor_id CALL_MAP = {"powerSupply": "get_power_supply_status", "fan": "get_fan_status"} PSU_EVENT = EventFactory("ipdevpoll", "eventEngine", "psuState", "psuNotOK", "psuOK") FAN_EVENT = EventFactory("ipdevpoll", "eventEngine", "fanState", "fanNotOK", "fanOK") EVENT_MAP = {"powerSupply": PSU_EVENT, "fan": FAN_EVENT} # Shorthand for database states STATE_UNKNOWN = PowerSupplyOrFan.STATE_UNKNOWN STATE_UP = PowerSupplyOrFan.STATE_UP STATE_DOWN = PowerSupplyOrFan.STATE_DOWN STATE_WARNING = PowerSupplyOrFan.STATE_WARNING class PowerSupplyOrFanStateWatcher(Plugin): """Collects PSU and FAN statues from netboxes""" def __init__(self, *args, **kwargs): super(PowerSupplyOrFanStateWatcher, self).__init__(*args, **kwargs)
"""Handling of gateway protocol state changes""" from __future__ import absolute_import from functools import partial from django.db import transaction from nav.event2 import EventFactory from nav.ipdevpoll.storage import Shadow, DefaultManager from nav.models import manage from .netbox import Netbox EVENT = EventFactory(source='ipdevpoll', target='eventEngine', event_type='bgpState', start_type='bgpDown', end_type='bgpEstablished') class GatewayPeerSessionManager(DefaultManager): """Manager for GatewayPeerSession objects""" _map = None def __init__(self, *args, **kwargs): super(GatewayPeerSessionManager, self).__init__(*args, **kwargs) self.netbox = self.containers.get(None, Netbox) self._sessions_to_keep = set() self._sessions_to_remove = set() def prepare(self): for session in self.get_managed():
import networkx as nx from networkx.algorithms.traversal.depth_first_search import dfs_tree as subtree from django.db import transaction from django.utils import six from django.utils.six import iteritems, itervalues from nav.toposort import build_graph, topological_sort from nav.ipdevpoll.storage import Shadow, DefaultManager from nav.models import manage from nav.event2 import EventFactory from .netbox import Netbox chassis_event = EventFactory('ipdevpoll', 'eventEngine', 'chassisState', 'chassisDown', 'chassisUp') class EntityManager(DefaultManager): """A manager class for NetboxEntity objects""" def __init__(self, *args, **kwargs): super(EntityManager, self).__init__(*args, **kwargs) self.netbox = self.containers.get(None, Netbox) self.matched = set() self.missing = set() self.existing = set() @transaction.atomic() def save(self): """Override parent only to add transaction handling""" super(EntityManager, self).save()
class Device(Shadow): __shadowclass__ = manage.Device __lookups__ = ['serial'] event = EventFactory('ipdevpoll', 'eventEngine', 'deviceNotice') def __init__(self, *args, **kwargs): super(Device, self).__init__(*args, **kwargs) self.changed_versions = {} def prepare(self, containers): self._fix_binary_garbage() self._detect_version_changes() def _fix_binary_garbage(self): """Fixes version strings that appear as binary garbage.""" for attr in ( 'hardware_version', 'software_version', 'firmware_version', 'serial', ): value = getattr(self, attr) if utils.is_invalid_database_string(value): self._logger.warning("Invalid value for %s: %r", attr, value) setattr(self, attr, repr(value)) self.clear_cached_objects() def _detect_version_changes(self): """ Detects if the software, hardware or firmware version changed for each device. Saves this information in changed_versions in the Device instance. """ old_device = self.get_existing_model() if old_device: changed_versions = set( self.get_diff_attrs(old_device)).intersection(( 'hardware_version', 'software_version', 'firmware_version', )) for version in changed_versions: self.changed_versions[version] = getattr(old_device, version) def cleanup(self, containers): if self.changed_versions: self._post_events_version_changes(containers) def _post_events_version_changes(self, containers): """Posts events for software, hardware or firmware changes.""" device = self.get_existing_model() for alert_type, old_version in self.changed_versions.items(): self.event.notify( device=device, netbox=containers.get(None, Netbox).get_existing_model(), alert_type=ALERT_TYPE_MAPPING[alert_type], varmap={ "old_version": old_version, }, ).save()