#!/bin/bash /usr/scripts/python.sh
# -*- coding: utf-8 -*-
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This file is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
"""Ce fichier propose un client snmp basique"""

import netsnmp
import socket

import gestion.secrets_new as secrets_new

class SNMPClient(object):
    """Classe de base définissant un client SNMP."""

    def __init__(self, host):
        """Crée une session pointant vers le serveur SNMP, et
        peuple les variables utiles."""
        # Le fait se gérer si c'est .adm.crans.org, .crans.org, ou
        # si le nom est un fqdn ou pas est du ressort du DNS (dans la
        # mesure où de toute façon, si on a pas de dns, contacter les
        # switches dont on doit résoudre l'IP va être tendu).
        try:
            self.host = socket.gethostbyname_ex(host)[0]
        except socket.gaierror:
            self.host = host

        self.__session = None
        self.__version3 = False
        self.__snmp_community = None
        self.__snmp_version = None
        self.__snmp_seclevel = None
        self.__snmp_authprotocol = None
        self.__snmp_authpassword = None
        self.__snmp_secname = None
        self.__snmp_privprotocol = None
        self.__snmp_privpassword = None

    def __get_session(self, version3=False):
        """Crée une session en cas de besoin, en vérifiant qu'une
        session répondant aux besoins n'existe pas déjà."""
        if version3 and self.__version3 and self.__session:
            return self.__session

        if not version3 and not self.__version3 and self.__session:
            return self.__session

        if version3 and (not self.__version3 or not self.__session):
            self.__snmp_community = 'private'
            self.__snmp_version = 3
            self.__snmp_seclevel = 'authPriv'
            self.__snmp_authprotocol = 'SHA'
            self.__snmp_authpassword = secrets_new.get('snmp_authentication_pass')
            self.__snmp_secname = 'crans'
            self.__snmp_privprotocol = 'DES'
            self.__snmp_privpassword = secrets_new.get('snmp_privacy_pass')

        if not version3 and (self.__version3 or not self.__session):
            self.__snmp_community = 'public'
            self.__snmp_version = 1
            self.__snmp_seclevel = 'noAuthNoPriv'
            self.__snmp_authprotocol = 'DEFAULT'
            self.__snmp_authpassword = ''
            self.__snmp_secname = 'initial'
            self.__snmp_privprotocol = 'DEFAULT'
            self.__snmp_privpassword = ''

        self.__version3 = version3
        session = netsnmp.Session(Version=self.__snmp_version, DestHost=self.host,
                                  Community=self.__snmp_community, SecLevel=self.__snmp_seclevel,
                                  SecName=self.__snmp_secname, PrivProto=self.__snmp_privprotocol,
                                  PrivPass=self.__snmp_privpassword, AuthProto=self.__snmp_authprotocol,
                                  AuthPass=self.__snmp_authpassword)

        return session

    def walk(self, attribute):
        """Fait un walk.

        Exemple:
            Si je demande hpSwitchPortFdbAddress, le retour contiendra
            des entrées ayant pour tag hpSwitchPortFdbAddress, pour iid
            une éventuelle valeur (si pertinent), et pour val la valeur
            associée."""

        self.__session = self.__get_session()

        # Crée une variable netsnmp exploitable pour walk.
        __varbind = netsnmp.Varbind(attribute)

        # La stocke dans une liste.
        __varlist = netsnmp.VarList(__varbind)

        # __varlist est modifiée en place par la méthode walk.
        _ = self.__session.walk(__varlist)

        return [
            {
                'tag': ret.tag,
                'iid': ret.iid,
                'val': ret.val,
            }
            for ret in __varlist
        ]

    def set(self, list_of_vars):
        """Met à jour un attribut"""
        # On passe en SNMPv3
        self.__session = self.__get_session(True)

        # On construit la varlist à balancer en SNMP
        __varlist = [
            netsnmp.Varbind(
                tag=res['tag'],
                iid=res['iid'],
                val=res['val']
            )
            for res in list_of_vars
        ]

        # Oui, c'est moche
        __varlist = netsnmp.VarList(*__varlist)

        __ret = self.__session.set(__varlist)

        return __ret

