File: Policy.pasteur.py

package info (click to toggle)
mobyle 1.0.6~dfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 8,036 kB
  • sloc: python: 19,496; sh: 54; makefile: 30; xml: 6; ansic: 5
file content (214 lines) | stat: -rw-r--r-- 8,252 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
########################################################################################
#                                                                                      #
#   Author: Bertrand Neron,                                                            #
#   Organization:'Biological Software and Databases' Group, Institut Pasteur, Paris.   #  
#   Distributed under GPLv2 Licence. Please refer to the COPYING.LIB document.         #
#                                                                                      #
########################################################################################

import sys
import os.path

import logging 
p_log = logging.getLogger('mobyle.policy')



def queue( queueName ):
    """
    @return: the name of the queue to be used to execute the job
    @rtype: string
    """
    return queueName


def emailCheck( **args ):
    """
    check if the email according to the local rules.
    @return:
     - Mobyle.Net.EmailAddress.VALID    if the email is valid
     - Mobyle.Net.EmailAddress.INVALID  if the email is rejected
     - Mobyle.Net.EmailAddress.CONTINUE to continue futher the email validation process
    """
    import Mobyle.Net
    from Mobyle.MobyleError import MobyleError
    
    user , domainName  = args['email'].split('@')
    if domainName == 'pasteur.fr':
        try:
            local = isLocal( args['email'] )
        except MobyleError , err:
            p_log.error( "an error is occured during checking local login : "+ str( err ))
            # I don't stop Mobyle for that. The user continue as an external user
            return Mobyle.Net.EmailAddress.CONTINUE
        
        if local:
            return Mobyle.Net.EmailAddress.VALID
        else:
            return Mobyle.Net.EmailAddress.INVALID
    else:
        return Mobyle.Net.EmailAddress.CONTINUE

        
def emailUserMessage( method ):
    messages = {
                'host'       : "you have abused our service. Your are not allowed to run on this server for now. For more informations contact mobyle@pasteur.fr",
                'syntax'     : "you are not allowed to run on this server for now" ,
                'blackList'  : "you have abused our service. Your are not allowed to run on this server for now. For more informations contact mobyle@pasteur.fr",
                'LocalRules' : "you are not allowed to run on this server for now",
                'dns'        : "you are not allowed to run on this server for now" ,
    }
    try:
        return messages[ method ]
    except KeyError:
        return "you are not allowed to run on this server for now"
    
def isLocal( email ):
    """
    @return: True if the userName is a pasteur login, False otherwise.
    @rtype: boolean
    """
    import ldap
    con = ldap.initialize( 'ldap://ldap.pasteur.fr' )
    try:
        con.simple_bind_s()
    except Exception , err :
        raise MobbyleError , err
    user , domainName  = email.split('@')
    
    base_dn='ou=personnes,dc=pasteur,dc=fr'
    if user.find('.') != -1:
        filter = '(& (objectclass=posixAccount) (mail=%s))' %email
    else:
        filter = '(& (objectclass=posixAccount) (uid=%s))' %user
    attrs =['mail']
    
    try:
        user = con.search_s( base_dn , ldap.SCOPE_SUBTREE , filter , attrs )  
    except Exception , err :
        raise MobyleError , err
    if user:
        try:
            ldapMail = user[0][1][ 'mail' ][0]
        except KeyError , err:
            #some one try to use a uid which have not mail attribute like dbmaint or sge
            p_log.critical( "some one try to connect with an uid which have not mail : " + str( email ) )
            return False
        return True
    else:
        return False



def authenticate( login , passwd ):
    """
    Mobyle administrator can put authentification code here. this function must return either 
     - Mobyle.AuthenticatedSession.AuthenticatedSession.CONTINUE: 
                the method does not autentified this login/passwd. The fall back method must be applied.
     - Mobyle.AuthenticatedSession.AuthenticatedSession.VALID:    
               the login/password has been authenticated.
     - Mobyle.AuthenticatedSession.AuthenticatedSession.REJECT:    
              the login/password is not allow to continue.
    """
    import Mobyle.AuthenticatedSession
    
    return Mobyle.AuthenticatedSession.AuthenticatedSession.CONTINUE


def allow_to_be_executed( job ):
    """
    check if the job is allowed to be executed 
    if a job is not allowed must raise a UserError
    @param job: the job to check before to submit it to Execution
    @type job: L{Job} instance  
    @raise UserValueError: if the job is not allowed to be executed
    """
    #place here the code you want to be executed to allow a job to be executed.
    #this is the last control be fore DRM submission
    #if you want to limit simultaneous job according some criteria as IP or user email, ...
    #this this the right place to put your code 
    if job.getEmail().endswith("@pasteur.fr") :
        #the email has been already check
        #and for email @pasteur.fr we already check the LDAP 
        #so it's not usefull to check the LDAP again at this step
        return True
    else:
        return over_limit( job )
    
    
    
def over_limit (job):
    """
    check if the user (same email) has a similar job (same command line or same workflow name) running 
    @param job: the job to check before to submit it to Execution
    @type job: L{Job} instance  
    @raise UserValueError: if the number of similar jobs exceed the Config.SIMULTANEOUS_JOBS
    """
    from hashlib import md5
    import glob
    from Mobyle.Admin import Admin
    from Mobyle.MobyleError import UserValueError
    
    newMd5 = md5()
    newMd5.update( str( job.getEmail() ) )
    try:
        remote = os.environ[ 'REMOTE_HOST' ]
        if not remote :
            try:
                remote = os.environ[ 'REMOTE_ADDR' ]
            except KeyError :
                remote = 'no web'
    except KeyError:
        try:
            remote = os.environ[ 'REMOTE_ADDR' ]
        except KeyError:
            remote = 'no web'
                
    newMd5.update( remote )
    newMd5.update( job.getCommandLine() )
    newDigest = newMd5.hexdigest()
    
    work_dir = job.getDir()
        
    thisJobAdm = Admin( work_dir )
    thisJobAdm.setMd5( newDigest )
    thisJobAdm.commit()

    mask = os.path.normpath( "%s/%s.*" %(
        job.cfg.admindir() ,
        job.getServiceName()
        )
                                 )
    jobs = glob.glob( mask )
    max_jobs = job.cfg.simultaneous_jobs()
        
    if max_jobs == 0 :
        return 
    nb_of_jobs = 0
    msg = None
    for one_job in jobs:
        try:
            oldAdm = Admin( one_job )
        except MobyleError, err :
            if os.path.lexists( one_job ):
                p_log.critical( "%s/%s: invalid job in ADMINDIR : %s" %( job.getServiceName() ,  job.getKey() , err ) )
            continue
        if( oldAdm.getWorkflowID() ):
            #we allow a workflow to run several identical job in parallel
            continue
            
        oldDigest = oldAdm.getMd5()
        if newDigest == oldDigest :
            oldStatus = job.getStatus() 
            if not oldStatus.isEnded() :
                nb_of_jobs += 1
                if nb_of_jobs >= max_jobs:
                    msg = "%d similar jobs (%s) have been already submitted (md5 = %s)" % (
                                                                                    nb_of_jobs ,
                                                                                    os.path.basename( one_job ),
                                                                                    newDigest
                                                                                    )
                    userMsg = " %d similar job(s) have been already submitted, and are(is) not finished yet. Please wait for the end of these jobs before you resubmit." % ( nb_of_jobs )
                    p_log.warning( msg + " : run aborted " )
                    raise UserValueError( parameter = None, msg = userMsg )
    return True