Project

General

Profile

Revision 51ede5e8

ID51ede5e86dacc738d21c587f7f22b2e2a9c4273f
Parent dde732e5
Child 19e88cb8

Added by Thomas ANDREJAK almost 15 years ago

Préparation pour le vigiboard séparé du vigicore

git-svn-id: https://vigilo-dev.si.c-s.fr/svn@348 b22e2e97-25c9-44ff-b637-2e5ceca36478

View differences:

README/README.txt
1 1
########################
2
#    SVN
3
########################
4

  
5
Révision SVN juste avant la séparation entre vigiboard et vigicore : 346 
6

  
7
########################
2 8
#    Désactiver l'environnement virtuel
3 9
########################
4 10

  
development.ini
21 21

  
22 22
[app:main]
23 23
use = egg:vigiboard
24
appname = vigiboard
24 25
full_stack = true
25
#lang = zh_tw 
26
#lang = fr
26 27
cache_dir = %(here)s/data
27 28
beaker.session.key = vigiboard
28 29
beaker.session.secret = somesecret
production.ini
20 20

  
21 21
[app:main]
22 22
use = egg:vigiboard
23
appname = vigiboard
23 24
full_stack = true
24 25
#lang = fr
25 26
cache_dir = %(here)s/data
setup.cfg
3 3
tag_svn_revision = true
4 4

  
5 5
[easy_install]
6
#find_links = http://www.pylonshq.com/download/
7 6
find_links =
8 7
	http://vigilo-dev.local/python/eggs/zc.buildout
9 8
	http://vigilo-dev.local/python/eggs/PasteScript
setup.py
46 46

  
47 47
    entry_points="""
48 48
    [paste.app_factory]
49
    main = vigiboard.config.middleware:make_app
49
    main = vigicore.config.middleware:make_app
50 50

  
51 51
    [paste.app_install]
52 52
    main = pylons.util:PylonsInstaller
vigiboard/__init__.py
1
# -*- coding: utf-8 -*-
2
"""The vigiboard package"""
vigiboard/config/__init__.py
1
# -*- coding: utf-8 -*-
2

  
vigiboard/config/app_cfg.py
1
# -*- coding: utf-8 -*-
2
"""
3
Global configuration file for TG2-specific settings in vigiboard.
4

  
5
This file complements development/deployment.ini.
6

  
7
Please note that **all the argument values are strings**. If you want to
8
convert them into boolean, for example, you should use the
9
:func:`paste.deploy.converters.asbool` function, as in::
10
    
11
    from paste.deploy.converters import asbool
12
    setting = asbool(global_conf.get('the_setting'))
13
 
14
"""
15

  
16
from tg.configuration import AppConfig
17

  
18
import vigiboard
19
from vigiboard import model
20
from vigiboard.lib import app_globals, helpers 
21

  
22
base_config = AppConfig()
23
base_config.renderers = []
24

  
25
base_config.package = vigiboard
26

  
27
#Set the default renderer
28
base_config.default_renderer = 'genshi'
29
base_config.renderers.append('genshi')
30
# if you want raw speed and have installed chameleon.genshi
31
# you should try to use this renderer instead.
32
# warning: for the moment chameleon does not handle i18n translations
33
#base_config.renderers.append('chameleon_genshi')
34

  
35
#Configure the base SQLALchemy Setup
36
base_config.use_sqlalchemy = True
37
base_config.model = vigiboard.model
38
base_config.DBSession = vigiboard.model.DBSession
39

  
40
# Configure the authentication backend
41
base_config.auth_backend = 'sqlalchemy'
42
base_config.sa_auth.dbsession = model.DBSession
43
# what is the class you want to use to search for users in the database
44
base_config.sa_auth.user_class = model.User
45
# what is the class you want to use to search for groups in the database
46
base_config.sa_auth.group_class = model.Group
47
# what is the class you want to use to search for permissions in the database
48
base_config.sa_auth.permission_class = model.Permission
49

  
50
# override this if you would like to provide a different who plugin for
51
# managing login and logout of your application
52
base_config.sa_auth.form_plugin = None
53

  
54
# You may optionally define a page where you want users to be redirected to
55
# on login:
56
base_config.sa_auth.post_login_url = '/post_login'
57

  
58
# You may optionally define a page where you want users to be redirected to
59
# on logout:
60
base_config.sa_auth.post_logout_url = '/post_logout'
vigiboard/config/deployment.ini_tmpl
1
#
2
# vigiboard - TurboGears configuration
3
#
4
# The %(here)s variable will be replaced with the parent directory of this file
5
#
6
[DEFAULT]
7
# WARGING == If debug is not set to false, you'll get the interactive
8
# debugger on production, which is a huge security hole. 
9

  
10
debug = false
11
email_to = you@yourdomain.com
12
smtp_server = localhost
13
error_email_from = paste@localhost
14

  
15
[server:main]
16
use = egg:Paste#http
17
host = 0.0.0.0
18
port = 8080
19

  
20
[app:main]
21
use = egg:vigiboard
22
full_stack = true
23
cache_dir = %(here)s/data
24
beaker.session.key = vigiboard
25
beaker.session.secret = ${app_instance_secret}
26
app_instance_uuid = ${app_instance_uuid}
27

  
28
# If you'd like to fine-tune the individual locations of the cache data dirs
29
# for the Cache data, or the Session saves, un-comment the desired settings
30
# here:
31
#beaker.cache.data_dir = %(here)s/data/cache
32
#beaker.session.data_dir = %(here)s/data/sessions
33
# Specify the database for SQLAlchemy to use via
34
# turbogears.database
35
# %(here) may include a ':' character on Windows environments; this can
36
# invalidate the URI when specifying a SQLite db via path name
37
sqlalchemy.url = sqlite:///%(here)s/somedb.db
38
sqlalchemy.echo = False
39

  
40
# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
41
# Debug mode will enable the interactive debugging tool, allowing ANYONE to
42
# execute malicious code after an exception is raised.
43
#set debug = false
44

  
45
# Logging configuration
46
# Add additional loggers, handlers, formatters here
47
# Uses python's logging config file format
48
# http://docs.python.org/lib/logging-config-fileformat.html
49

  
50
[loggers]
51
keys = root, vigiboard, sqlalchemy, auth
52

  
53
[handlers]
54
keys = console
55

  
56
[formatters]
57
keys = generic
58

  
59
# If you create additional loggers, add them as a key to [loggers]
60
[logger_root]
61
level = INFO
62
handlers = console
63

  
64
[logger_vigiboard]
65
level = INFO
66
handlers =
67
qualname = vigiboard
68

  
69
[logger_sqlalchemy]
70
level = WARN
71
handlers =
72
qualname = sqlalchemy.engine
73
# "level = INFO" logs SQL queries.
74
# "level = DEBUG" logs SQL queries and results.
75
# "level = WARN" logs neither.  (Recommended for production systems.)
76

  
77

  
78
# A logger for authentication, identification and authorization -- this is
79
# repoze.who and repoze.what:
80
[logger_auth]
81
level = WARN
82
handlers = 
83
qualname = auth
84

  
85
# If you create additional handlers, add them as a key to [handlers]
86
[handler_console]
87
class = StreamHandler
88
args = (sys.stderr,)
89
level = NOTSET
90
formatter = generic
91

  
92
# If you create additional formatters, add them as a key to [formatters]
93
[formatter_generic]
94
format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
95
datefmt = %H:%M:%S
vigiboard/config/environment.py
1
# -*- coding: utf-8 -*-
2
"""WSGI environment setup for vigiboard."""
3

  
4
from vigiboard.config.app_cfg import base_config
5

  
6
__all__ = ['load_environment']
7

  
8
#Use base_config to setup the environment loader function
9
load_environment = base_config.make_load_environment()
vigiboard/config/middleware.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4:
3

  
4
"""WSGI middleware initialization for the vigiboard application."""
5

  
6
from vigiboard.config.app_cfg import base_config
7
from vigiboard.config.environment import load_environment
8
from vigiboard.config.vigilo_conf import vigilo_mods
9

  
10
__all__ = ['make_app']
11

  
12
# Use base_config to setup the necessary PasteDeploy application factory. 
13
# make_base_app will wrap the TG2 app with all the middleware it needs. 
14
make_base_app = base_config.setup_tg_wsgi_app(load_environment)
15

  
16

  
17
def make_app(global_conf, full_stack=True, **app_conf):
18
    """
19
    Set vigiboard up with the settings found in the PasteDeploy configuration
20
    file used.
21
    
22
    :param global_conf: The global settings for vigiboard (those
23
        defined under the ``[DEFAULT]`` section).
24
    :type global_conf: dict
25
    :param full_stack: Should the whole TG2 stack be set up?
26
    :type full_stack: str or bool
27
    :return: The vigiboard application with all the relevant middleware
28
        loaded.
29
    
30
    This is the PasteDeploy factory for the vigiboard application.
31
    
32
    ``app_conf`` contains all the application-specific settings (those defined
33
    under ``[app:main]``.
34
    
35
   
36
    """
37

  
38
    # Petit hack permettant d'importer la configuration de vigiboard
39

  
40
    for mod in vigilo_mods :
41
        myconf = __import__(
42
            'vigiboard.config.vigilo_conf.' + mod ,globals(), locals(), [mod + '_config'],-1)
43
        myconf = getattr(myconf,mod + '_config')
44
        for conf in myconf:
45
            app_conf[conf] = myconf[conf]
46

  
47
    app_conf['vigilo_mods'] = vigilo_mods
48

  
49
    app = make_base_app(global_conf, full_stack=True, **app_conf)
50
    
51
    # Wrap your base TurboGears 2 application with custom middleware here
52
    
53
    return app
vigiboard/config/vigilo_conf/__init__.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4:
3

  
4
vigilo_mods = [
5
                    'vigicore',
6
		            'vigiboard'
7
	          ]
vigiboard/config/vigilo_conf/vigiboard.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4:
3
"""Configuration de Vigiboard."""
4

  
5
vigiboard_config = {
6
    
7
    # Affichage, lien disponibles dans la fenêtre de détail d'un évènement
8
    'vigiboard_links.nagios' : 'http://example1.com/%(idevent)d',
9
    'vigiboard_links.metrology' : 'http://example2.com/%(idevent)d',
10
    'vigiboard_links.security' : 'http://example3.com/%(idevent)d',
11
    'vigiboard_links.servicetype' : 'http://example4.com/%(idevent)d',
12
    
13
    # Nombre d'évènments par pages
14
    'vigiboard_item_per_page' : '15',
15

  
16
    'vigiboard_plugins' : [
17
        [ 'shn' , 'PluginSHN' ]
18
        ]
19

  
20
}
21

  
vigiboard/config/vigilo_conf/vigicore.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4:
3
"""Configuration de VigiCore."""
4

  
5
vigicore_config = {
6
        'vigicore_bdd.basename' : ''
7
}
vigiboard/controllers/__init__.py
1
# -*- coding: utf-8 -*-
2
"""Controllers for the vigiboard application."""
vigiboard/controllers/controller.template
1
# -*- coding: utf-8 -*-
2
"""Sample controller module"""
3

  
4
# turbogears imports
5
from tg import expose
6
#from tg import redirect, validate, flash
7

  
8
# third party imports
9
#from pylons.i18n import ugettext as _
10
#from repoze.what import predicates
11

  
12
# project specific imports
13
from vigiboard.lib.base import BaseController
14
#from vigiboard.model import DBSession, metadata
15

  
16

  
17
class SampleController(BaseController):
18
    #Uncomment this line if your controller requires an authenticated user
19
    #allow_only = authorize.not_anonymous()
20
    
21
    @expose('vigiboard.templates.index')
22
    def index(self):
23
        return dict(page='index')
vigiboard/controllers/error.py
1
# -*- coding: utf-8 -*-
2
"""Error controller"""
3

  
4
from tg import request, expose
5

  
6
__all__ = ['ErrorController']
7

  
8

  
9
class ErrorController(object):
10
    """
11
    Generates error documents as and when they are required.
12

  
13
    The ErrorDocuments middleware forwards to ErrorController when error
14
    related status codes are returned from the application.
15

  
16
    This behaviour can be altered by changing the parameters to the
17
    ErrorDocuments middleware in your config/middleware.py file.
18
    
19
    """
20

  
21
    @expose('vigiboard.templates.error')
22
    def document(self, *args, **kwargs):
23
        """Render the error document"""
24
        resp = request.environ.get('pylons.original_response')
25
        default_message = ("<p>We're sorry but we weren't able to process "
26
                           " this request.</p>")
27
        values = dict(prefix=request.environ.get('SCRIPT_NAME', ''),
28
                      code=request.params.get('code', resp.status_int),
29
                      message=request.params.get('message', default_message))
30
        return values
vigiboard/controllers/root.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""Main Controller"""
4

  
5
from tg import expose, flash, require, url, request, redirect, config
6

  
7
from pylons.i18n import ugettext as _, lazy_ugettext as l_
8
from catwalk.tg2 import Catwalk
9
from repoze.what import predicates
10

  
11
from vigiboard.lib.base import BaseController
12
from vigiboard.model import DBSession 
13
from vigiboard.controllers.error import ErrorController
14
from vigiboard import model
15
from vigiboard.controllers.secure import SecureController
16

  
17
__all__ = ['RootController']
18

  
19
class RootController(BaseController):
20
    """
21
    The root controller for the vigiboard application.
22
    
23
    All the other controllers and WSGI applications should be mounted on this
24
    controller. For example::
25
    
26
        panel = ControlPanelController()
27
        another_app = AnotherWSGIApplication()
28
    
29
    Keep in mind that WSGI applications shouldn't be mounted directly: They
30
    must be wrapped around with :class:`tg.controllers.WSGIAppController`.
31
    
32
    """
33
    secc = SecureController()
34
    
35
    admin = Catwalk(model, DBSession)
36
    
37
    error = ErrorController()
38

  
39
    # on charge les controleurs souhaité en dynamique
40
    def __init__(self) :
41
        super(RootController,self).__init__()
42
        
43
        for mod in config['vigilo_mods']:
44
            try :
45
                mymod = __import__(
46
                    'vigiboard.controllers.' + mod + '_ctl',globals(), locals(), [mod + 'Controller'],-1)
47
                setattr(self,mod,getattr(mymod,mod + 'Controller')())
48
            except:
49
                pass
50

  
51
    @expose('vigiboard.templates.index')
52
    def index(self):
53
        """Handle the front-page."""
54
        return dict(page='index')
55

  
56
    @expose('vigiboard.templates.about')
57
    def about(self):
58
        """Handle the 'about' page."""
59
        return dict(page='about')
60

  
61
    @expose('vigiboard.templates.authentication')
62
    def auth(self):
63
        """Display some information about auth* on this application."""
64
        return dict(page='auth')
65

  
66
    @expose('vigiboard.templates.index')
67
    @require(predicates.has_permission('manage', msg=l_('Only for managers')))
68
    def manage_permission_only(self, **kw):
69
        """Illustrate how a page for managers only works."""
70
        return dict(page='managers stuff')
71

  
72
    @expose('vigiboard.templates.index')
73
    @require(predicates.is_user('editor', msg=l_('Only for the editor')))
74
    def editor_user_only(self, **kw):
75
        """Illustrate how a page exclusive for the editor works."""
76
        return dict(page='editor stuff')
77

  
78
    @expose('vigiboard.templates.login')
79
    def login(self, came_from=url('/')):
80
        """Start the user login."""
81
        login_counter = request.environ['repoze.who.logins']
82
        if login_counter > 0:
83
            flash(_('Wrong credentials'), 'warning')
84
        return dict(page='login', login_counter=str(login_counter),
85
                    came_from=came_from)
86
    
87
    @expose()
88
    def post_login(self, came_from=url('/')):
89
        """
90
        Redirect the user to the initially requested page on successful
91
        authentication or redirect her back to the login page if login failed.
92
        
93
        """
94
        if not request.identity:
95
            login_counter = request.environ['repoze.who.logins'] + 1
96
            redirect(url('/login', came_from=came_from, __logins=login_counter))
97
        userid = request.identity['repoze.who.userid']
98
        flash(_('Welcome back, %s!') % userid)
99
        redirect(came_from)
100

  
101
    @expose()
102
    def post_logout(self, came_from=url('/')):
103
        """
104
        Redirect the user to the initially requested page on logout and say
105
        goodbye as well.
106
        
107
        """
108
        flash(_('We hope to see you soon!'))
109
        redirect(came_from)
vigiboard/controllers/secure.py
1
# -*- coding: utf-8 -*-
2
"""Sample controller with all its actions protected."""
3
from tg import expose, flash
4
from pylons.i18n import ugettext as _, lazy_ugettext as l_
5
from repoze.what.predicates import has_permission
6
#from dbsprockets.dbmechanic.frameworks.tg2 import DBMechanic
7
#from dbsprockets.saprovider import SAProvider
8

  
9
from vigiboard.lib.base import BaseController
10
#from vigiboard.model import DBSession, metadata
11

  
12
__all__ = ['SecureController']
13

  
14

  
15
class SecureController(BaseController):
16
    """Sample controller-wide authorization"""
17
    
18
    # The predicate that must be met for all the actions in this controller:
19
    allow_only = has_permission('manage',
20
                                msg=l_('Only for people with the "manage" permission'))
21
    
22
    @expose('vigiboard.templates.index')
23
    def index(self):
24
        """Let the user know that's visiting a protected controller."""
25
        flash(_("Secure Controller here"))
26
        return dict(page='index')
27
    
28
    @expose('vigiboard.templates.index')
29
    def some_where(self):
30
        """Let the user know that this action is protected too."""
31
        return dict(page='some_where')
vigiboard/controllers/template.py
1
# -*- coding: utf-8 -*-
2
"""Fallback controller."""
3

  
4
from vigiboard.lib.base import BaseController
5

  
6
__all__ = ['TemplateController']
7

  
8

  
9
class TemplateController(BaseController):
10
    """
11
    The fallback controller for vigiboard.
12
    
13
    By default, the final controller tried to fulfill the request
14
    when no other routes match. It may be used to display a template
15
    when all else fails, e.g.::
16
    
17
        def view(self, url):
18
            return render('/%s' % url)
19
    
20
    Or if you're using Mako and want to explicitly send a 404 (Not
21
    Found) response code when the requested template doesn't exist::
22
    
23
        import mako.exceptions
24
        
25
        def view(self, url):
26
            try:
27
                return render('/%s' % url)
28
            except mako.exceptions.TopLevelLookupException:
29
                abort(404)
30
    
31
    """
32
    
33
    def view(self, url):
34
        """Abort the request with a 404 HTTP status code."""
35
        abort(404)
vigiboard/controllers/userutils.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4:
3
"""Fonctions utiles en rapport avec l'utilisateur"""
4

  
5
from vigiboard.model import DBSession, Permission, Groups, GroupPermissions
6
from sets import Set
7
import tg 
8

  
9
def get_user_groups():
10
    
11
    """
12
    Permet de connaître l'ensemble des groups d'hôte et de service de vigiboard
13
    auquel l'utilisateur appartient
14

  
15
    @return: Liste des groups
16
    """
17

  
18
    # Requête permettant d'obtenir les groups directs de l'utilisateur
19

  
20
    groups = DBSession.query(Groups.name).join(
21
        ( GroupPermissions , Groups.name == GroupPermissions.groupname ),
22
        ( Permission ,
23
            Permission.permission_id == GroupPermissions.idpermission )
24
        ).filter(Permission.permission_name.in_(
25
            tg.request.environ.get('repoze.who.identity').get('permissions')
26
        ))
27
    
28
    lst_grp = Set([i.name for i in groups])
29
    lst_tmp = lst_grp
30
    
31
    # On recherche maintenant les groupes indirect
32
    
33
    while len(lst_tmp) > 0:
34
        groups = DBSession.query(Groups.name).filter(Groups.parent.in_(lst_tmp))
35
        tmp = Set([])
36
        for i in groups :
37
            tmp.add(i.name)
38
            lst_grp.add(i.name)
39
        lst_tmp = tmp
40

  
41
    return lst_grp
vigiboard/controllers/vigiboard_ctl/__init__.py
1
"""
2
Module contenant le controller ainsi que la classe
3
permettant l'affichage du Vigiboard
4
"""
5

  
6
from vigiboard.controllers.vigiboard_ctl.vigiboardrequest import \
7
		VigiboardRequest
8
from vigiboard.controllers.vigiboard_ctl.vigiboard_ctl import \
9
		vigiboardController
vigiboard/controllers/vigiboard_ctl/vigiboard_ctl.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""Vigiboard Controller"""
4

  
5
import tg
6

  
7
from tg import expose, flash, require, request, redirect, \
8
                validate, tmpl_context
9

  
10
from tw.forms import validators 
11

  
12
from pylons.i18n import ugettext as _
13

  
14
from sqlalchemy import sql, asc
15

  
16
from vigiboard.lib.base import TGController
17
from vigiboard.model import DBSession
18

  
19
from vigiboard.model import ServiceHautNiveau, HostGroups, \
20
        Events, EventHistory
21

  
22
from repoze.what.predicates import Any, not_anonymous
23

  
24
from vigiboard.widgets.edit_event import edit_event_status_options
25

  
26
from vigiboard.controllers.userutils import get_user_groups
27
from vigiboard.controllers.vigiboard_ctl.vigiboardrequest import \
28
        VigiboardRequest
29

  
30
__all__ = ['VigiboardController']
31

  
32
class vigiboardController(TGController):
33
    
34
    """
35
    Le controller général de vigiboard
36
    """
37

  
38
    @expose()
39
    def process_form_errors (self, *argv, **kwargv):
40

  
41
        """
42
        Gestion des erreurs de validation : On affiche les erreurs
43
        puis on redirige vers la dernière page accédée.
44
        """
45
        flash(tmpl_context.form_errors, 'error')
46
        if request.environ.get('HTTP_REFERER') :
47
            redirect(request.environ.get('HTTP_REFERER'
48
                ).split(request.environ.get('HTTP_HOST'))[1])
49
        else :
50
            redirect('/')
51

  
52
    @validate(validators={'page':validators.Int(not_empty=False)},
53
            error_handler=process_form_errors)
54
    @expose('vigiboard.templates.vigiboard')
55
    @require(Any(not_anonymous(), msg="You need to be authenticated"))
56
    def default(self, page = 1, host = None, service = None, output = None,
57
            trouble_ticket=None):
58
            
59
        """
60
        Page d'accueil de Vigiboard. Elle affiche, suivant la page demandée (page 1 par
61
        defaut), la liste des évènements, rangé par ordre de prise en compte puis de sévérité.
62
        Pour accéder à cette page, l'utilisateur doit être authentifié.
63

  
64
        @param page: numéro de la page souhaité, commence à 1
65
        @param host: Si l'utilisateur souhaite sélectionner seulement certains
66
                     évènments suivant leur hôte, il peut placer une expression
67
                     ici en suivant la structure du LIKE en SQL
68
        @param service: Idem que host mais sur les services
69
        @param output: Idem que host mais sur le text explicatif
70
        @param trouble_ticket: Idem que host mais sur les tickets attribués
71
        """
72

  
73
        if page < 1 :
74
            page = 1
75

  
76
        events = VigiboardRequest()
77

  
78
        # Application des filtres si nécessaire
79
        if host :
80
            events.add_filter(Events.hostname.like('%%%s%%' % host))
81
        if service :
82
            events.add_filter(Events.servicename.like('%%%s%%' % service))
83
        if output :
84
            events.add_filter(Events.output.like('%%%s%%' % output))
85
        if trouble_ticket :
86
            events.add_filter(Events.trouble_ticket.like(
87
                '%%%s%%' % trouble_ticket))
88

  
89
        # Calcul des éléments à afficher et du nombre de pages possibles
90
        total_row = events.num_rows()
91
       
92
        item_per_page = int(tg.config['vigiboard_item_per_page'])
93

  
94
        if total_row <= item_per_page * (page-1) :
95
            page = 1
96
        id_first_row = item_per_page * (page-1)
97
        id_last_row = min(id_first_row + item_per_page, total_row)
98

  
99
        events.format_events(id_first_row, id_last_row)
100
        events.generate_tmpl_context() 
101

  
102
        return dict(
103
               events = events.events,
104
               id_first_row = id_first_row + 1,
105
               id_last_row = id_last_row,
106
               total_row = total_row,
107
               pages = range(1, (total_row / item_per_page) + 2),
108
               page = page,
109
               event_edit_status_options = edit_event_status_options,
110
               history = [],
111
               hist_error = False
112
            )
113
       
114
    @validate(validators={'idevent':validators.Int(not_empty=True)},
115
            error_handler=process_form_errors)
116
    @expose('json')
117
    @require(Any(not_anonymous(), msg=_("You need to be authenticated")))
118
    def history_dialog (self, idevent) :
119
        
120
        """
121
        JSon renvoyant les éléments pour l'affichage de la fenêtre de dialogue
122
        contenant des liens internes et externes.
123
        Pour accéder à cette page, l'utilisateur doit être authentifié.
124

  
125
        @param id: identifiant de l'évènement
126
        """
127
        
128
        # Obtention de données sur l'évènement et sur son historique
129
        events = DBSession.query(Events.severity, Events.idevent,
130
                        Events.hostname, Events.servicename
131
                 ).join(( HostGroups , Events.hostname == HostGroups.hostname )
132
                 ).filter(HostGroups.groupname.in_(get_user_groups())
133
                 ).filter(Events.idevent == idevent)[0]
134

  
135
        initial_state = DBSession.query(EventHistory
136
                 ).filter(EventHistory.idevent == idevent
137
                 ).order_by(asc(EventHistory.timestamp)
138
                 ).order_by(asc(EventHistory.type_action))
139

  
140
        if initial_state.count() > 0 :
141
            initial_state = initial_state[0].value
142
        else :
143
            initial_state = 0
144
        
145
        severity = { 0: _('None'), 1: _('OK'), 2: _('Suppressed'),
146
                3: _('Initial'), 4: _('Maintenance'), 5: _('Minor'),
147
                6: _('Major'), 7: _('Critical') }
148
        
149
        return dict(
150
                initial_state = severity[int(initial_state)],
151
                current_state = severity[events.severity],
152
                idevent = events.idevent,
153
                host = events.hostname,
154
                service = events.servicename,
155
                nagios_link = tg.config['vigiboard_links.nagios'] % \
156
                        {'idevent': events.idevent},
157
                metrology_link = tg.config['vigiboard_links.metrology'] % \
158
                        {'idevent': events.idevent},
159
                security_link = tg.config['vigiboard_links.security'] % \
160
                        {'idevent': events.idevent},
161
                servicetype_link = tg.config['vigiboard_links.servicetype'] % \
162
                        {'idevent': events.idevent}
163
            )
164

  
165
    @validate(validators={'idevent':validators.Int(not_empty=True)},
166
            error_handler=process_form_errors)
167
    @expose('vigiboard.templates.vigiboard')
168
    @require(Any(not_anonymous(), msg=_("You need to be authenticated")))
169
    def event(self, idevent):
170
        """
171
        Affichage de l'historique d'un évènement.
172
        Pour accéder à cette page, l'utilisateur doit être authentifié.
173

  
174
        @param idevent: identifiant de l'évènement souhaité
175
        """
176

  
177
        events = VigiboardRequest()
178
        events.add_filter(Events.idevent == idevent)
179
        
180
        # Vérification que l'évènement existe
181
        if events.num_rows() != 1 :
182
            flash(_('Error in DB'), 'error')
183
            redirect('/')
184
       
185
        events.format_events(0, 1)
186
        events.format_history()
187
        events.generate_tmpl_context() 
188

  
189
        return dict(
190
               events = events.events,
191
               id_first_row = 1,
192
               id_last_row = 1,
193
               total_row = 1,
194
               pages = [1],
195
               page = 1,
196
               event_edit_status_options = edit_event_status_options,
197
               history = events.hist,
198
               hist_error = True
199
            )
200

  
201
    @validate(validators={'host':validators.NotEmpty(),
202
        'service':validators.NotEmpty()}, error_handler=process_form_errors)
203
    @expose('vigiboard.templates.vigiboard')
204
    @require(Any(not_anonymous(), msg=_("You need to be authenticated")))
205
    def host_service(self, host, service):
206
        
207
        """
208
        Affichage de l'historique de l'ensemble des évènements correspondant au
209
        host et service demandé.
210
        Pour accéder à cette page, l'utilisateur doit être authentifié.
211

  
212
        @param host: Nom de l'hôte souhaité.
213
        @param service: Nom du service souhaité
214
        """
215

  
216
        events = VigiboardRequest()
217
        events.add_filter(Events.hostname == host,
218
                Events.servicename == service)
219
        
220
        # Vérification qu'il y a au moins 1 évènement qui correspond
221
        if events.num_rows() == 0 :
222
            redirect('/')
223
       
224
        events.format_events(0, events.num_rows())
225
        events.format_history()
226
        events.generate_tmpl_context() 
227

  
228
        return dict(
229
               events = events.events,
230
               id_first_row = 1,
231
               id_last_row = 1,
232
               total_row = 1,
233
               pages = [1],
234
               page = 1,
235
               event_edit_status_options = edit_event_status_options,
236
               history = events.hist,
237
               hist_error = True
238
            )
239

  
240
    @validate(validators={
241
        "id":validators.Regex(r'^[0-9]+(,[0-9]*)*,?$'),
242
        "trouble_ticket":validators.Regex(r'^[0-9]*$'),
243
        "status":validators.OneOf(['NoChange', 'None', 'Acknowledged',
244
                'AAClosed'])
245
        }, error_handler=process_form_errors)
246
    @require(Any(not_anonymous(), msg=_("You need to be authenticated")))
247
    def update(self,**krgv):
248
        
249
        """
250
        Mise à jour d'un évènement suivant les arguments passés.
251
        Cela peut être un changement de ticket ou un changement de statu.
252
        
253
        @param krgv['id']: Le ou les identifiants des évènements à traiter
254
        @param krgv['tt']: Nouveau numéro du ticket associé.
255
        @param krgv['status']: Nouveau status de/des évènements.
256
        """
257
        
258
        # Si l'utilisateur édite plusieurs évènements à la fois,
259
        # il nous faut chacun des identifiants
260

  
261
        ids = krgv['id'].split(',')
262
       
263
        if len(ids) > 1 :
264
            ids = ids[:-1]
265
        
266
        events = VigiboardRequest()
267
        events.add_filter(Events.idevent.in_(ids))
268
        
269
        # Vérification que au moins un des identifiants existe et est éditable
270
        if events.num_rows() <= 0 :
271
            flash(_('No access to this event'), 'error')
272
            redirect('/')
273
        
274
        # Modification des évènements et création d'un historique
275
        # pour chacun d'eux
276
        
277
        username = request.environ.get('repoze.who.identity'
278
                ).get('repoze.who.userid')
279

  
280
        for req in events.req :
281
            if isinstance(req,Events):
282
                event = req
283
            else:
284
                event = req[0]
285
            if krgv['trouble_ticket'] != '' :
286
                event.trouble_ticket = krgv['trouble_ticket']
287
                history = EventHistory(type_action = "Ticket change",
288
                    idevent = event.idevent, value = '', text = '',
289
                    username = username)
290
                DBSession.add(history)   
291
            if krgv['status'] != 'NoChange' :
292
                event.status = krgv['status']
293
                history = EventHistory(
294
                        type_action = "Acknowlegement change state",
295
                        idevent = event.idevent, value = '', text = '',
296
                        username = username)
297
                DBSession.add(history)
298
       
299
        flash(_('Updated successfully'))
300
	# Redirection vers la dernière page accédée
301
        redirect(request.environ.get('HTTP_REFERER').split(
302
            request.environ.get('HTTP_HOST')+tg.config['base_url_filter.base_url'])[1])
303

  
vigiboard/controllers/vigiboard_ctl/vigiboard_plugin/__init__.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3

  
4
class VigiboardRequestPlugin(object):
5

  
6
    """
7
    Classe dont les plugins utilisé dans VigiboardRequest doivent étendre.
8
    """
9

  
10
    def __init__ (self, table = None, join = None, outerjoin = None,
11
            filters = None, groupby = None, orderby = None, name = '',
12
            style = None):
13

  
14
        self.table = table
15
        self.join = join
16
        self.outerjoin = outerjoin
17
        self.filter = filters
18
        self.orderby = orderby
19
        self.name = name
20
        self.groupby = groupby
21
        self.style = style
22

  
23
    def __show__ (self, event):
24

  
25
        """
26
        Permet d'éviter toutes erreurs d'affichage.
27
        C'est la fonction appelé par le formateur d'évènements.
28
        """
29

  
30
        show = self.show(event)
31

  
32
        if show != None :
33
            try:
34
                return str(show)
35
            except:
36
                return _('Error')
37

  
38
    def show(self, event):
39

  
40
        """
41
        Fonction qui affichera par défaut une chaîne de
42
        caractères vide dans la colonne attribué au plugin.
43

  
44
        En général, les plugins devront redéfinir cette fonction
45
        pour afficher ce qu'ils souhaitent.
46
        """
47

  
48
        return ''
49

  
vigiboard/controllers/vigiboard_ctl/vigiboard_plugin/shn.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3

  
4
from vigiboard.controllers.vigiboard_ctl.vigiboard_plugin import \
5
        VigiboardRequestPlugin
6
from vigiboard.model import ServiceHautNiveau, Events
7
from sqlalchemy import sql, asc
8
from pylons.i18n import ugettext as _
9

  
10
class PluginSHN (VigiboardRequestPlugin):
11

  
12
    """
13
    Plugin permettant de rajouter le nombre de SHNs impactés à
14
    l'affichage
15
    """
16

  
17
    def __init__(self):
18
        super(PluginSHN,self).__init__(
19
            table = [ServiceHautNiveau.servicename_dep,
20
                sql.func.count(Events.idevent)],
21
            outerjoin = [(ServiceHautNiveau,
22
                ServiceHautNiveau.servicename_dep == Events.servicename)],
23
            groupby = [(Events),(ServiceHautNiveau.servicename_dep)],
24
            name = _(u'SHNs impacté'),
25
            style = {'style':'text-align:center'}
26
        )
27
    
28
    def show(self, req):
29
        """Fonction d'affichage"""
30
        if req[1] :
31
            return req[2]
32
        else :
33
            return None
vigiboard/controllers/vigiboard_ctl/vigiboard_plugin/tests.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3

  
4
from vigiboard.controllers.vigiboard_ctl.vigiboard_plugin import \
5
	        VigiboardRequestPlugin
6
from vigiboard.model import EventHistory, Events
7

  
8
class MonPlugin(VigiboardRequestPlugin):
9
    """Plugin de test"""
10
    
11
    def __init__(self):
12
        super(PluginSHN,self).__init__(
13
            table = [EventHistory.idevent],
14
            join = [(EventHistory, EventHistory.idevent == Events.idevent)]
15
        )
16

  
17
    def show(self, req):
18
	"""Fonction d'affichage"""
19
	return req[1]
20

  
vigiboard/controllers/vigiboard_ctl/vigiboardrequest.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""Gestion de la requête, des plugins et de l'affichage du Vigiboard"""
4

  
5
from vigiboard.model import Events, Host, Service, \
6
        HostGroups, ServiceGroups, EventHistory
7
from tg import tmpl_context, url, config
8
from vigiboard.model import DBSession
9
from sqlalchemy import not_ , and_ , asc , desc
10
from tw.jquery import JQueryUIDialog
11
from vigiboard.widgets.edit_event import EditEventForm , SearchForm
12
from vigiboard.controllers.userutils import get_user_groups
13
from vigiboard.controllers.vigiboard_ctl.vigiboard_plugin import VigiboardRequestPlugin
14
from pylons.i18n import ugettext as _
15

  
16
class VigiboardRequest():
17
    
18
    """
19
    Classe gérant la génération de la requête finale,
20
    le préformatage des évènements et celui des historiques
21
    """
22

  
23
    def __init__(self):
24

  
25
        """
26
        Initialisation de toutes les variables nécessaires: Liste des groupes de
27
        l'utilisateur, les classes à appliquer suivant la sévérité, les
28
        différentes étapes de la génération de la requête et la liste des
29
        plugins appliqués.
30
        """
31

  
32
        self.user_groups = get_user_groups()
33
        self.bouton_severity = { 0: 'Minor', 1: 'Minor', 2: 'Minor',
34
                3: 'Minor', 4: 'Minor', 5: 'Minor', 6: 'Major', 7: 'Critical' }
35
        self.class_severity = { 0: 'None', 1: 'None', 2: 'None', 3: 'None',
36
                4: 'None', 5: 'Minor', 6: 'Major', 7: 'Critical' }
37
        self.severity = { 0: _('None'), 1: _('OK'), 2: _('Suppressed'),
38
                3: _('Initial'), 4: _('Maintenance'), 5: _('Minor'),
39
                6: _('Major'), 7: _('Critical') }
40

  
41
        self.class_ack = {'Acknowledged': 'Ack', 'None': '', 'AAClosed': 'Ack'}
42

  
43
        self.generaterq = False
44
        self.table = [Events]
45
        self.join = [( Host, Events.hostname == Host.name ),
46
                ( Service, Events.servicename == Service.name ),
47
                ( HostGroups , Host.name == HostGroups.hostname ),
48
                ( ServiceGroups , Service.name == ServiceGroups.servicename )
49
                ]
50
        self.outerjoin = []
51
        self.filter = [HostGroups.groupname.in_(self.user_groups),
52
                 ServiceGroups.groupname.in_(self.user_groups),
53
                 not_(and_(Events.active == False,
54
                     Events.status == 'AAClosed')),
55
                 Events.timestamp_active != None#,
56
                 #not_(Events.timestamp_active.like('0000-00-00 00:00:00'))
57
                 ]
58
        self.orderby = [desc(Events.status),
59
                                desc(Events.active),
60
                                desc(Events.severity),
61
                                asc(Events.hostname),
62
                                desc(Events.timestamp)]
63
        self.groupby = []
64
        self.plugin = []
65
        self.events = []
66
        self.idevents = []
67
        self.hist = []
68
        self.req = DBSession
69

  
70
    def add_plugin(self, *argv):
71
        
72
        """
73
        Ajout d'un plugin, on lui prélève ses ajouts dans la requête
74
        """
75
        for i in argv :
76
            if isinstance(i, VigiboardRequestPlugin):
77
                if i.table :
78
                    self.add_table(*i.table)
79
                if i.join :
80
                    self.add_join(*i.join)
81
                if i.outerjoin :
82
                    self.add_outer_join(*i.outerjoin)
83
                if i.filter :
84
                    self.add_filter(*i.filter)
85
                if i.groupby :    
86
                    self.add_group_by(*i.groupby)
87
                if i.orderby :
88
                    self.add_order_by(*i.orderby)
89
                self.plugin.append(i)
90

  
91
    def generate_request(self):
92
        
93
        """
94
        Génération de la requête avec l'ensemble des données stockées
95
        et la place dans la variable rq de la classe
96
        """
97
        for plug in config['vigiboard_plugins']:
98
            try:
99
                mypac = __import__(
100
                    'vigiboard.controllers.vigiboard_ctl.vigiboard_plugin.' +\
101
                            plug[0],globals(), locals(), [plug[1]],-1)
102
                self.add_plugin(getattr(mypac,plug[1])())
103
            except:
104
                raise
105
        
106
        # query et join ont besoin de referrence
107
        self.req = self.req.query(*self.table)
108
        self.req = self.req.join(*self.join)
109

  
110
        # le reste, non
111
        for i in self.outerjoin:
112
            self.req = self.req.outerjoin(i)
113
        for i in self.filter:
114
            self.req = self.req.filter(i)
115
        for i in self.groupby:
116
            self.req = self.req.group_by(i)
117
        for i in self.orderby:
118
            self.req = self.req.order_by(i)
119

  
120
    def num_rows(self):
121

  
122
        """
123
        Retourne le nombre de lignes de la requête.
124
        Si celle-ci n'est pas encore générée, on le fait.
125

  
126
        @return: Nombre de ligne
127
        """
128

  
129
        if not self.generaterq :
130
            self.generate_request()
131
            self.generaterq = True
132
        return self.req.count()
133

  
134
    def add_table(self, *argv):
135
        
136
        """
137
        Ajoute une ou plusieurs tables/élément d'une table à
138
        la requête.
139

  
140
        @param argv: Liste des tables à ajouter
141
        """
142
        
143
        #On vérifi qu'il n'y a pas de doublons dans la liste des
144
        #tables finale
145
        
146
        for i in argv :
147
            for j in self.table:
148
                if str(i) == str(j):
149
                    break
150
            self.table.append(i)
151

  
152
    def add_join(self, *argv):
153
        
154
        """
155
        Ajoute une ou plusieurs jointures à
156
        la requête.
157

  
158
        @param argv: Liste des jointures à ajouter
159
        """
160
        
161
        #On vérifi qu'il n'y a pas de doublons dans la liste des
162
        #jointures finale
163
        
164
        for i in argv:
165
            for j in self.join:
166
                if str(i) == str(j):
167
                    break
168
            self.join.append(i)
169

  
170
    def add_outer_join(self, *argv):
171
        
172
        """
173
        Ajoute une ou plusieurs jointures externes à
174
        la requête.
175

  
176
        @param argv: Liste des jointures externes à ajouter
177
        """
178
        
179
        #On vérifi qu'il n'y a pas de doublons dans la liste des
180
        #jointures externes finale
181
        
182
        for i in argv:
183
            for j in self.outerjoin:
184
                if str(i) == str(j):
185
                    break
186
            self.outerjoin.append(i)    
187

  
188
    def add_filter(self, *argv):
189

  
190
        """
191
        Ajoute un ou plusieurs filtres à la requête.
192

  
193
        @param argv: Liste des filtres à ajouter
194
        """
195
        
196
        #On vérifi qu'il n'y a pas de doublons dans la liste des
197
        #filtres finale
198
        
199
        for i in argv:
200
            for j in self.filter:
201
                if str(i) == str(j):
202
                    break
203
            self.filter.append(i)
204

  
205
    def add_group_by(self, *argv):
206

  
207
        """
208
        Ajoute un ou plusieurs groupements à la requête.
209

  
210
        @param argv: Liste des groupements à ajouter
211
        """
212
        
213
        #On vérifi qu'il n'y a pas de doublons dans la liste des
214
        #groupements finale
215
        
216
        for i in argv:
217
            for j in self.groupby:
218
                if str(i) == str(j):
219
                    break
220
            self.groupby.append(i)
221

  
222
    def add_order_by(self, *argv):
223

  
224
        """
225
        Ajoute un ou plusieurs orders à la requête.
226

  
227
        @param argv: Liste des ordres à ajouter
228
        """
229
        
230
        #On vérifi qu'il n'y a pas de doublons dans la liste des
231
        #ordres finale
232
        
233
        for i in argv:
234
            for j in self.orderby:
235
                if str(i) == str(j):
236
                    break
237
            self.orderby.append(i)
238

  
239
    def format_events_img_statu (self, event):
240
        
241
        """
242
        Suivant l'état de l'évènement, retourne la classe à appliquer
243
        à l'image indiquant si l'évènement est pris en compte ou non.
244

  
245
        @param event: l'évènement à analyser
246

  
247
        @return: Dictionnaire représentant la classe à appliquer
248
        """
249

  
250
        if event.active and event.status == 'AAClosed':
251
            return { 'src': url('/images/crossed.png') }
252
        elif event.status == 'Acknowledged' :
253
            return { 'src': url('/images/checked.png') }
254
        else:
255
            return None
256

  
257
    def format_events(self, first_row, last_row):
258
        
259
        """
260
        Formate la réponse de la requête et y applique les plugins
261
        pour un affichage simple du résultat par Genshi.
262
        On génère une liste de liste, chaqu'une étant la description de
263
        l'affichage pour un évènement donné.
264

  
265
        @param first_row: Indice de début de la liste des évènements
266
        @param last_row: Indice de fin de la liste des évènements
267
        """
268
        
269
        # Si la requête n'est pas générée, on le fait
270
        if not self.generaterq :
271
            self.generate_request()
272
            self.generaterq = True
273

  
274
        # Liste des éléments pour la tête du tableau
275

  
276
        lst_title = ['', _('Date<br />[Duration]'), '#', _('Host'),
277
                _('Service Type<br />Service Name'), _('Output')]
278
        lst_title.extend([plug.name for plug in self.plugin])
279
        lst_title.extend(['[T T]', ''])
280
        
281
        events = [lst_title]
282
        i = 0
283
        class_tr = ['odd', 'even']
284
        ids = []
285
        for req in self.req[first_row : last_row]:
286

  
287
            # Si il y a plus d'un élément dans la liste des tables,
288
            # rq devient une liste plutôt que d'être directement la
289
            # table souhaité
290
            
291
            if isinstance(req, Events) :
292
                event = req
293
            else :
294
                event = req[0]
295
            ids.append(event.idevent)
296

  
297
            # La liste pour l'évènement actuel comporte dans l'ordre :
298
            #   L'évènment en lui même
299
            #   La classe à appliquer sur la ligne (permet d'alterner les
300
            #       couleurs suivant les lignes)
301
            #   La classe pour la case comportant la flèche de détails
302
            #   La classe pour la date, l'occurrence et l'édition
303
            #   L'image a affiche pour la flèche de détails
304
            #   Une liste (une case par plugin) de ce que le plugin souhaite
305
            #       afficher en fonction de l'évènement
306

  
307
            if event.active :
308
                events.append([
309
                    event,
310
                    {'class': class_tr[i%2]},
311
                    {'class' : self.bouton_severity[event.severity] + \
312
                            self.class_ack[event.status]},
313
                    {'class' : self.bouton_severity[event.severity] + \
314
                            self.class_ack[event.status] },
315
                    {'src' : '/images/%s2.png' % \
316
                            self.bouton_severity[event.severity].upper()},
317
                    self.format_events_img_statu(event),
318
                    [[j.__show__(req), j.style] for j in self.plugin]
319
                    ])
320
            else :
321
                events.append([
322
                    event,
323
                    {'class': class_tr[i%2]},
324
                    {'class' : self.bouton_severity[event.severity] + \
325
                            self.class_ack[event.status] },
326
                    {'class' : 'Cleared' + self.class_ack[event.status] },
327
                    {'src' : '/images/%s2.png' % \
328
                            self.bouton_severity[event.severity].upper()},
329
                    self.format_events_img_statu(event),
330
                    [[j.__show__(req), j.style] for j in self.plugin]
331
                    ])
332
            i = i + 1
333

  
334
        # On sauvegarde la liste précédemment créée puis rempli
335
        # le TmplContext
336

  
337
        self.events = events
338
        self.idevents = ids
339

  
340
    def format_history (self):
341
        
342
        """
343
        Formate les historiques correspondant aux évènements sélectionnés
344
        pour un affichage simple du résultat par Genshi.
345
        On génère une liste de liste, chaqu'une étant la description de l'affichage pour un
346
        historique donné.
347
        """
348

  
349
        history = DBSession.query(EventHistory
350
                ).filter(EventHistory.idevent.in_(self.idevents)
351
                ).order_by(desc(EventHistory.timestamp)
352
                ).order_by(desc(EventHistory.idhistory))
353

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff