/**
  * Gets the state of the automated backup system.
  *
  * @global moodle_database $DB
  * @return int One of self::STATE_*
  */
 public static function get_automated_backup_state($rundirective = self::RUN_ON_SCHEDULE)
 {
     global $DB;
     $config = get_config('backup');
     $active = (int) $config->backup_auto_active;
     $weekdays = (string) $config->backup_auto_weekdays;
     // In case of automated backup also check that it is scheduled for at least one weekday.
     if ($active === self::AUTO_BACKUP_DISABLED || $rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL || $rundirective == self::RUN_ON_SCHEDULE && strpos($weekdays, '1') === false) {
         return self::STATE_DISABLED;
     } else {
         if (!empty($config->backup_auto_running)) {
             // Detect if the backup_auto_running semaphore is a valid one
             // by looking for recent activity in the backup_controllers table
             // for backups of type backup::MODE_AUTOMATED
             $timetosee = 60 * 90;
             // Time to consider in order to clean the semaphore
             $params = array('purpose' => backup::MODE_AUTOMATED, 'timetolook' => time() - $timetosee);
             if ($DB->record_exists_select('backup_controllers', "operation = 'backup' AND type = 'course' AND purpose = :purpose AND timemodified > :timetolook", $params)) {
                 return self::STATE_RUNNING;
                 // Recent activity found, still running
             } else {
                 // No recent activity found, let's clean the semaphore
                 mtrace('Automated backups activity not found in last ' . (int) $timetosee / 60 . ' minutes. Cleaning running status');
                 backup_cron_automated_helper::set_state_running(false);
             }
         }
     }
     return self::STATE_OK;
 }
Ejemplo n.º 2
0
    /**
     * Runs the automated backups if required
     *
     * @global moodle_database $DB
     */
    public static function run_automated_backup($rundirective = self::RUN_ON_SCHEDULE) {
        global $CFG, $DB;

        $status = true;
        $emailpending = false;
        $now = time();

        mtrace("Checking automated backup status",'...');
        $state = backup_cron_automated_helper::get_automated_backup_state($rundirective);
        if ($state === backup_cron_automated_helper::STATE_DISABLED) {
            mtrace('INACTIVE');
            return $state;
        } else if ($state === backup_cron_automated_helper::STATE_RUNNING) {
            mtrace('RUNNING');
            if ($rundirective == self::RUN_IMMEDIATELY) {
                mtrace('automated backups are already. If this script is being run by cron this constitues an error. You will need to increase the time between executions within cron.');
            } else {
                mtrace("automated backup are already running. Execution delayed");
            }
            return $state;
        } else {
            mtrace('OK');
        }
        backup_cron_automated_helper::set_state_running();

        mtrace("Getting admin info");
        $admin = get_admin();
        if (!$admin) {
            mtrace("Error: No admin account was found");
            $state = false;
        }

        if ($status) {
            mtrace("Checking courses");
            mtrace("Skipping deleted courses", '...');
            mtrace(sprintf("%d courses", backup_cron_automated_helper::remove_deleted_courses_from_schedule()));
        }

        if ($status) {

            mtrace('Running required automated backups...');

            // This could take a while!
            @set_time_limit(0);
            raise_memory_limit(MEMORY_EXTRA);

            $nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup($admin->timezone, $now);
            $showtime = "undefined";
            if ($nextstarttime > 0) {
                $showtime = userdate($nextstarttime,"",$admin->timezone);
            }

            $rs = $DB->get_recordset('course');
            foreach ($rs as $course) {
                $backupcourse = $DB->get_record('backup_courses', array('courseid'=>$course->id));
                if (!$backupcourse) {
                    $backupcourse = new stdClass;
                    $backupcourse->courseid = $course->id;
                    $DB->insert_record('backup_courses',$backupcourse);
                    $backupcourse = $DB->get_record('backup_courses', array('courseid'=>$course->id));
                }

                // Skip backup of unavailable courses that have remained unmodified in a month
                $skipped = false;
                if (empty($course->visible) && ($now - $course->timemodified) > 31*24*60*60) {  //Hidden + unmodified last month
                    $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
                    $DB->update_record('backup_courses', $backupcourse);
                    mtrace('Skipping unchanged course '.$course->fullname);
                    $skipped = true;
                } else if (($backupcourse->nextstarttime >= 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY) {
                    mtrace('Backing up '.$course->fullname, '...');

                    //We have to send a email because we have included at least one backup
                    $emailpending = true;

                    //Only make the backup if laststatus isn't 2-UNFINISHED (uncontrolled error)
                    if ($backupcourse->laststatus != 2) {
                        //Set laststarttime
                        $starttime = time();

                        $backupcourse->laststarttime = time();
                        $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED;
                        $DB->update_record('backup_courses', $backupcourse);

                        $backupcourse->laststatus = backup_cron_automated_helper::launch_automated_backup($course, $backupcourse->laststarttime, $admin->id);
                        $backupcourse->lastendtime = time();
                        $backupcourse->nextstarttime = $nextstarttime;

                        $DB->update_record('backup_courses', $backupcourse);

                        if ($backupcourse->laststatus) {
                            // Clean up any excess course backups now that we have
                            // taken a successful backup.
                            $removedcount = backup_cron_automated_helper::remove_excess_backups($course);
                        }
                    }

                    mtrace("complete - next execution: $showtime");
                }
            }
            $rs->close();
        }

        //Send email to admin if necessary
        if ($emailpending) {
            mtrace("Sending email to admin");
            $message = "";

            $count = backup_cron_automated_helper::get_backup_status_array();
            $haserrors = ($count[backup_cron_automated_helper::BACKUP_STATUS_ERROR] != 0 || $count[backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED] != 0);

            //Build the message text
            //Summary
            $message .= get_string('summary')."\n";
            $message .= "==================================================\n";
            $message .= "  ".get_string('courses').": ".array_sum($count)."\n";
            $message .= "  ".get_string('ok').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_OK]."\n";
            $message .= "  ".get_string('skipped').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_SKIPPED]."\n";
            $message .= "  ".get_string('error').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_ERROR]."\n";
            $message .= "  ".get_string('unfinished').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED]."\n\n";

            //Reference
            if ($haserrors) {
                $message .= "  ".get_string('backupfailed')."\n\n";
                $dest_url = "$CFG->wwwroot/$CFG->admin/report/backups/index.php";
                $message .= "  ".get_string('backuptakealook','',$dest_url)."\n\n";
                //Set message priority
                $admin->priority = 1;
                //Reset unfinished to error
                $DB->set_field('backup_courses','laststatus','0', array('laststatus'=>'2'));
            } else {
                $message .= "  ".get_string('backupfinished')."\n";
            }

            //Build the message subject
            $site = get_site();
            $prefix = $site->shortname.": ";
            if ($haserrors) {
                $prefix .= "[".strtoupper(get_string('error'))."] ";
            }
            $subject = $prefix.get_string('automatedbackupstatus', 'backup');

            //Send the message
            $eventdata = new stdClass();
            $eventdata->modulename        = 'moodle';
            $eventdata->userfrom          = $admin;
            $eventdata->userto            = $admin;
            $eventdata->subject           = $subject;
            $eventdata->fullmessage       = $message;
            $eventdata->fullmessageformat = FORMAT_PLAIN;
            $eventdata->fullmessagehtml   = '';
            $eventdata->smallmessage      = '';

            $eventdata->component         = 'moodle';
            $eventdata->name         = 'backup';

            message_send($eventdata);
        }

        //Everything is finished stop backup_auto_running
        backup_cron_automated_helper::set_state_running(false);

        mtrace('Automated backups complete.');

        return $status;
    }