glusterfs
190 строк · 6.5 Кб
1#!/usr/bin/python3
2#
3# Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
4# This file is part of GlusterFS.
5#
6# This file is licensed to you under your choice of the GNU Lesser
7# General Public License, version 3 or any later version (LGPLv3 or
8# later), or the GNU General Public License, version 2 (GPLv2), in all
9# cases as published by the Free Software Foundation.
10
11from __future__ import print_function12import subprocess13import os14import os.path15import sys16import time17import logging18import logging.handlers19import fcntl20
21
22GCRON_TASKS = "/run/gluster/shared_storage/snaps/glusterfs_snap_cron_tasks"23GCRON_CROND_TASK = "/etc/cron.d/glusterfs_snap_cron_tasks"24GCRON_RELOAD_FLAG = "/var/run/gluster/crond_task_reload_flag"25LOCK_FILE_DIR = "/run/gluster/shared_storage/snaps/lock_files/"26log = logging.getLogger("gcron-logger")27start_time = 0.028
29
30def initLogger(script_name):31log.setLevel(logging.DEBUG)32logFormat = "[%(asctime)s %(filename)s:%(lineno)s %(funcName)s] "\33"%(levelname)s %(message)s"34formatter = logging.Formatter(logFormat)35
36sh = logging.handlers.SysLogHandler()37sh.setLevel(logging.ERROR)38sh.setFormatter(formatter)39
40process = subprocess.Popen(["gluster", "--print-logdir"],41stdout=subprocess.PIPE,42universal_newlines=True)43out, err = process.communicate()44if process.returncode == 0:45logfile = os.path.join(out.strip(), script_name[:-3]+".log")46
47fh = logging.FileHandler(logfile)48fh.setLevel(logging.DEBUG)49fh.setFormatter(formatter)50
51log.addHandler(sh)52log.addHandler(fh)53
54
55def takeSnap(volname="", snapname=""):56success = True57if volname == "":58log.debug("No volname given")59return False60if snapname == "":61log.debug("No snapname given")62return False63
64cli = ["gluster",65"snapshot",66"create",67snapname,68volname]69log.debug("Running command '%s'", " ".join(cli))70
71p = subprocess.Popen(cli, stdout=subprocess.PIPE,72stderr=subprocess.PIPE)73out, err = p.communicate()74rv = p.returncode75
76log.debug("Command '%s' returned '%d'", " ".join(cli), rv)77
78if rv:79log.error("Snapshot of %s failed", volname)80log.error("Command output:")81log.error(err)82success = False83else:84log.info("Snapshot of %s successful", volname)85
86return success87
88
89def doJob(name, lockFile, jobFunc, volname):90success = True91try:92f = os.open(lockFile, os.O_CREAT | os.O_RDWR | os.O_NONBLOCK)93try:94fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)95mtime = os.path.getmtime(lockFile)96global start_time97log.debug("%s last modified at %s", lockFile, time.ctime(mtime))98if mtime < start_time:99log.debug("Processing job %s", name)100if jobFunc(volname, name):101log.info("Job %s succeeded", name)102else:103log.error("Job %s failed", name)104success = False105os.utime(lockFile, None)106else:107log.info("Job %s has been processed already", name)108fcntl.flock(f, fcntl.LOCK_UN)109except (OSError, IOError):110log.info("Job %s is being processed by another agent", name)111os.close(f)112except (OSError, IOError) as e:113log.debug("Failed to open lock file %s : %s", lockFile, e)114log.error("Failed to process job %s", name)115success = False116
117return success118
119
120def main():121script_name = os.path.basename(__file__)122initLogger(script_name)123global start_time124if sys.argv[1] == "--update":125if not os.path.exists(GCRON_TASKS):126# Create a flag in /var/run/gluster which indicates that this127# node doesn't have access to GCRON_TASKS right now, so that128# when the mount is available and GCRON_TASKS is available129# the flag will tell this routine to reload GCRON_CROND_TASK130try:131f = os.open(GCRON_RELOAD_FLAG,132os.O_CREAT | os.O_NONBLOCK, 0o644)133os.close(f)134except OSError as e:135if errno != EEXIST:136log.error("Failed to create %s : %s",137GCRON_RELOAD_FLAG, e)138output("Failed to create %s. Error: %s"139% (GCRON_RELOAD_FLAG, e))140return141
142if not os.path.exists(GCRON_CROND_TASK):143return144
145# As GCRON_TASKS exists now, we should check if GCRON_RELOAD_FLAG146# also exists. If so we should touch GCRON_CROND_TASK and remove147# the GCRON_RELOAD_FLAG148if os.path.exists(GCRON_RELOAD_FLAG):149try:150os.remove(GCRON_RELOAD_FLAG);151process = subprocess.Popen(["touch", "-h", GCRON_CROND_TASK],152stdout=subprocess.PIPE,153stderr=subprocess.PIPE)154out, err = process.communicate()155if process.returncode != 0:156log.error("Failed to touch %s. Error: %s.",157GCRON_CROND_TASK, err)158except (IOError, OSError) as e:159log.error("Failed to touch %s. Error: %s.",160GCRON_CROND_TASK, e)161return162if os.lstat(GCRON_TASKS).st_mtime > \163os.lstat(GCRON_CROND_TASK).st_mtime:164try:165process = subprocess.Popen(["touch", "-h", GCRON_CROND_TASK],166stdout=subprocess.PIPE,167stderr=subprocess.PIPE)168out, err = process.communicate()169if process.returncode != 0:170log.error("Failed to touch %s. Error: %s.",171GCRON_CROND_TASK, err)172except IOError as e:173log.error("Failed to touch %s. Error: %s.",174GCRON_CROND_TASK, e)175return176
177volname = sys.argv[1]178jobname = sys.argv[2]179locking_file = os.path.join(LOCK_FILE_DIR, jobname)180log.debug("locking_file = %s", locking_file)181log.debug("volname = %s", volname)182log.debug("jobname = %s", jobname)183
184start_time = int(time.time())185
186doJob("Scheduled-" + jobname + "-" + volname, locking_file, takeSnap, volname)187
188
189if __name__ == "__main__":190main()191