Forum Français

 View Only

ArubaOS-CX et l'automatisation - Part 4.1 : Basique des scripts avec Network Analytics Engine

This thread has been viewed 0 times
  • 1.  ArubaOS-CX et l'automatisation - Part 4.1 : Basique des scripts avec Network Analytics Engine

    Posted Dec 17, 2018 06:06 PM

    Comme évoqué dans le post précédent présentant le Framework Network Analytics d’Engine d’ArubaOS-CX, nous allons ici voir la structure et les possibilités des scripts supportés par cet outil, et des agents en découlant.

    Pour cette présentation, nous allons prendre un script disponible sur Aruba Solution Exchange, qui permet de monitorer le statut d'une interface.

     

    1. Les éléments de base du script

     

    Dans la construction d'un script destiné au Network Analytics Engine, certains parties sont obligatoires, car utilisées par ce dernier dans l’instanciation et la création des agents.

    Ces parties obligatoires sont les suivantes :

     

    Header

     

    Cette partie permet de présenter les aspects légaux et de licences liés à l’utilisation de ce script, notamment Apache2

    Il a la forme :

     

    #-*- coding: utf-8 -*-
    #
    #Copyright (c) 2017 Hewlett Packard Enterprise Development LP
    #
    #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.

    Manifest

     

    Cette variable, qui se présente sous forme de dictionnaire, reprend l’ensemble des metadatas et les détails qui sont utilisés pour le stockage des informations relatives au script dans la base de données.

    Dans notre cas :

    Manifest = {
    'Name': 'single_interface_link_state_monitor',
    'Description': 'Interface Link Status Monitoring Agent',
    'Version': '1.0',
    'Author': 'Aruba Networks'
    }

    Nous retrouvons donc ces valeurs, dans la WebUI d’ArubaOS-CX, de la manière suivante, lorsque le script est uploadé :

     
    Screen Shot 2018-12-17 at 23.16.28.png

    ParameterDefinitions

     

    Cette variable reprend un dictionnaire de dictionnaires, dans lequel on peut trouver l’ensemble des paramètres utilisés dans l’agent. Étant donné que l’on ne spécifie pas ici de valeur spécifique, hormis une valeur par défaut, cela implique que chaque agent peut avoir ses propres valeurs.

    Dans notre cas :

     

    ParameterDefinitions = {
    'interface_id': {
    'Name': 'Interface Id',
    'Description': 'Interface to be monitored',
    'Type': 'string',
    'Default': '1/1/1'
    }
    }

    Ici, nous allons créer une variable qui a pour nom “interface_id”, de type “string”, et dont la valeur par défaut est “1/1/1”.

    Nous retrouvons donc ces valeurs, dans la WebUI d’ArubaOS-CX, de la manière suivante, lorsque le script est uploadé :

    Screen Shot 2018-12-17 at 23.16.34.png

     

    Corps du script (Class)

     

    C’est dans cette partie, qui n’est autre qu’une classe permettant d’instancier un objet, que l’on retrouve l’ensemble des fonctions, donc les méthodes, disponibles pour l’agent en cours d’utilisation ou de création.

     

    class Policy(NAE):
    
        def __init__(self):

    2. Les méthodes nécessaires

     

    Les monitors

     

    Cette partie du script permet de pouvoir définir les objets que l’on souhaite monitorer. La définition de ces objets est réalisée sur la base des URI spécifiques liées.

    Par exemple, dans notre cas :

     

    uri1 = '/rest/v1/system/interfaces/{}?attributes=link_state'
    self.m1 = Monitor(uri1, 'Interface Link status', [self.params['interface_id']])

    Nous avons donc défini une variable “uri”, qui est ensuite utilisée comme paramètre de la fonction Monitor, qui est une fonction native au Network Analytics Engine, permettant d’indiquer au système de monitorer une URI, et qui prend les paramètres suivantes :

    • URI à monitorer
    • Description
    • Valeur a positioner dans l’URI (a la place des “{}”)

    Le résultat de cette fonction est positionné dans la variable “m1” (“self” étant une variable liée à la programmation objet, et qui représente l’instanciation de la classe, ici “Agent”)

    Si on souhaite prendre une clé spécifique dans le JSON de retour, il est possible de le spécifier.

    Par exemple :

    • /rest/v1/system/subsystem/system/base/attributes=resource_utilization.cpu
    • “.cpu” indique la valeur a prendre dans le JSON de retour.

    La déclaration des Monitors est à realiser dans la méthode spéciale "__init__", de manière à être lancée dès que l'agent est créé.

     

    Règles, Conditions et Actions

     

    Il s’agit ici de spécifier certains des éléments les plus importants du script :

    • Règles : Instanciation d’une règle de monitoring, et qui peut être déclenché en fonction d’une condition.
    • Conditions : Détermination de la condition de déclenchement d’une action, liée à la règle.
    • Actions : Actions prises par le Network Analytics Engine dans le cadre de cette règle

    Par exemple, dans notre cas :

     

    self.r1 = Rule('Link Went Down')
    self.r1.condition('transition {} from "up" to "down"', [self.m1])
    self.r1.action(self.action_interface_down)

    Nous créons donc ici une règle, dont le nom est “Link Went Down”. Cette instanciation de règles est positionnée dans la règle “r1”.

    Nous créons une nouvelle condition, au travers de la méthode “condition”, qui est incluse dans la règle “r1” que nous venons de créer. Ici, notre condition est une transition d’un statut “up” à un statut “down” de l'interface monitorée (“m1”)

    Dans la cas du déclenchement de cette condition, nous réalisons alors une action, qui consiste à exécuter la fonction “action_interface_down”.

     

    La déclaration des Règles, avec leurs Conditions et Actions est à realiser dans la méthode spéciale "__init__", de manière à être lancée dès que l'agent est créé.

     

    3. Actions : Les fonctions

     

    La définition des actions, globalement la fonction associée, est à réaliser hors de la methode "__init__".

     

    Il existe 3 types de fonctions disponibles :

    1. Les actions prédéfinies, natives au Network Analytics Engine
    2. Les Callback Actions, qui sont des fonctions appelées par la règle afin de réaliser des actions complémentaires
    3. Les Clear Actions, qui sont les actions appelées la règle, qui sont exécutées lorsque la condition n’est plus valide, et que le comportement/monitoring redevient normal

    Comme nous avons pu le voir la méthode “action” fait appel à d’autres fonctions intégrées dans l’agent.

    Commençons par étudier une fonction de notre script.

    Ici, nous faisons appel à la fonction “action_port_down” lorsque le statut administrative d’un port passe de “up” a “down”.

     

    Voici la fonction :

     def action_interface_down(self, event):
    self.logger.debug("================ Down ================")
    if self.get_alert_level() != AlertLevel.CRITICAL:
    ActionSyslog('Interface {} Link gone down', [self.params['interface_id']])
    ActionCLI("show lldp configuration {}", [self.params['interface_id']])
    ActionCLI("show interface {} extended", [self.params['interface_id']])
    self.set_alert_level(AlertLevel.CRITICAL)
    self.logger.debug("================ /Down ================")

    Plusieurs éléments importants sont à noter dans cette fonction :

     

    Appel de la variable “event” – Le Network Analytics Engine peut récupérer l’ensemble des informations relatives à l’évènement qui vient de se passer. C’est informations sont alors disponibles dans “event”, qui est un dictionnaire comprenant les clés suivantes :

    • event['labels'] : Labels de l’évènement créé dans la base Time Series
    • event['condition_name'] : Nom de la condition qui a déclenché l’évènement
    • event['monitor_name'] : Nom du monitor associé
    • event['time_series'] : Nom de la métrique Time Series associée (valeur)
    • event['value'] : Valeur de la métrique Time Series associée
    • event['timestamp'] : Timestamp de l’évènement génère
    • event['condition_description'] : Description de la condition qui a déclenché l’évènement

    Appel des fonctions “ActionCLI” et “ActionSyslog” – Ces fonctions sont des fonctions natives au Network Analytics Engine. “ActionCLI” permet de passer une commande CLI sur l’equipement, passé en paramètre, et d’afficher le résultat associé dans le détail de l’alerte sur la WebUI, tandis qu’“ActionSyslog” permet de générer un Syslog, dont le texte est passé en paramètre. Nous voyons que nous pouvons toujours faire appel au paramètre que nous avions défini. Nous verrons toutes les actions disponibles par la suite.

     

    Modification du niveau d’alerte de l’agent – La fonction “self.get_alert_level()” permet de récupérer le statut courant de l’agent. Dans notre fonction, nous considérons que si le statut courant n’est pas au niveau “CRITICAL”, alors nous le passons à ce niveau avec la fonction “self.set_alert_level()”

     

    Création d'un log Python - L’interpréteur Python utilise par le Network Analytics Engine embarque également nativement le module “logging”, et plus particulièrement une instanciation de la classe Logger, qui permet par exemple ici de générer un log Python avec comme description ce qui lui est passé en paramètre.

     

    Pour résumer, voici ce que fait notre fonction :

    1. Nous créons un log Python, de niveau debug, pour indiquer que nous commençons la fonction associée au statut "Down".
    2. Si le statut de notre agent n’est pas au niveau “CRITICAL”, alors nous executons le code suivant :
    3. Elle crée un Syslog dont le contenu sera “'Interface {} Link gone down'” ({} étant remplacé par le nom de l'interface)
    4. Elle passe 2 lignes de commandes sur l’equipement : “show lldp configuration {}" et “show interface {} extended” ({} étant remplacé par le nom du port)
    5. Nous passons le statut de l'agent au niveau Critical.
    6. Enfin, nous créons un log Python pour indiquer que la fonction a été exécutée.

    Voici ce que cela donne en exploitation, lorsque l’évènement est déclenché.

    Vue detaillée de l'alerte :Screen Shot 2018-12-17 at 23.27.33.png

    Résultat de la commande "show lldp configuration 1/1/1", en cliquant sur "output" :Screen Shot 2018-12-17 at 23.27.45.png

     

    4. Les différentes actions natives possibles

     

    Comme nous l’avons vu, différentes fonctions d’actions sont disponibles nativement dans le Network Analytics Engine, de manière a pouvoir réaliser des actions sur l’equipement. Nous pouvons y trouver :

    • ActionCLI : Permet d’exécuter n’importe quelle ligne de commande, comme si nous étions en CLI sur l’equipement. Ex : ActionCLI("config
      interface 1/1/1
      no shutdown
      exit
      exit")
    • ActionShell : Permet d’exécuter une commande en mode Bash sur l’equipement. Ex : ActionShell("cd {}",[ self.params["path"])
    • ActionSyslog : Permet de créer un Syslog dont le message est le texte passé en paramètre. Ex : ActionSyslog("Sample message: {}", [self.params["message"]]). Il est a noter qu’il est possible de passer l’adresse IP du Syslog directement en paramètre. Ex : ActionSyslog("Sample message: {}", "tcp:172.17.0.2:444", [self.params["message"]])
    • ActionCustomReport : Permet de pouvoir générer une page Web au format HTML, dont le contenu est passé en paramètre. Ex : ActionCustomReport(my_template, [self.params["author"]])

    Ces actions peuvent également être appelées hors des "Callback Actions", en utilisant le format suivant :

     

    self.r.action("SHELL", "cd {}",[ self.params["path"])

    Les Clear Actions sont elles appelées de la maniere suivante :

     

    self.rule.clear_action(self.set_normal)

    5. Script dans sa globalité

     

    Si nous reprenons notre exemple, et ainsi toutes les notions de voir, voici le script dans sa globalité :

     

     

    # -*- coding: utf-8 -*-
    #
    # (c) Copyright 2017-2018 Hewlett Packard Enterprise Development LP
    #
    # 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.
    
    Manifest = {
        'Name': 'single_interface_link_state_monitor',
        'Description': 'Interface Link Status Monitoring Agent',
        'Version': '1.0',
        'Author': 'Aruba Networks'
    }
    
    ParameterDefinitions = {
        'interface_id': {
            'Name': 'Interface Id',
            'Description': 'Interface to be monitored',
            'Type': 'string',
            'Default': '1/1/1'
        }
    }
    
    class Agent(NAE):
    
        def __init__(self):
            # Definition de l'URI cible et du monitor
            uri1 = '/rest/v1/system/interfaces/{}?attributes=link_state'
            self.m1 = Monitor(uri1,'Interface Link status', [self.params['interface_id']])
    # Declaration de la règle, de la condition de declenchement et de l'action associée. self.r1 = Rule('Link Went Down') self.r1.condition('transition {} from "up" to "down"', [self.m1]) self.r1.action(self.action_interface_down)
    # Declaration des conditions et actions de retour à la normale. self.r1.clear_conditions(condition('transition {} from "down" to "up"', [self.m1]) self.r1.clear_actions(self.action_interface_up)
    # Déclaration de la fonction et des actions qui seront réalisées lorsque l'interface devient down. def action_interface_down(self, event): self.logger.debug("================ Down ================") if self.get_alert_level() != AlertLevel.CRITICAL: ActionSyslog( 'Interface {} Link gone down', [self.params['interface_id']]) ActionCLI("show lldp configuration {}", [self.params['interface_id']]) ActionCLI("show interface {} extended", [self.params['interface_id']]) self.set_alert_level(AlertLevel.CRITICAL) self.logger.debug("================ /Down ================")
    # Déclaration de la fonction et des actions qui seront réalisées lorsque l'interface redevient up. def action_interface_up(self, event): self.logger.debug("================ Up ================") if self.get_alert_level() is not None: ActionSyslog('Interface {} Link came up', [self.params['interface_id']]) self.remove_alert_level() self.logger.debug("================ /Up ================")

    Nous verrons dans la partie 4.2, comment gerer les scripts et agents via la WebUI, mais également la partie Baselining, ADC et troubleshooting.

     

    Pour plus d'informations, n'hesitez pas à consulter la configuration guide du Network Analytics Engine, sur le site du support Aruba.