##// END OF EJS Templates
Miguel Valdez -
r681:a13b962c6023
parent child
Show More
@@ -0,0 +1,346
1 """The admin module contains all administrative classes relating to the schain python api.
2
3 The main role of this module is to send some reports. It contains a
4 notification class and a standard error handing class.
5
6 $Id: admin.py 3966 2015-12-01 14:32:29Z miguel.urco $
7 """
8 import os
9 import smtplib
10 import ConfigParser
11 import StringIO
12
13 from email.mime.text import MIMEText
14 from email.mime.application import MIMEApplication
15 from email.mime.multipart import MIMEMultipart
16
17 class SchainConfigure():
18
19 __DEFAULT_SENDER_EMAIL = "notifier-schain@jro.igp.gob.pe"
20 __DEFAULT_ADMINISTRATOR_EMAIL = "miguel.urco@jro.igp.gob.pe"
21 __DEFAULT_EMAIL_SERVER = "jro-zimbra.igp.gob.pe"
22
23 __SCHAIN_ADMINISTRATOR_EMAIL = "CONTACT"
24 __SCHAIN_EMAIL_SERVER = "MAILSERVER"
25 __SCHAIN_SENDER_EMAIL = "MAILSERVER_ACCOUNT"
26
27 def __init__(self, initFile = None):
28
29 # Set configuration file
30 if (initFile == None):
31 self.__confFilePath = "/etc/schain.conf"
32 else:
33 self.__confFilePath = initFile
34
35 # open configuration file
36 try:
37 self.__confFile = open(self.__confFilePath, "r")
38 except IOError:
39 # can't read from file - use all hard-coded values
40 self.__initFromHardCode()
41 return
42
43 # create Parser using standard module ConfigParser
44 self.__parser = ConfigParser.ConfigParser()
45
46 # read conf file into a StringIO with "[madrigal]\n" section heading prepended
47 strConfFile = StringIO.StringIO("[schain]\n" + self.__confFile.read())
48
49 # parse StringIO configuration file
50 self.__parser.readfp(strConfFile)
51
52 # read information from configuration file
53 self.__readConfFile()
54
55 # close conf file
56 self.__confFile.close()
57
58
59 def __initFromHardCode(self):
60
61 self.__sender_email = self.__DEFAULT_SENDER_EMAIL
62 self.__admin_email = self.__DEFAULT_ADMINISTRATOR_EMAIL
63 self.__email_server = self.__DEFAULT_EMAIL_SERVER
64
65 def __readConfFile(self):
66 """__readConfFile is a private helper function that reads information from the parsed config file.
67
68 Inputs: None
69
70 Returns: Void.
71
72 Affects: Initializes class member variables that are found in the config file.
73
74 Exceptions: MadrigalError thrown if any key not found.
75 """
76
77 # get the sender email
78 try:
79 self.__sender_email = self.__parser.get("schain", self.__SCHAIN_SENDER_EMAIL)
80 except:
81 self.__sender_email = self.__DEFAULT_SENDER_EMAIL
82
83 # get the administrator email
84 try:
85 self.__admin_email = self.__parser.get("schain", self.__SCHAIN_ADMINISTRATOR_EMAIL)
86 except:
87 self.__admin_email = self.__DEFAULT_ADMINISTRATOR_EMAIL
88
89 # get the server email
90 try:
91 self.__email_server = self.__parser.get("schain", self.__SCHAIN_EMAIL_SERVER)
92 except:
93 self.__email_server = self.__DEFAULT_EMAIL_SERVER
94
95 def getEmailServer(self):
96
97 return self.__email_server
98
99 def getSenderEmail(self):
100
101 return self.__sender_email
102
103 def getAdminEmail(self):
104
105 return self.__admin_email
106
107 class SchainNotify:
108 """SchainNotify is an object used to send messages to an administrator about a Schain software.
109
110 This object provides functions needed to send messages to an administrator about a Schain , for now
111 only sendAlert, which sends an email to the site administrator found is ADMIN_EMAIL
112
113 Usage example:
114
115 import schainpy.admin
116
117 try:
118
119 adminObj = schainpy.admin.SchainNotify()
120 adminObj.sendAlert('This is important!', 'Important Message')
121
122 except schainpy.admin.SchainError, e:
123
124 print e.getExceptionStr()
125
126
127 Non-standard Python modules used:
128 None
129
130 Exceptions thrown: None - Note that SchainNotify tries every trick it knows to avoid
131 throwing exceptions, since this is the class that will generally be called when there is a problem.
132
133 Change history:
134
135 Written by "Miguel Urco":mailto:miguel.urco@jro.igp.gob.pe Dec. 1, 2015
136 """
137
138 #constants
139
140 def __init__(self):
141 """__init__ initializes SchainNotify by getting some basic information from SchainDB and SchainSite.
142
143 Note that SchainNotify tries every trick it knows to avoid throwing exceptions, since
144 this is the class that will generally be called when there is a problem.
145
146 Inputs: Existing SchainDB object, by default = None.
147
148 Returns: void
149
150 Affects: Initializes self.__binDir.
151
152 Exceptions: None.
153 """
154
155 # note that the main configuration file is unavailable
156 # the best that can be done is send an email to root using localhost mailserver
157 confObj = SchainConfigure()
158
159 self.__emailFromAddress = confObj.getSenderEmail()
160 self.__emailToAddress = confObj.getAdminEmail()
161 self.__emailServer = confObj.getEmailServer()
162
163 def sendEmail(self, email_from, email_to, subject='Error running ...', message="", subtitle="", filename="", html_format=True):
164
165 msg = MIMEMultipart()
166 msg['Subject'] = subject
167 msg['From'] = "(Python SChain API): " + email_from
168 msg['Reply-to'] = email_from
169 msg['To'] = email_to
170
171 # That is what u see if dont have an email reader:
172 msg.preamble = 'SChainPy'
173
174 if html_format:
175 message = "<h1> %s </h1>" %subject + "<h3>" + subtitle.replace("\n", "</h3><h3>\n") + "</h3>" + message.replace("\n", "<br>\n")
176 message = "<html>\n" + message + '</html>'
177
178 # This is the textual part:
179 part = MIMEText(message, "html")
180 else:
181 message = subject + "\n" + subtitle + "\n" + message
182 part = MIMEText(message)
183
184 msg.attach(part)
185
186 if os.path.isfile(filename):
187 # This is the binary part(The Attachment):
188 part = MIMEApplication(open(filename,"rb").read())
189 part.add_header('Content-Disposition',
190 'attachment',
191 filename=os.path.basename(filename))
192 msg.attach(part)
193
194 # Create an instance in SMTP server
195 smtp = smtplib.SMTP(self.__emailServer)
196 # Start the server:
197 # smtp.ehlo()
198 # smtp.login(email_from, email_from_pass)
199
200 # Send the email
201 smtp.sendmail(msg['From'], msg['To'], msg.as_string())
202 smtp.quit()
203
204
205 def sendAlert(self, message, subject = "", subtitle="", filename=""):
206 """sendAlert sends an email with the given message and optional title.
207
208 Inputs: message (string), and optional title (string)
209
210 Returns: void
211
212 Affects: none
213
214 Exceptions: None.
215 """
216 print "***** Sending alert to %s *****" %self.__emailToAddress
217 # set up message
218
219 self.sendEmail(email_from=self.__emailFromAddress,
220 email_to=self.__emailToAddress,
221 subject=subject,
222 message=message,
223 subtitle=subtitle,
224 filename=filename)
225
226 print "***** Your system administrator has been notified *****"
227
228
229 def notify(self, email, message, subject = "", subtitle="", filename=""):
230 """notify sends an email with the given message and title to email.
231
232 Inputs: email (string), message (string), and subject (string)
233
234 Returns: void
235
236 Affects: none
237
238 Exceptions: None.
239 """
240
241 print "Notifying to %s ..." %email
242
243 self.sendEmail(email_from=self.__emailFromAddress,
244 email_to=email,
245 subject=subject,
246 message=message,
247 subtitle=subtitle,
248 filename=filename)
249
250 print "***** Your system administrator has been notified *****"
251
252 class SchainError:
253 """SchainError is an exception class that is thrown for all known errors in using Schain Py lib.
254
255 Usage example:
256
257 import sys, traceback
258 import schainpy.admin
259
260 try:
261
262 test = open('ImportantFile.txt', 'r')
263
264 except:
265
266 raise schainpy.admin.SchainError('ImportantFile.txt not opened!',
267 traceback.format_exception(sys.exc_info()[0],
268 sys.exc_info()[1],
269 sys.exc_info()[2]))
270 """
271
272
273 def __init__(self, strInterpretation, exceptionList):
274 """ __init__ gathers the interpretation string along with all information from sys.exc_info().
275
276 Inputs: strIntepretation - A string representing the programmer's interpretation of
277 why the exception occurred
278
279 exceptionList - a list of strings completely describing the exception.
280 Generated by traceback.format_exception(sys.exc_info()[0],
281 sys.exc_info()[1],
282 sys.exc_info()[2])
283
284 Returns: Void.
285
286 Affects: Initializes class member variables _strInterp, _strExcList.
287
288 Exceptions: None.
289 """
290
291 self._strInterp = strInterpretation
292 self._strExcList = exceptionList
293
294
295 def getExceptionStr(self):
296 """ getExceptionStr returns a formatted string ready for printing completely describing the exception.
297
298 Inputs: None
299
300 Returns: A formatted string ready for printing completely describing the exception.
301
302 Affects: None
303
304 Exceptions: None.
305 """
306 excStr = 'The following Schain Python exception has occurred:\n'
307 excStr = excStr + self._strInterp + '\n\n'
308
309 if self._strExcList != None:
310 for item in self._strExcList:
311 excStr = excStr + str(item) + '\n'
312
313 return excStr
314
315 def __str__(self):
316 return(self.getExceptionStr())
317
318
319 def getExceptionHtml(self):
320 """ getExceptionHtml returns an Html formatted string completely describing the exception.
321
322 Inputs: None
323
324 Returns: A formatted string ready for printing completely describing the exception.
325
326 Affects: None
327
328 Exceptions: None.
329 """
330
331 excStr = '<BR>The following Schain Python exception has occurred:\n<BR>'
332 excStr = excStr + self._strInterp + '\n<BR>\n'
333
334 if self._strExcList != None:
335 for item in self._strExcList:
336 excStr = excStr + str(item) + '\n<BR>'
337
338 return excStr
339
340 if __name__ == '__main__':
341
342 test = SchainNotify()
343
344 test.sendAlert('This is a message from the python module SchainNotify', 'Test from SchainNotify')
345
346 print 'Hopefully message sent - check.'
@@ -0,0 +1,5
1 #Copy this file to /etc/schain.conf
2 [schain]
3 CONTACT = miguel.urco@jro.igp.gob.pe
4 MAILSERVER = jro-zimbra.igp.gob.pe
5 MALSERVER_ACCOUNT = notifier-schain@jro.igp.gob.pe No newline at end of file
@@ -23,4 +23,7 VERSIONS:
23 23 -controller_api.py: Safe access to ControllerThead
24 24
25 25 2.1.3.3:
26 -Colored Button Icons were added to GUI No newline at end of file
26 -Colored Button Icons were added to GUI
27
28 2.1.4:
29 -Sending error notifications to signal chain administrator No newline at end of file
@@ -4,4 +4,4 Created on Feb 7, 2012
4 4 @author $Author$
5 5 @version $Id$
6 6 '''
7 __version__ = "2.1.3.3" No newline at end of file
7 __version__ = "2.1.4" No newline at end of file
@@ -2,18 +2,18
2 2 Created on September , 2012
3 3 @author:
4 4 '''
5 from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring
6 from xml.dom import minidom
7
8 from model import *
9 from time import sleep
10 5
11 6 import sys
12 7 import ast
13 8 import traceback
9 import schainpy
10 import schainpy.admin
14 11
15 SCHAIN_MAIL = "miguel.urco@jro.igp.gob.pe"
16 EMAIL_SERVER = "jro.igp.gob.pe"
12 from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring
13 from xml.dom import minidom
14
15 from schainpy.model import *
16 from time import sleep
17 17
18 18 def prettify(elem):
19 19 """Return a pretty-printed XML string for the Element.
@@ -325,9 +325,9 class OperationConf():
325 325
326 326 return parmConfObj
327 327
328 def makeXml(self, upElement):
328 def makeXml(self, procUnitElement):
329 329
330 opElement = SubElement(upElement, self.ELEMENTNAME)
330 opElement = SubElement(procUnitElement, self.ELEMENTNAME)
331 331 opElement.set('id', str(self.id))
332 332 opElement.set('name', self.name)
333 333 opElement.set('type', self.type)
@@ -539,16 +539,16 class ProcUnitConf():
539 539
540 540 return opConfObj
541 541
542 def makeXml(self, procUnitElement):
542 def makeXml(self, projectElement):
543 543
544 upElement = SubElement(procUnitElement, self.ELEMENTNAME)
545 upElement.set('id', str(self.id))
546 upElement.set('name', self.name)
547 upElement.set('datatype', self.datatype)
548 upElement.set('inputId', str(self.inputId))
544 procUnitElement = SubElement(projectElement, self.ELEMENTNAME)
545 procUnitElement.set('id', str(self.id))
546 procUnitElement.set('name', self.name)
547 procUnitElement.set('datatype', self.datatype)
548 procUnitElement.set('inputId', str(self.inputId))
549 549
550 550 for opConfObj in self.opConfObjList:
551 opConfObj.makeXml(upElement)
551 opConfObj.makeXml(procUnitElement)
552 552
553 553 def readXml(self, upElement):
554 554
@@ -757,12 +757,53 class ReadUnitConf(ProcUnitConf):
757 757
758 758 return opObj
759 759
760 # def makeXml(self, projectElement):
761 #
762 # procUnitElement = SubElement(projectElement, self.ELEMENTNAME)
763 # procUnitElement.set('id', str(self.id))
764 # procUnitElement.set('name', self.name)
765 # procUnitElement.set('datatype', self.datatype)
766 # procUnitElement.set('inputId', str(self.inputId))
767 #
768 # for opConfObj in self.opConfObjList:
769 # opConfObj.makeXml(procUnitElement)
770
771 def readXml(self, upElement):
772
773 self.id = upElement.get('id')
774 self.name = upElement.get('name')
775 self.datatype = upElement.get('datatype')
776 self.inputId = upElement.get('inputId')
777
778 if self.ELEMENTNAME == "ReadUnit":
779 self.datatype = self.datatype.replace("Reader", "")
780
781 if self.inputId == 'None':
782 self.inputId = '0'
783
784 self.opConfObjList = []
785
786 opElementList = upElement.getiterator(OperationConf().getElementName())
787
788 for opElement in opElementList:
789 opConfObj = OperationConf()
790 opConfObj.readXml(opElement)
791 self.opConfObjList.append(opConfObj)
792
793 if opConfObj.name == 'run':
794 self.path = opConfObj.getParameterValue('path')
795 self.startDate = opConfObj.getParameterValue('startDate')
796 self.endDate = opConfObj.getParameterValue('endDate')
797 self.startTime = opConfObj.getParameterValue('startTime')
798 self.endTime = opConfObj.getParameterValue('endTime')
799
760 800 class Project():
761 801
762 802 id = None
763 803 name = None
764 804 description = None
765 # readUnitConfObjList = None
805 filename = None
806
766 807 procUnitConfObjDict = None
767 808
768 809 ELEMENTNAME = 'Project'
@@ -898,14 +939,26 class Project():
898 939
899 940 def writeXml(self, filename):
900 941
901 self.makeXml()
942 if not os.access(os.path.dirname(filename), os.W_OK):
943 return 0
902 944
903 #print prettify(self.projectElement)
945 if os.path.isfile(filename) and not(os.access(filename, os.W_OK)):
946 return 0
947
948 self.makeXml()
904 949
905 950 ElementTree(self.projectElement).write(filename, method='xml')
951
952 self.filename = filename
953
954 return 1
906 955
907 956 def readXml(self, filename):
908 957
958 if not os.path.isfile(filename):
959 print "%s does not exist" %filename
960 return 0
961
909 962 self.projectElement = None
910 963 self.procUnitConfObjDict = {}
911 964
@@ -938,7 +991,9 class Project():
938 991 procUnitConfObj.parentId = self.id
939 992
940 993 self.procUnitConfObjDict[procUnitConfObj.getId()] = procUnitConfObj
941
994
995 return 1
996
942 997 def printattr(self):
943 998
944 999 print "Project[%s]: name = %s, description = %s" %(self.id,
@@ -1010,7 +1065,7 class Project():
1010 1065
1011 1066 print
1012 1067 print "*"*60
1013 print " Starting SIGNAL CHAIN PROCESSING "
1068 print " Starting SIGNAL CHAIN PROCESSING v%s " %schainpy.__version__
1014 1069 print "*"*60
1015 1070 print
1016 1071
@@ -1026,28 +1081,46 class Project():
1026 1081
1027 1082 procUnitConfObj = self.procUnitConfObjDict[procKey]
1028 1083
1029 message = ""
1030 1084 try:
1031 1085 sts = procUnitConfObj.run()
1032 1086 is_ok = is_ok or sts
1033 1087 except:
1034 print "***** Error running %s *****" %procUnitConfObj.name
1035 sleep(1)
1088 print "***** Error occurred in %s *****" %(procUnitConfObj.name)
1089
1090 sleep(0.5)
1036 1091
1037 1092 err = traceback.format_exception(sys.exc_info()[0],
1038 1093 sys.exc_info()[1],
1039 1094 sys.exc_info()[2])
1040 1095
1041 for thisLine in err:
1042 message += thisLine
1096 import socket
1097
1098 subject = "SChain v%s: Error running %s\n" %(schainpy.__version__, procUnitConfObj.name)
1099
1100 subtitle = "%s: %s\n" %(procUnitConfObj.getElementName() ,procUnitConfObj.name)
1101 subtitle += "Hostname: %s\n" %socket.gethostbyname(socket.gethostname())
1102 subtitle += "Working directory: %s\n" %os.path.abspath("./")
1103 subtitle += "Configuration file: %s\n" %self.filename
1104
1105 readUnitConfObj = self.getReadUnitObj()
1106 if readUnitConfObj:
1107 subtitle += "Data path: %s\n" %readUnitConfObj.path
1108 subtitle += "Data type: %s\n" %readUnitConfObj.datatype
1109 subtitle += "Start date: %s\n" %readUnitConfObj.startDate
1110 subtitle += "End date: %s\n" %readUnitConfObj.endDate
1111 subtitle += "Start time: %s\n" %readUnitConfObj.startTime
1112 subtitle += "End time: %s\n" %readUnitConfObj.endTime
1113
1114 message = "".join(err)
1043 1115
1044 1116 sys.stderr.write(message)
1045 # print "*"*60
1046 # print message
1047 # print "*"*60
1117
1118 adminObj = schainpy.admin.SchainNotify()
1119 adminObj.sendAlert(message=message,
1120 subject=subject,
1121 subtitle=subtitle,
1122 filename=self.filename)
1048 1123
1049 # self.sendReport(message)
1050 sleep(0.1)
1051 1124 is_ok = False
1052 1125
1053 1126 break
@@ -1075,23 +1148,6 class Project():
1075 1148 self.createObjects()
1076 1149 self.connectObjects()
1077 1150 self.run()
1078
1079 def sendReport(self, message, subject="Error occurred in Signal Chain", email=SCHAIN_MAIL):
1080
1081 import smtplib
1082
1083 print subject
1084 print "Sending report to %s ..." %email
1085
1086 message = 'From: (Python Signal Chain API) ' + email + '\n' + \
1087 'To: ' + email + '\n' + \
1088 'Subject: ' + str(subject) + '\n' + \
1089 'Content-type: text/html\n\n' + message
1090
1091 server = smtplib.SMTP(EMAIL_SERVER)
1092 server.sendmail(email.split(',')[0],
1093 email.split(','), message)
1094 server.quit()
1095 1151
1096 1152 if __name__ == '__main__':
1097 1153
@@ -1,8 +1,5
1 1 import threading
2 2
3 from PyQt4 import QtCore
4 from PyQt4.QtCore import SIGNAL
5
6 3 from schainpy.controller import Project
7 4
8 5 class ControllerThread(threading.Thread, Project):
@@ -74,68 +71,71 class ControllerThread(threading.Thread, Project):
74 71 def isFinished(self):
75 72
76 73 return not self.is_alive()
77
78 class ControllerQThread(QtCore.QThread, Project):
79
80 def __init__(self, filename):
81
82 QtCore.QThread.__init__(self)
83 Project.__init__(self)
84
85 self.filename = filename
86
87 self.lock = threading.Lock()
88 self.control = {'stop':False, 'pause':False}
89
90 def __del__(self):
91
92 self.control['stop'] = True
93 self.wait()
94
95 def stop(self):
96
97 self.lock.acquire()
98
99 self.control['stop'] = True
100
101 self.lock.release()
102
103 def pause(self):
104
105 self.lock.acquire()
106
107 self.control['pause'] = not(self.control['pause'])
108 paused = self.control['pause']
109
110 self.lock.release()
111
112 return paused
113
114 def isPaused(self):
115
116 self.lock.acquire()
117 paused = self.control['pause']
118 self.lock.release()
119
120 return paused
121
122 def isStopped(self):
123
124 self.lock.acquire()
125 stopped = self.control['stop']
126 self.lock.release()
127
128 return stopped
129
130 def run(self):
131
132 self.control['stop'] = False
133 self.control['pause'] = False
134
135 self.readXml(self.filename)
136 self.createObjects()
137 self.connectObjects()
138 self.emit( SIGNAL( "jobStarted( PyQt_PyObject )" ), 1)
139 Project.run(self)
140 self.emit( SIGNAL( "jobFinished( PyQt_PyObject )" ), 1)
141 No newline at end of file
74
75 # from PyQt4 import QtCore
76 # from PyQt4.QtCore import SIGNAL
77 #
78 # class ControllerQThread(QtCore.QThread, Project):
79 #
80 # def __init__(self, filename):
81 #
82 # QtCore.QThread.__init__(self)
83 # Project.__init__(self)
84 #
85 # self.filename = filename
86 #
87 # self.lock = threading.Lock()
88 # self.control = {'stop':False, 'pause':False}
89 #
90 # def __del__(self):
91 #
92 # self.control['stop'] = True
93 # self.wait()
94 #
95 # def stop(self):
96 #
97 # self.lock.acquire()
98 #
99 # self.control['stop'] = True
100 #
101 # self.lock.release()
102 #
103 # def pause(self):
104 #
105 # self.lock.acquire()
106 #
107 # self.control['pause'] = not(self.control['pause'])
108 # paused = self.control['pause']
109 #
110 # self.lock.release()
111 #
112 # return paused
113 #
114 # def isPaused(self):
115 #
116 # self.lock.acquire()
117 # paused = self.control['pause']
118 # self.lock.release()
119 #
120 # return paused
121 #
122 # def isStopped(self):
123 #
124 # self.lock.acquire()
125 # stopped = self.control['stop']
126 # self.lock.release()
127 #
128 # return stopped
129 #
130 # def run(self):
131 #
132 # self.control['stop'] = False
133 # self.control['pause'] = False
134 #
135 # self.readXml(self.filename)
136 # self.createObjects()
137 # self.connectObjects()
138 # self.emit( SIGNAL( "jobStarted( PyQt_PyObject )" ), 1)
139 # Project.run(self)
140 # self.emit( SIGNAL( "jobFinished( PyQt_PyObject )" ), 1)
141 # No newline at end of file
@@ -27,7 +27,9 setup(name="schainpy",
27 27 'schainpy.gui.viewer.windows'},
28 28 py_modules=['schainpy.serializer.DataTranslate',
29 29 'schainpy.serializer.JROSerializer'],
30 package_data={'schainpy.gui.figures': ['*.png','*.jpg']},
30 package_data={'schainpy': ['*.cfg'],
31 'schainpy.gui.figures': ['*.png','*.jpg']
32 },
31 33 include_package_data=True,
32 34 scripts =['schainpy/gui/schainGUI'],
33 35 install_requires=["numpy >= 1.6.0",
General Comments 0
You need to be logged in to leave comments. Login now