|
1 |
| -#!/usr/local/bin/python3.8 |
2 |
| -import logging as mLog |
3 |
| -from logging import Formatter, FileHandler |
4 |
| -from logging.handlers import RotatingFileHandler |
5 |
| -from configparser import RawConfigParser |
6 |
| -from subprocess import Popen, PIPE |
7 |
| -from datetime import timedelta, datetime, time |
8 |
| - |
9 |
| -## Exceptions |
10 |
| -class AutoBkError(Exception): pass |
11 |
| - |
12 |
| -############################### |
13 |
| -# Global Configurations and Constants |
14 |
| -oLog = mLog.getLogger() # root logger |
15 |
| -sAt = 'autobk:%s=%s' |
16 |
| -sCombo = '{} @ {}' |
17 |
| -sAuthKey = '{}:{}' |
18 |
| -sSubPath = "{}/{}" |
19 |
| -sSqlTimeFmt = '%Y-%m-%d %H:%M:%S' |
20 |
| - |
21 |
| -############################### |
22 |
| -# Loads the configuration file and logger |
23 |
| -def LoadConfig(sMod, *, sIniFile='./autobk.ini', bRotate=False): |
24 |
| - global oLog, sAt |
25 |
| - # Parse Config File |
26 |
| - oINI = RawConfigParser() |
27 |
| - oINI.read([sIniFile]) |
28 |
| - |
29 |
| - # Load Logging config |
30 |
| - sIni = 'Logging' |
31 |
| - sLogFile = oINI.get(sIni, 'File', fallback='./autobk.log') |
32 |
| - iLogSize = oINI.getint(sIni, 'MaxSize', fallback=64000) |
33 |
| - iLogCount = oINI.getint(sIni, 'Count', fallback=3) |
34 |
| - sLogLevel = oINI.get(sIni, 'Level', fallback=mLog.INFO) |
35 |
| - sAt = sMod + ':%s=%s' |
36 |
| - |
37 |
| - # Logging Components |
38 |
| - oF = Formatter('%(asctime)s - %(message)s', sSqlTimeFmt) |
39 |
| - oH = RotatingFileHandler(sLogFile, 'a', iLogSize, iLogCount) if bRotate else FileHandler(sLogFile) |
40 |
| - oH.setFormatter(oF) |
41 |
| - |
42 |
| - # Setup Loggers |
43 |
| - oLog.setLevel(mLog.WARNING) |
44 |
| - oLog.addHandler(oH) |
45 |
| - oLog = mLog.getLogger('AutoBk') # Switch to local logger to avoid spam from other modules |
46 |
| - oLog.setLevel(sLogLevel) |
47 |
| - oLog.addHandler(oH) |
48 |
| - oLog.propagate = False |
49 |
| - |
50 |
| - return (oINI, oLog, sAt) |
51 |
| - |
52 |
| -############################### |
53 |
| -# Returns the next iWeekday@iHour from tFrom |
54 |
| -def NextWeekday(tFrom, iWeekday, iHour, iWeeks=1): |
55 |
| - iOffset = iWeekday - tFrom.isoweekday() |
56 |
| - if (iOffset > 0): iWeeks -= 1 |
57 |
| - iOffset += iWeeks * 7 |
58 |
| - return datetime.combine(tFrom + timedelta(days=iOffset), time(hour=iHour), tFrom.tzinfo) |
59 |
| - |
60 |
| -############################### |
61 |
| -# Executes a script in a new process and waits for completion |
62 |
| -def CallScript(sName, sScript, *, lsArg=None, iTimeout=60, bOutIsErr=True): |
63 |
| - # Prepare arguments for process call |
64 |
| - lsParam = ['python3.8', sScript] |
65 |
| - if (lsArg is not None): lsParam += lsArg |
66 |
| - |
67 |
| - # Execute script |
68 |
| - oLog.info(sAt, sName, 'calling') |
69 |
| - oProc = Popen(lsParam, stdout=PIPE, text=True) |
70 |
| - sOut = None |
71 |
| - |
72 |
| - # Wait for completion |
73 |
| - try: |
74 |
| - (sOut, sErr) = oProc.communicate(timeout=iTimeout) |
75 |
| - except Exception as oErr: |
76 |
| - oLog.error(sAt, sName, 'timeout') |
77 |
| - oProc.kill() |
78 |
| - |
79 |
| - if (oProc.returncode == 0): |
80 |
| - oLog.info(sAt, sName, 'complete') |
81 |
| - return None if (bOutIsErr) else sOut |
82 |
| - else: |
83 |
| - oLog.error(sAt, sName, 'failed') |
84 |
| - return sOut if (bOutIsErr) else None |
85 |
| - |
86 |
| -############################### |
87 |
| -# Sends an HTTP request and returns the response |
88 |
| -def HttpRequest(oHttpCnx, sURL, dnHdrs, *, bPost=False, bData=True, sMsg=None, sFallbackURL=None): |
89 |
| - # Send HTTP transfer request message to get a file |
90 |
| - oHttpCnx.request('POST' if (bPost) else 'GET', sURL, sMsg, dnHdrs) |
91 |
| - oResponse = oHttpCnx.getresponse() |
92 |
| - if (oResponse.status == 200 or oResponse.status == 302): |
93 |
| - return oResponse.read() if bData else oResponse |
94 |
| - elif (oResponse.status == 404 and sFallbackURL is not None): |
95 |
| - oResponse.read() # Must read all data before trying fallback |
96 |
| - return HttpRequest(oHttpCnx, sFallbackURL, dnHdrs, bPost=bPost, bData=bData, sMsg=sMsg) |
97 |
| - else: |
98 |
| - raise AutoBkError('Bad HTTP Response: {}'.format(oResponse.status)) |
| 1 | +#!/usr/local/bin/python3.8 |
| 2 | +import logging as mLog |
| 3 | +from logging import Formatter, FileHandler |
| 4 | +from logging.handlers import RotatingFileHandler |
| 5 | +from configparser import RawConfigParser |
| 6 | +from subprocess import Popen, PIPE |
| 7 | +from datetime import timedelta, datetime, time |
| 8 | + |
| 9 | +## Exceptions |
| 10 | +class AutoBkError(Exception): pass |
| 11 | + |
| 12 | +############################### |
| 13 | +# Global Configurations and Constants |
| 14 | +oLog = mLog.getLogger() # root logger |
| 15 | +sAt = 'autobk:%s=%s' |
| 16 | +sCombo = '{} @ {}' |
| 17 | +sAuthKey = '{}:{}' |
| 18 | +sSubPath = "{}/{}" |
| 19 | +sSqlTimeFmt = '%Y-%m-%d %H:%M:%S' |
| 20 | + |
| 21 | +############################### |
| 22 | +# Loads the configuration file and logger |
| 23 | +def LoadConfig(sMod, *, sIniFile='./autobk.ini', bRotate=False): |
| 24 | + global oLog, sAt |
| 25 | + # Parse Config File |
| 26 | + oINI = RawConfigParser() |
| 27 | + oINI.read([sIniFile]) |
| 28 | + |
| 29 | + # Load Logging config |
| 30 | + sIni = 'Logging' |
| 31 | + sLogFile = oINI.get(sIni, 'File', fallback='./autobk.log') |
| 32 | + iLogSize = oINI.getint(sIni, 'MaxSize', fallback=64000) |
| 33 | + iLogCount = oINI.getint(sIni, 'Count', fallback=3) |
| 34 | + sLogLevel = oINI.get(sIni, 'Level', fallback=mLog.INFO) |
| 35 | + sAt = sMod + ':%s=%s' |
| 36 | + |
| 37 | + # Logging Components |
| 38 | + oF = Formatter('%(asctime)s - %(message)s', sSqlTimeFmt) |
| 39 | + oH = RotatingFileHandler(sLogFile, 'a', iLogSize, iLogCount) if bRotate else FileHandler(sLogFile) |
| 40 | + oH.setFormatter(oF) |
| 41 | + |
| 42 | + # Setup Loggers |
| 43 | + oLog.setLevel(mLog.WARNING) |
| 44 | + oLog.addHandler(oH) |
| 45 | + oLog = mLog.getLogger('AutoBk') # Switch to local logger to avoid spam from other modules |
| 46 | + oLog.setLevel(sLogLevel) |
| 47 | + oLog.addHandler(oH) |
| 48 | + oLog.propagate = False |
| 49 | + |
| 50 | + return (oINI, oLog, sAt) |
| 51 | + |
| 52 | +############################### |
| 53 | +# Returns the next iWeekday@iHour from tFrom |
| 54 | +def NextWeekday(tFrom, iWeekday, iHour, iWeeks=1): |
| 55 | + iOffset = iWeekday - tFrom.isoweekday() |
| 56 | + if (iOffset > 0): iWeeks -= 1 |
| 57 | + iOffset += iWeeks * 7 |
| 58 | + return datetime.combine(tFrom + timedelta(days=iOffset), time(hour=iHour), tFrom.tzinfo) |
| 59 | + |
| 60 | +############################### |
| 61 | +# Executes a script in a new process and waits for completion |
| 62 | +def CallScript(sName, sScript, *, lsArg=None, iTimeout=60, bOutIsErr=True): |
| 63 | + # Prepare arguments for process call |
| 64 | + lsParam = ['python3.8', sScript] |
| 65 | + if (lsArg is not None): lsParam += lsArg |
| 66 | + |
| 67 | + # Execute script |
| 68 | + oLog.info(sAt, sName, 'calling') |
| 69 | + oProc = Popen(lsParam, stdout=PIPE, text=True) |
| 70 | + sOut = None |
| 71 | + |
| 72 | + # Wait for completion |
| 73 | + try: |
| 74 | + (sOut, sErr) = oProc.communicate(timeout=iTimeout) |
| 75 | + except Exception as oErr: |
| 76 | + oLog.error(sAt, sName, 'timeout') |
| 77 | + oProc.kill() |
| 78 | + |
| 79 | + if (oProc.returncode == 0): |
| 80 | + oLog.info(sAt, sName, 'complete') |
| 81 | + return None if (bOutIsErr) else sOut |
| 82 | + else: |
| 83 | + oLog.error(sAt, sName, 'failed') |
| 84 | + return sOut if (bOutIsErr) else None |
| 85 | + |
| 86 | +############################### |
| 87 | +# Sends an HTTP request and returns the response |
| 88 | +def HttpRequest(oHttpCnx, sURL, dnHdrs, *, bPost=False, bData=True, sMsg=None, sFallbackURL=None): |
| 89 | + # Send HTTP transfer request message to get a file |
| 90 | + oHttpCnx.request('POST' if (bPost) else 'GET', sURL, sMsg, dnHdrs) |
| 91 | + oResponse = oHttpCnx.getresponse() |
| 92 | + if (oResponse.status == 200 or oResponse.status == 302): |
| 93 | + return oResponse.read() if bData else oResponse |
| 94 | + elif (oResponse.status == 404 and sFallbackURL is not None): |
| 95 | + oResponse.read() # Must read all data before trying fallback |
| 96 | + return HttpRequest(oHttpCnx, sFallbackURL, dnHdrs, bPost=bPost, bData=bData, sMsg=sMsg) |
| 97 | + else: |
| 98 | + raise AutoBkError('Bad HTTP Response: {}'.format(oResponse.status)) |
0 commit comments