2018-08-21 10:27:31 +09:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import logging
|
2018-08-21 11:02:09 +09:00
|
|
|
from datetime import time, datetime
|
2018-08-21 10:27:31 +09:00
|
|
|
|
2018-08-21 11:02:09 +09:00
|
|
|
from util import install_except_hook, KSTTZ, UTCTZ
|
2018-08-21 10:27:31 +09:00
|
|
|
|
|
|
|
|
|
|
|
def handle_daemon(name, action, args):
|
|
|
|
log = logging.getLogger("main_loop")
|
2018-08-21 11:02:09 +09:00
|
|
|
from signal import SIGTERM
|
|
|
|
from util.log import wrap
|
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
if action == 'start':
|
|
|
|
# load config
|
2018-08-21 11:02:09 +09:00
|
|
|
from util import EnteringLoop
|
2018-08-21 10:27:31 +09:00
|
|
|
with EnteringLoop(
|
|
|
|
name,
|
|
|
|
log_dir=args.log_location,
|
|
|
|
log_level=args.log_level,
|
|
|
|
is_forground=args.foreground,
|
|
|
|
pid_path=args.pid_path
|
|
|
|
) as loop:
|
2018-08-21 11:02:09 +09:00
|
|
|
from apscheduler.jobstores.memory import MemoryJobStore
|
|
|
|
from apscheduler.executors.asyncio import AsyncIOExecutor
|
|
|
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|
|
|
from apscheduler.util import undefined
|
|
|
|
from signal import SIGTERM, SIGABRT, SIGINT, SIGQUIT
|
|
|
|
from handler import Session
|
|
|
|
import ujson
|
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
jobstores = {
|
|
|
|
'default': MemoryJobStore()
|
|
|
|
}
|
|
|
|
executors = {
|
|
|
|
'default': AsyncIOExecutor(),
|
|
|
|
}
|
|
|
|
job_defaults = {
|
|
|
|
'coalesce': True,
|
|
|
|
'max_instances': 2
|
|
|
|
}
|
|
|
|
scheduler = AsyncIOScheduler(
|
|
|
|
jobstores=jobstores,
|
|
|
|
executors=executors,
|
|
|
|
job_defaults=job_defaults,
|
|
|
|
timezone=KSTTZ,
|
|
|
|
event_loop=loop)
|
2018-08-21 11:02:09 +09:00
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
with open(args.config) as cfgFile:
|
|
|
|
config = ujson.load(cfgFile)
|
|
|
|
sess = Session(loop=loop, **config)
|
|
|
|
del config
|
|
|
|
job = scheduler.add_job(sess.get_resources,
|
|
|
|
name="charger",
|
|
|
|
trigger='cron',
|
|
|
|
day_of_week='mon-fri',
|
|
|
|
hour=args.standard_time.hour,
|
|
|
|
minute=args.standard_time.minute,
|
|
|
|
second=args.standard_time.second,
|
|
|
|
args=(args.standard_time,),
|
2018-08-21 11:02:09 +09:00
|
|
|
next_run_time=datetime.utcnow().replace(tzinfo=UTCTZ).astimezone(
|
|
|
|
KSTTZ) if args.immediately else undefined
|
2018-08-21 10:27:31 +09:00
|
|
|
)
|
|
|
|
scheduler.start()
|
2018-08-21 11:02:09 +09:00
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
if not args.immediately:
|
|
|
|
log.info("job(%s) may be start in %s", job.name, job.next_run_time)
|
2018-08-21 11:02:09 +09:00
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
def stopme(*_):
|
|
|
|
scheduler.shutdown()
|
|
|
|
sess.close()
|
|
|
|
log.info("handler closed")
|
|
|
|
loop.stop()
|
|
|
|
log.info("loop closed")
|
2018-08-21 11:02:09 +09:00
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
loop.add_signal_handler(SIGQUIT, stopme)
|
|
|
|
loop.add_signal_handler(SIGTERM, stopme)
|
|
|
|
loop.add_signal_handler(SIGINT, stopme)
|
|
|
|
loop.add_signal_handler(SIGABRT, stopme)
|
|
|
|
loop.run_forever()
|
|
|
|
log.info("bye!")
|
|
|
|
elif action == 'stop':
|
2018-08-21 11:02:09 +09:00
|
|
|
from os import path, kill
|
2018-08-21 10:27:31 +09:00
|
|
|
wrap(name, level=args.log_level, stderr=True)
|
|
|
|
if not path.exists(args.pid_path):
|
|
|
|
log.warning("cannot find pidfile(%s)", args.pid_path)
|
|
|
|
return
|
|
|
|
with open(args.pid_path, 'r') as pidFile:
|
|
|
|
pid = int(pidFile.readline())
|
|
|
|
kill(pid, SIGTERM)
|
|
|
|
log.warning("pid(%d) sigterm!", pid)
|
|
|
|
else:
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2018-08-21 11:02:09 +09:00
|
|
|
import argparse
|
|
|
|
from functools import partial
|
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
install_except_hook()
|
2018-08-21 11:02:09 +09:00
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
# 실행 플래그 파싱
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
prog='bill_man',
|
|
|
|
epilog='contact @spi-ca.',
|
|
|
|
description='report aws billing .',
|
|
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
2018-08-21 11:02:09 +09:00
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
parser.add_argument('--pid_path',
|
|
|
|
help='specify pidPath',
|
|
|
|
default='bill_man.pid')
|
|
|
|
parser.add_argument('--log_level',
|
|
|
|
help='set logging level',
|
|
|
|
type=lambda level: logging._nameToLevel[level.upper()],
|
|
|
|
choices=logging._nameToLevel.keys(),
|
|
|
|
default='INFO')
|
2018-08-21 11:02:09 +09:00
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
parser.set_defaults(func=lambda *_: parser.print_help())
|
2018-08-21 11:02:09 +09:00
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
sp = parser.add_subparsers()
|
2018-08-21 11:02:09 +09:00
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
sp_start = sp.add_parser('start', help='Starts %(prog)s daemon',
|
|
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
|
|
sp_start.add_argument('--config',
|
|
|
|
help='specify config file path',
|
|
|
|
default='bill_man.json')
|
|
|
|
sp_start.add_argument('--foreground',
|
|
|
|
help='Don\'t daemonize!',
|
|
|
|
default=False,
|
|
|
|
action='store_true')
|
|
|
|
sp_start.add_argument('--immediately',
|
|
|
|
help='run batch now!',
|
|
|
|
default=False,
|
|
|
|
action='store_true')
|
|
|
|
sp_start.add_argument('--log_location',
|
|
|
|
help='specify location of logs!',
|
|
|
|
default='log')
|
|
|
|
sp_start.add_argument('--standard_time',
|
|
|
|
help='set standard time/HHMMSS',
|
|
|
|
type=lambda ti: time(
|
|
|
|
hour=int(ti[0:2]),
|
|
|
|
minute=int(ti[2:4]),
|
|
|
|
second=int(ti[4:6]),
|
|
|
|
tzinfo=KSTTZ
|
|
|
|
),
|
|
|
|
default='120000')
|
2018-08-21 11:02:09 +09:00
|
|
|
|
|
|
|
sp_start.set_defaults(func=partial(handle_daemon, parser.prog, 'start'))
|
2018-08-21 10:27:31 +09:00
|
|
|
sp_stop = sp.add_parser('stop', help='Stop %(prog)s daemon',
|
|
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
2018-08-21 11:02:09 +09:00
|
|
|
sp_stop.set_defaults(func=partial(handle_daemon, parser.prog, 'stop'))
|
|
|
|
|
2018-08-21 10:27:31 +09:00
|
|
|
args = parser.parse_args()
|
|
|
|
args.func(args)
|