Blob Blame History Raw
From 475b0ff983f3eece51641bb49983295e54187599 Mon Sep 17 00:00:00 2001
From: Avra Sengupta <asengupt@redhat.com>
Date: Fri, 29 May 2015 18:11:01 +0530
Subject: [PATCH 06/18] snapshot/scheduler: Return proper error code in case of
 failure

    Backport of http://review.gluster.org/#/c/11005/

ENUM                              RETCODE     ERROR
----------------------------------------------------------
INTERNAL_ERROR                    2           Internal Error
SHARED_STORAGE_DIR_DOESNT_EXIST   3           Shared Storage Dir
                                              does not exist
SHARED_STORAGE_NOT_MOUNTED        4           Shared storage is not mounted
ANOTHER_TRANSACTION_IN_PROGRESS   5           Another transaction is in progress
INIT_FAILED                       6           Initialisation failed
SCHEDULING_ALREADY_DISABLED       7           Scheduler is already disabled
SCHEDULING_ALREADY_ENABLED        8           Scheduler is already enabled
NODE_NOT_INITIALISED              9           Node not initialised
ANOTHER_SCHEDULER_ACTIVE          10          Another scheduler is active
JOB_ALREADY_EXISTS                11          Job already exists
JOB_NOT_FOUND                     12          Job not found
INVALID_JOBNAME                   13          Jobname is invalid
INVALID_VOLNAME                   14          Volname is invalid
INVALID_SCHEDULE                  15          Schedule is invalid
INVALID_ARG                       16          Argument is invalid

Change-Id: Ia1da166659099f4c951fcdb4d755529e41167b80
BUG: 1223206
Signed-off-by: Avra Sengupta <asengupt@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/50090
Reviewed-by: Rajesh Joseph <rjoseph@redhat.com>
Tested-by: Rajesh Joseph <rjoseph@redhat.com>
---
 extras/snap_scheduler/snap_scheduler.py | 142 ++++++++++++++++++--------------
 1 file changed, 81 insertions(+), 61 deletions(-)

diff --git a/extras/snap_scheduler/snap_scheduler.py b/extras/snap_scheduler/snap_scheduler.py
index e7c1791..1c5f938 100755
--- a/extras/snap_scheduler/snap_scheduler.py
+++ b/extras/snap_scheduler/snap_scheduler.py
@@ -38,6 +38,21 @@ tasks = {}
 longest_field = 12
 current_scheduler = ""
 
+INTERNAL_ERROR = 2
+SHARED_STORAGE_DIR_DOESNT_EXIST = 3
+SHARED_STORAGE_NOT_MOUNTED = 4
+ANOTHER_TRANSACTION_IN_PROGRESS = 5
+INIT_FAILED = 6
+SCHEDULING_ALREADY_DISABLED = 7
+SCHEDULING_ALREADY_ENABLED = 8
+NODE_NOT_INITIALISED = 9
+ANOTHER_SCHEDULER_ACTIVE = 10
+JOB_ALREADY_EXISTS = 11
+JOB_NOT_FOUND = 12
+INVALID_JOBNAME = 13
+INVALID_VOLNAME = 14
+INVALID_SCHEDULE = 15
+INVALID_ARG = 16
 
 def output(msg):
     print("%s: %s" % (SCRIPT_NAME, msg))
@@ -66,7 +81,7 @@ def initLogger():
 
 
 def scheduler_status():
-    success = False
+    ret = INTERNAL_ERROR
     global scheduler_enabled
     try:
         f = os.path.realpath(GCRON_TASKS)
@@ -76,33 +91,32 @@ def scheduler_status():
         else:
             log.info("Snapshot scheduler is currently enabled.")
             scheduler_enabled = True
-        success = True
+        ret = 0
     except:
         log.error("Failed to enable snapshot scheduling. Error: "
                   "Failed to check the status of %s.", GCRON_DISABLED)
 
-    return success
+    return ret
 
 def enable_scheduler():
     ret = scheduler_status()
-    if ret:
+    if ret == 0:
         if not scheduler_enabled:
 
             # Check if another scheduler is active.
             ret = get_current_scheduler()
-            if ret:
+            if ret == 0:
                 if (current_scheduler != "none"):
                     print_str = "Failed to enable snapshot scheduling. " \
                                 "Error: Another scheduler is active."
                     log.error(print_str)
                     output(print_str)
-                    ret = False
+                    ret = ANOTHER_SCHEDULER_ACTIVE
                     return ret
             else:
                 print_str = "Failed to get current scheduler info."
                 log.error(print_str)
                 output(print_str)
-                ret = False
                 return ret
 
             log.info("Enabling snapshot scheduler.")
@@ -118,23 +132,24 @@ def enable_scheduler():
                 except IOError as (errno, strerror):
                     log.error("Failed to open %s. Error: %s.",
                               GCRON_ENABLED, strerror)
-                    ret = False
+                    ret = INTERNAL_ERROR
                     return ret
                 os.symlink(GCRON_ENABLED, GCRON_TASKS)
                 update_current_scheduler("cli")
                 log.info("Snapshot scheduling is enabled")
                 output("Snapshot scheduling is enabled")
+                ret = 0
             except IOError as (errno, strerror):
                 print_str = "Failed to enable snapshot scheduling. Error: "+strerror
                 log.error(print_str)
                 output(print_str)
-                ret = False
+                ret = INTERNAL_ERROR
         else:
             print_str = "Failed to enable snapshot scheduling. " \
                         "Error: Snapshot scheduling is already enabled."
             log.error(print_str)
             output(print_str)
-            ret = False
+            ret = SCHEDULING_ALREADY_ENABLED
     else:
         print_str = "Failed to enable snapshot scheduling. " \
                     "Error: Failed to check scheduler status."
@@ -146,14 +161,14 @@ def enable_scheduler():
 
 def disable_scheduler():
     ret = scheduler_status()
-    if ret:
+    if ret == 0:
         if scheduler_enabled:
             log.info("Disabling snapshot scheduler.")
             try:
                 # Check if another scheduler is active. If not, then
                 # update current scheduler to "none". Else do nothing.
                 ret = get_current_scheduler()
-                if ret:
+                if ret == 0:
                     if (current_scheduler == "cli"):
                         update_current_scheduler("none")
                 else:
@@ -161,7 +176,6 @@ def disable_scheduler():
                                 "Error: Failed to get current scheduler info."
                     log.error(print_str)
                     output(print_str)
-                    ret = False
                     return ret
 
                 if os.path.exists(GCRON_DISABLED):
@@ -173,22 +187,24 @@ def disable_scheduler():
                 os.symlink(GCRON_DISABLED, GCRON_TASKS)
                 log.info("Snapshot scheduling is disabled")
                 output("Snapshot scheduling is disabled")
+                ret = 0
             except IOError as (errno, strerror):
                 print_str = "Failed to disable snapshot scheduling. Error: "+strerror
                 log.error(print_str)
                 output(print_str)
-                ret = False
+                ret = INTERNAL_ERROR
         else:
             print_str = "Failed to disable scheduling. " \
                         "Error: Snapshot scheduling is already disabled."
             log.error(print_str)
             output(print_str)
-            ret = False
+            ret = SCHEDULING_ALREADY_DISABLED
     else:
         print_str = "Failed to disable snapshot scheduling. " \
                     "Error: Failed to check scheduler status."
         log.error(print_str)
         output(print_str)
+        ret = INTERNAL_ERROR
 
     return ret
 
@@ -211,10 +227,10 @@ def load_tasks_from_file():
                                     len(schedule))
                 tasks[jobname] = schedule+":"+volname
             f.close()
-        ret = True
+        ret = 0
     except IOError as (errno, strerror):
         log.error("Failed to open %s. Error: %s.", GCRON_ENABLED, strerror)
-        ret = False
+        ret = INTERNAL_ERROR
 
     return ret
 
@@ -225,10 +241,10 @@ def get_current_scheduler():
         with open(CURRENT_SCHEDULER, 'r') as f:
             current_scheduler = f.readline().rstrip('\n')
             f.close()
-        ret = True
+        ret = 0
     except IOError as (errno, strerror):
         log.error("Failed to open %s. Error: %s.", CURRENT_SCHEDULER, strerror)
-        ret = False
+        ret = INTERNAL_ERROR
 
     return ret
 
@@ -236,7 +252,7 @@ def get_current_scheduler():
 def list_schedules():
     log.info("Listing snapshot schedules.")
     ret = load_tasks_from_file()
-    if ret:
+    if ret == 0:
         if len(tasks) == 0:
             output("No snapshots scheduled")
         else:
@@ -255,6 +271,7 @@ def list_schedules():
                           longest_field + 5)
                 operation = "Snapshot Create".ljust(longest_field+5)
                 print(jobname+schedule+operation+volname)
+            ret = 0
     else:
         print_str = "Failed to list snapshot schedules. " \
                     "Error: Failed to load tasks from "+GCRON_ENABLED
@@ -265,7 +282,6 @@ def list_schedules():
 
 
 def write_tasks_to_file():
-    ret = False
     try:
         with open(TMP_FILE, "w", 0644) as f:
             # If tasks is empty, just create an empty tmp file
@@ -282,16 +298,15 @@ def write_tasks_to_file():
             f.close()
     except IOError as (errno, strerror):
         log.error("Failed to open %s. Error: %s.", TMP_FILE, strerror)
-        ret = False
+        ret = INTERNAL_ERROR
         return ret
 
     shutil.move(TMP_FILE, GCRON_ENABLED)
-    ret = True
+    ret = 0
 
     return ret
 
 def update_current_scheduler(data):
-    ret = False
     try:
         with open(TMP_FILE, "w", 0644) as f:
             f.write("%s" % data)
@@ -300,11 +315,11 @@ def update_current_scheduler(data):
             f.close()
     except IOError as (errno, strerror):
         log.error("Failed to open %s. Error: %s.", TMP_FILE, strerror)
-        ret = False
+        ret = INTERNAL_ERROR
         return ret
 
     shutil.move(TMP_FILE, CURRENT_SCHEDULER)
-    ret = True
+    ret = 0
 
     return ret
 
@@ -312,17 +327,17 @@ def update_current_scheduler(data):
 def add_schedules(jobname, schedule, volname):
     log.info("Adding snapshot schedules.")
     ret = load_tasks_from_file()
-    if ret:
+    if ret == 0:
         if jobname in tasks:
             print_str = ("%s already exists in schedule. Use "
                          "'edit' to modify %s" % (jobname, jobname))
             log.error(print_str)
             output(print_str)
-            ret = False
+            ret = JOB_ALREADY_EXISTS
         else:
             tasks[jobname] = schedule + ":" + volname
             ret = write_tasks_to_file()
-            if ret:
+            if ret == 0:
                 # Create a LOCK_FILE for the job
                 job_lockfile = LOCK_FILE_DIR + jobname
                 try:
@@ -331,10 +346,11 @@ def add_schedules(jobname, schedule, volname):
                 except IOError as (errno, strerror):
                     log.error("Failed to open %s. Error: %s.",
                               job_lockfile, strerror)
-                    ret = False
+                    ret = INTERNAL_ERROR
                     return ret
                 log.info("Successfully added snapshot schedule %s" % jobname)
                 output("Successfully added snapshot schedule")
+                ret = 0
     else:
         print_str = "Failed to add snapshot schedule. " \
                     "Error: Failed to load tasks from "+GCRON_ENABLED
@@ -347,11 +363,11 @@ def add_schedules(jobname, schedule, volname):
 def delete_schedules(jobname):
     log.info("Delete snapshot schedules.")
     ret = load_tasks_from_file()
-    if ret:
+    if ret == 0:
         if jobname in tasks:
             del tasks[jobname]
             ret = write_tasks_to_file()
-            if ret:
+            if ret == 0:
                 # Delete the LOCK_FILE for the job
                 job_lockfile = LOCK_FILE_DIR+jobname
                 try:
@@ -359,15 +375,18 @@ def delete_schedules(jobname):
                 except IOError as (errno, strerror):
                     log.error("Failed to open %s. Error: %s.",
                               job_lockfile, strerror)
+                    ret = INTERNAL_ERROR
+                    return ret
                 log.info("Successfully deleted snapshot schedule %s"
                          % jobname)
                 output("Successfully deleted snapshot schedule")
+                ret = 0
         else:
             print_str = ("Failed to delete %s. Error: No such "
                          "job scheduled" % jobname)
             log.error(print_str)
             output(print_str)
-            ret = False
+            ret = JOB_NOT_FOUND
     else:
         print_str = "Failed to delete snapshot schedule. " \
                     "Error: Failed to load tasks from "+GCRON_ENABLED
@@ -380,11 +399,11 @@ def delete_schedules(jobname):
 def edit_schedules(jobname, schedule, volname):
     log.info("Editing snapshot schedules.")
     ret = load_tasks_from_file()
-    if ret:
+    if ret == 0:
         if jobname in tasks:
             tasks[jobname] = schedule+":"+volname
             ret = write_tasks_to_file()
-            if ret:
+            if ret == 0:
                 log.info("Successfully edited snapshot schedule %s" % jobname)
                 output("Successfully edited snapshot schedule")
         else:
@@ -392,7 +411,7 @@ def edit_schedules(jobname, schedule, volname):
                          "job scheduled" % jobname)
             log.error(print_str)
             output(print_str)
-            ret = False
+            ret = JOB_NOT_FOUND
     else:
         print_str = "Failed to edit snapshot schedule. " \
                     "Error: Failed to load tasks from "+GCRON_ENABLED
@@ -413,7 +432,7 @@ def initialise_scheduler():
             f.close()
     except IOError as (errno, strerror):
         log.error("Failed to open /tmp/crontab. Error: %s.", strerror)
-        ret = False
+        ret = INIT_FAILED
         return ret
 
     shutil.move("/tmp/crontab", GCRON_UPDATE_TASK)
@@ -424,7 +443,7 @@ def initialise_scheduler():
             f.close()
         except IOError as (errno, strerror):
             log.error("Failed to open %s. Error: %s.", GCRON_TASKS, strerror)
-            ret = False
+            ret = INIT_FAILED
             return ret
 
     if os.path.lexists(GCRON_CROND_TASK):
@@ -435,22 +454,22 @@ def initialise_scheduler():
     log.info("Successfully inited snapshot scheduler for this node")
     output("Successfully inited snapshot scheduler for this node")
 
-    ret = True
+    ret = 0
     return ret
 
 
 def syntax_checker(args):
-    ret = False
-
     if hasattr(args, 'jobname'):
         if (len(args.jobname.split()) != 1):
             output("Invalid Jobname. Jobname should not be empty and should not contain \" \" character.")
+            ret = INVALID_JOBNAME
             return ret
         args.jobname=args.jobname.strip()
 
     if hasattr(args, 'volname'):
         if (len(args.volname.split()) != 1):
             output("Invalid Volname. Volname should not be empty and should not contain \" \" character.")
+            ret = INVALID_VOLNAME
             return ret
         args.volname=args.volname.strip()
 
@@ -464,26 +483,25 @@ def syntax_checker(args):
             print ("| | +-------- Day of the Month  (range: 1-31)")
             print ("| +---------- Hour              (range: 0-23)")
             print ("+------------ Minute            (range: 0-59)")
+            ret = INVALID_SCHEDULE
             return ret
 
-    ret = True
+    ret = 0
     return ret
 
 
 def perform_operation(args):
-    ret = False
-
     # Initialise snapshot scheduler on local node
     if args.action == "init":
         ret = initialise_scheduler()
-        if not ret:
+        if ret != 0:
             output("Failed to initialise snapshot scheduling")
         return ret
 
     # Disable snapshot scheduler
     if args.action == "disable_force":
         ret = disable_scheduler()
-        if ret:
+        if ret == 0:
             subprocess.Popen(["touch", "-h", GCRON_TASKS])
         return ret
 
@@ -495,12 +513,13 @@ def perform_operation(args):
                      "the snap scheduler for the local node.")
         log.error(print_str)
         output(print_str)
+        ret = NODE_NOT_INITIALISED
         return ret
 
     # Check status of snapshot scheduler.
     if args.action == "status":
         ret = scheduler_status()
-        if ret:
+        if ret == 0:
             if scheduler_enabled:
                 output("Snapshot scheduling status: Enabled")
             else:
@@ -512,14 +531,14 @@ def perform_operation(args):
     # Enable snapshot scheduler
     if args.action == "enable":
         ret = enable_scheduler()
-        if ret:
+        if ret == 0:
             subprocess.Popen(["touch", "-h", GCRON_TASKS])
         return ret
 
     # Disable snapshot scheduler
     if args.action == "disable":
         ret = disable_scheduler()
-        if ret:
+        if ret == 0:
             subprocess.Popen(["touch", "-h", GCRON_TASKS])
         return ret
 
@@ -531,33 +550,34 @@ def perform_operation(args):
     # Add snapshot schedules
     if args.action == "add":
         ret = syntax_checker(args)
-        if not ret:
+        if ret != 0:
             return ret
         ret = add_schedules(args.jobname, args.schedule, args.volname)
-        if ret:
+        if ret == 0:
             subprocess.Popen(["touch", "-h", GCRON_TASKS])
         return ret
 
     # Delete snapshot schedules
     if args.action == "delete":
         ret = syntax_checker(args)
-        if not ret:
+        if ret != 0:
             return ret
         ret = delete_schedules(args.jobname)
-        if ret:
+        if ret == 0:
             subprocess.Popen(["touch", "-h", GCRON_TASKS])
         return ret
 
     # Edit snapshot schedules
     if args.action == "edit":
         ret = syntax_checker(args)
-        if not ret:
+        if ret != 0:
             return ret
         ret = edit_schedules(args.jobname, args.schedule, args.volname)
-        if ret:
+        if ret == 0:
             subprocess.Popen(["touch", "-h", GCRON_TASKS])
         return ret
 
+    ret = INVALID_ARG
     return ret
 
 
@@ -601,11 +621,11 @@ def main():
 
     if not os.path.exists(SHARED_STORAGE_DIR):
         output("Failed: "+SHARED_STORAGE_DIR+" does not exist.")
-        return ret
+        return SHARED_STORAGE_DIR_DOESNT_EXIST
 
     if not os.path.ismount(SHARED_STORAGE_DIR):
         output("Failed: Shared storage is not mounted at "+SHARED_STORAGE_DIR)
-        return ret
+        return SHARED_STORAGE_NOT_MOUNTED
 
     if not os.path.exists(SHARED_STORAGE_DIR+"/snaps/"):
         try:
@@ -615,6 +635,7 @@ def main():
                 log.error("Failed to create %s : %s", SHARED_STORAGE_DIR+"/snaps/", strerror)
                 output("Failed to create %s. Error: %s"
                        % (SHARED_STORAGE_DIR+"/snaps/", strerror))
+                return INTERNAL_ERROR
 
     if not os.path.exists(GCRON_ENABLED):
         f = os.open(GCRON_ENABLED, os.O_CREAT | os.O_NONBLOCK, 0644)
@@ -628,6 +649,7 @@ def main():
                 log.error("Failed to create %s : %s", LOCK_FILE_DIR, strerror)
                 output("Failed to create %s. Error: %s"
                        % (LOCK_FILE_DIR, strerror))
+                return INTERNAL_ERROR
 
     if not os.path.exists(CURRENT_SCHEDULER):
         update_current_scheduler("none")
@@ -637,19 +659,17 @@ def main():
         try:
             fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
             ret = perform_operation(args)
-            if not ret:
-                ret = 1
-            else:
-                ret = 0
             fcntl.flock(f, fcntl.LOCK_UN)
         except IOError as (errno, strerror):
             log.info("%s is being processed by another agent.", LOCK_FILE)
             output("Another snap_scheduler command is running. "
                    "Please try again after some time.")
+            return ANOTHER_TRANSACTION_IN_PROGRESS
         os.close(f)
     except IOError as (errno, strerror):
         log.error("Failed to open %s : %s", LOCK_FILE, strerror)
         output("Failed to open %s. Error: %s" % (LOCK_FILE, strerror))
+        return INTERNAL_ERROR
 
     return ret
 
-- 
1.9.3