예제 #1
0
파일: app.py 프로젝트: dutch2005/hermes
def init_db():
    logger.warning("Database will be created from scratch")

    db.drop_all()
    db.create_all()

    with app.app_context():

        super_admin_role = Role(name='superadmin')
        admin_role = Role(name='admin')

        db.session.add(super_admin_role)
        db.session.add(admin_role)

        db.session.commit()

        test_user = admins_store.create_user(
            first_name='admin',
            last_name='hermes',
            email='hermes@localhost',
            password=hash_password('admin'),
            roles=[super_admin_role, admin_role])

        db.session.add(test_user)

        db.session.commit()

    logger.info("Database has been created")
    return
예제 #2
0
def export_automates():
    if 'file' not in request.files:
        return jsonify({'message': 'Aucun fichier envoyé'}), 400

    mon_fichier = request.files['file']  # type: FileStorage

    if mon_fichier.content_type != 'application/json' or mon_fichier.filename.endswith(
            '.json') is False:
        return jsonify(
            {'message':
             _('Fichier message invalide, fichier JSON requis !')}), 400

    def rec_(at, act):
        """
        :param Automate at:
        :param ActionNoeud act:
        :return:
        """
        act.automate_id = at.id
        if act.action_reussite is not None:
            rec_(at, act.action_reussite)
        if act.action_echec is not None:
            rec_(at, act.action_echec)

    db.session.query(ActionNoeudExecution).delete()
    db.session.query(RechercheInteretExecution).delete()
    db.session.query(AutomateExecution).delete()

    for sb in ActionNoeud.__subclasses__():
        db.session.query(sb).delete()

    db.session.query(ActionNoeud).delete()
    db.session.query(Automate).delete()

    db.session.query(LienDetecteurRechercheInteret).delete()

    db.session.query(LienSousRegleOperationLogique).delete()

    for sb in RechercheInteret.__subclasses__():
        db.session.query(sb).delete()

    db.session.query(RechercheInteret).delete()

    db.session.query(Detecteur).delete()

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

    try:
        from json import loads
        automates = AutomateLegacySchema(many=True).load(
            loads(mon_fichier.stream.read().decode(
                'ascii')))  # type: list[Automate]
    except MarshmallowError as e:
        return jsonify({
            'message':
            _("Impossible d'importer votre fichier '{fname}' car votre fichier ne respecte pas la structure JSON obligatoire ! '{msg_err}'."
              ).format(fname=mon_fichier.filename, msg_err=str(e))
        }), 409

    for automate in automates:

        try:
            act_r = deepcopy(automate.action_racine)
            automate.action_racine = None

            automate.createur = current_user
            automate.responsable_derniere_modification = current_user

            automate.detecteur.createur = current_user
            automate.detecteur.responsable_derniere_modification = current_user

            for rg in automate.detecteur.regles:

                ri_ex = db.session.query(RechercheInteret).filter_by(
                    designation=rg.designation,
                    mapped_class_child=rg.mapped_class_child).first()

                if ri_ex is not None:
                    automate.detecteur.regles[automate.detecteur.regles.index(
                        rg)] = ri_ex

            db.session.add(automate)
            db.session.commit()

            if act_r is not None:
                rec_(automate, act_r)
                automate.action_racine = act_r
                db.session.commit()

        except SQLAlchemyError as e:
            logger.error(_(
                "Impossible d'importer votre automate '{automate_nom}' car une erreur de transposition en base de données est survenue '{msg_err}'."
            ),
                         automate_nom=automate.designation,
                         msg_err=str(e))
            continue

    try:
        db.session.flush()
    except SQLAlchemyError as e:
        logger.warning(_("Erreur SQL '{err_msg}'."), err_msg=str(e))
        return jsonify({
            'message':
            _('Erreur de transaction SQL : {err_msg}').format(err_msg=str(e))
        }), 409

    return jsonify({}), 204
예제 #3
0
        test_user = admins_store.create_user(
            first_name='admin',
            last_name='hermes',
            email='hermes@localhost',
            password=hash_password('admin'),
            roles=[super_admin_role, admin_role])

        db.session.add(test_user)

        db.session.commit()
    return


try:
    db.session.query(Role).all()
except NoReferencedTableError as e:
    init_db()
except NoSuchTableError as e:
    init_db()
except OperationalError as e:
    init_db()
except ProgrammingError as e:
    init_db()
except Exception as e:
    logger.warning(_(
        'Exception générique attrapée lors de la requête de test schéma. "{msg_err}"'
    ),
                   msg_err=str(e))
    init_db()
예제 #4
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