예제 #1
0
    def on_model_change(self, form, model, is_created):
        """

        :param form:
        :param Configuration model:
        :param bool is_created:
        :return:
        """
        if is_created is True:
            model.createur = current_user
            model.date_creation = datetime.now()

        model.date_modification = datetime.now()
        model.responsable_derniere_modification = current_user

        Session.charger_input(model.designation, model.valeur, model.format)
예제 #2
0
    def thread():

        logger.info(_("Chargement des variables globales passées en base de données"))
        configurations = db.session.query(Configuration).all()  # type: list[Configuration]

        for configuration in configurations:
            logger.info(_("Chargement de la configuration <'{conf_nom}'::{conf_format}>"), conf_nom=configuration.designation, conf_format=configuration.format)
            try:
                Session.charger_input(
                    configuration.designation,
                    configuration.valeur,
                    configuration.format
                )
            except TypeError as e:
                logger.error(_("Impossible de charger la configuration <'{conf_nom}'::{conf_format}> car '{error_msg}'"), conf_nom=configuration.designation, conf_format=configuration.format, error_msg=str(e))

        logger.info(_("Démarrage de la boucle de surveillance des automates sur les boîtes IMAP4"))

        InstanceInteroperabilite.liste_attente_test_lock.acquire()
        est_une_sequence_test = len(InstanceInteroperabilite.liste_attente_test) > 0

        if not est_une_sequence_test:
            InstanceInteroperabilite.liste_attente_test_lock.release()

        while InstanceInteroperabilite.stop_instruction is None:

            boites_aux_lettres = db.session.query(BoiteAuxLettresImap).all()  # type: list[BoiteAuxLettresImap]
            mail_factories = []

            for el in boites_aux_lettres:
                try:
                    mail_factories.append(
                        el.get_mailtoolbox()
                    )
                except LoginError as e:
                    logger.error(_("Impossible de démarrer l'usine "
                                                        "à production de source '{designation}' car '{msg_err}'"), designation=el.designation, msg_err=str(e))
                except Exception as e:
                    logger.error(_("Impossible de démarrer l'usine "
                                                        "à production de source '{designation}' car '{msg_err}'"), designation=el.designation, msg_err=str(e))

            if len(mail_factories) == 0:
                logger.warning(_("Aucune usine à production de source n'est active, impossible de continuer"))
                break

            logger.debug(_("{n} usine(s) à production de source sont actives"), n=len(mail_factories))

            if est_une_sequence_test:
                models_automates = db.session.query(Automate).filter_by(production=False).all()  # type: list[Automate]
            else:
                models_automates = db.session.query(Automate).filter_by(production=True).all()  # type: list[Automate]

            models_automates.sort(key=lambda x: x.priorite, reverse=True)

            if len(models_automates) == 0:
                logger.warning(
                    _("Aucune automate à traitement de source n'est actif, impossible de continuer"))
                break

            logger.debug(_("{n} automates en production sont actifs"), n=len(models_automates))

            for mail_factory in mail_factories:

                logger.debug(_("Ouverture de la BAL '{nom_utilisateur}'@'{hote_imap}'"), nom_utilisateur=mail_factory.nom_utilisateur, hote_imap=mail_factory.hote_imap)

                if InstanceInteroperabilite.stop_instruction is not None:
                    logger.info(_("Arrêt de la surveillance continue des BAL"))
                    return

                sources = mail_factory.extraire()

                logger.debug(_("{n} sources ont été extraites de l'usine à production '{usine}'"), n=len(sources), usine=str(mail_factory))

                for source in sources:

                    logger.debug(_("Vérification du message électronique '{source_nom}'"), source_nom=source.titre)

                    for model in models_automates:

                        automate = model.transcription()

                        if InstanceInteroperabilite.stop_instruction is not None:
                            logger.info(_("Arrêt de la surveillance continue des BAL"))
                            return

                        if est_une_sequence_test and model.id not in InstanceInteroperabilite.liste_attente_test:
                            logger.debug(_("Séquence de test ne conserne pas '{automate_nom}'."), automate_nom=model.designation)
                            continue

                        date_depart_automate = datetime.now()

                        # On vérifie les conditions pour anti-spam
                        nb_execution_heure = db.session.query(AutomateExecution).filter(
                            AutomateExecution.automate == model,
                            AutomateExecution.sujet == source.titre,
                            AutomateExecution.corps == source.corps,
                            # AutomateExecution.validation_automate == False,
                            AutomateExecution.date_creation >= (date_depart_automate - timedelta(hours=1))
                        ).count()

                        if nb_execution_heure >= (model.limite_par_heure if model.limite_par_heure is not None else 100):
                            logger.warning(
                                _("L'automate '{automate_nom}' ne va pas traiter la source '{source_nom}' car celle ci  "
                                "dépasse la limite de {n} lancement(s) par heure."),
                                automate_nom=automate.designation,
                                source_nom=source.titre,
                                n=(model.limite_par_heure if model.limite_par_heure is not None else 100)
                            )
                            continue

                        nb_execution_echec_heure = db.session.query(AutomateExecution).filter(
                            AutomateExecution.automate == model,
                            AutomateExecution.sujet == source.titre,
                            AutomateExecution.corps == source.corps,
                            AutomateExecution.validation_automate == False,
                            AutomateExecution.date_creation >= (date_depart_automate - timedelta(hours=1))
                        ).count()

                        if nb_execution_echec_heure >= (model.limite_echec_par_heure if model.limite_echec_par_heure is not None else 10):
                            logger.warning(
                                _("L'automate '{automate_nom}' ne va pas traiter la source '{source_nom}' car celle ci  "
                                "dépasse la limite en échec de {n} lancement(s) par heure."),
                                automate_nom=automate.designation,
                                source_nom=source.titre,
                                n=(model.limite_echec_par_heure if model.limite_echec_par_heure is not None else 10)
                            )
                            continue

                        try:
                            etat_final_automate = automate.lance_toi(source)

                            if etat_final_automate is True:
                                logger.info(
                                    _("L'automate '{automate_nom}' vient de traiter avec succès la source '{source_nom}'"),
                                    automate_nom=automate.designation,
                                    source_nom=source.titre
                                )
                            elif etat_final_automate is False and automate.detecteur.est_accomplis is True:
                                logger.warning(
                                    _("L'automate '{automate_nom}' vient de traiter avec au moins une erreur la source '{source_nom}'"),
                                    automate_nom=automate.designation,
                                    source_nom=source.titre
                                )

                                if model.notifiable is True:
                                    NotificationIncident.prevenir(
                                        model,
                                        source,
                                        _("L'automate '{automate_nom}' n'a pas réussi à aboutir, au moins une action est en échec").format(automate_nom=automate.designation),
                                        _("Vous recevez ce message car votre automate '{automate_nom}' est configurée "
                                        "pour émettre une notification dans ce cas. \n\n"
                                        "En PJ les élements nécessaires à l'analyse des évènements. "
                                        "L'automate est toujours actif. \n\n").format(
                                            automate_nom=automate.designation,
                                        )
                                    )

                        except AucuneObligationInteretException as e:
                            logger.error(
                                _("L'automate '{automate_nom}' ne dispose pas d'un détecteur contraignant, "
                                "il est nécessaire d'avoir au moins une règle avec obligation. "
                                "Désactivation de l'automate."),
                                automate_nom=automate.designation
                            )
                            model.production = False
                            db.session.commit()
                            db.session.flush()
                            continue
                        except KeyError as e:
                            logger.error(
                                _("L'automate '{automate_nom}' est en erreur grave, "
                                "une variable est non résolue: '{err_msg}'"),
                                automate_nom=automate.designation,
                                err_msg=str(e)
                            )
                            NotificationIncident.prevenir(
                                model,
                                source,
                                _("L'automate '{automate_nom}' est en erreur grave, une variable est non résolue !").format(
                                    automate_nom=automate.designation),
                                _("Vous recevez ce message car votre automate '{automate_nom}' n'est pas en mesure d'aboutir. \n\n"
                                "Une variable est non résolue. Veuillez revenir en conception. "
                                "L'automate <b>a été désactivé</b> par précaution. \n\n"
                                "Information technique: \n\n"
                                "<pre class='code code-html'><label></label><code>{msg_err}</code></pre>").format(
                                    automate_nom=automate.designation,
                                    msg_err=str(e)
                                )
                            )

                            model.production = False

                            db.session.commit()
                            db.session.flush()

                            continue
                        except Exception as e:

                            from sys import exc_info
                            from os import path
                            import traceback

                            exc_type, exc_obj, exc_tb = exc_info()

                            logger.critical(
                                _("L'automate '{automate_nom}' est en erreur critique, "
                                "une exception est soulevée: '{msg_err}'"),
                                automate_nom=automate.designation,
                                msg_err=str(e)
                            )

                            fname = path.split(exc_tb.tb_frame.f_code.co_filename)[1]

                            logger.critical(
                                _("Informations complémentaires '{exc_type}', '{fname}' à la ligne {lineno}."), exc_type=str(exc_type), fname=str(fname), lineno=str(exc_tb.tb_lineno)
                            )

                            logger.critical(
                                traceback.format_exc()
                            )

                            NotificationIncident.prevenir(
                                model,
                                source,
                                _("L'automate '{automate_nom}' est en erreur critique, une exception est soulevée !").format(automate_nom=automate.designation),

                                _("Vous recevez ce message car votre automate '{automate_nom}' n'est pas en mesure d'aboutir. \n\n"
                                "Une exception est non résolue. Veuillez revenir en conception. "
                                "L'automate a été désactivé par précaution. \n\n"
                                "Information technique: \n\n"
                                "<pre class='code code-html'><label>Logs</label><code>{msg_err}</code></pre>").format(automate_nom=automate.designation, msg_err=traceback.format_exc())
                            )

                            model.production = False

                            db.session.commit()
                            db.session.flush()

                            continue

                        if automate.detecteur.est_accomplis is True:

                            automate_execution = AutomateExecution(
                                automate=model,
                                sujet=source.titre if len(source.titre) < 255 else source.titre[1:250]+'..',
                                corps=source.corps,
                                date_creation=date_depart_automate,
                                detecteur=model.detecteur,
                                validation_detecteur=automate.detecteur.est_accomplis,
                                validation_automate=etat_final_automate,
                                explications_detecteur=automate.detecteur.explain(),
                                date_finalisation=datetime.now(),
                                logs=automate.logs
                            )

                            for action_lancee in automate.actions_lancees:

                                action_noeud_execution = ActionNoeudExecution(
                                    automate_execution=automate_execution,
                                    action_noeud=db.session.query(ActionNoeud).filter_by(designation=action_lancee.designation, automate_id=model.id).one(),
                                    validation_action_noeud=action_lancee.est_reussite,
                                    payload=str(action_lancee.payload),
                                    args_payload=dumps(action_lancee.snapshot)
                                )

                                db.session.add(action_noeud_execution)

                            db.session.add(automate_execution)
                            db.session.commit()

                            break  # La source a été traitée. Pas besoin d'y appliquer un autre automate.

                db.session.flush()

            if est_une_sequence_test:
                InstanceInteroperabilite.liste_attente_test.clear()
                InstanceInteroperabilite.liste_attente_test_lock.release()
                break

            sleep(1 if len(mail_factories) > 0 else 10)

        logger.info(_("Fin de surveillance continue des automates sur les boîtes IMAP4"))
        InstanceInteroperabilite.current_thread = None