Example #1
0
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)
Example #2
0
"""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)
Example #3
0
"""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():
Example #4
0
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()
Example #5
0
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()