private Models.ISchedulablePlan LoadPlan(Options options) { Models.ISchedulablePlan result = null; switch (options.PlanType) { case PlanTypeEnum.Backup: result = _daoBackupPlan.Get(options.PlanIdentifier); break; case PlanTypeEnum.Restore: result = _daoRestorePlan.Get(options.PlanIdentifier); break; } return(result); }
private IBaseOperation CreateOperation(Models.ISchedulablePlan plan, Options options) { IBaseOperation result = null; switch (options.PlanType) { case PlanTypeEnum.Backup: result = CreateBackupOperation(plan as Models.BackupPlan); //result = CreateBackupOperation(plan as Models.BackupPlan); break; case PlanTypeEnum.Restore: result = CreateRestoreOperation(plan as Models.RestorePlan); //result = CreateRestoreOperation(plan as Models.RestorePlan); break; } return(result); }
public BaseOperationHelper(Models.ISchedulablePlan plan) { Plan = plan; Plan.Config.WireUpActions(); // IMPORTANT: Must be invoked before raising any plan event. }
private void Run() { // Load informed plan Models.ISchedulablePlan plan = LoadPlan(Options); if (plan == null) { logger.Fatal("The {0} plan with id {1} does not exist.", Options.PlanType.ToString().ToLowerInvariant(), Options.PlanIdentifier); ExitShowingHelpText(1); } Model = plan; if (Options.Verbose) { logger.Info("Running {0} plan #{1}", Options.PlanType.ToString().ToLowerInvariant(), Options.PlanIdentifier); } #if !DEBUG try #endif { RunningOperation = CreateOperation(plan, Options); RunningOperation.Start(); while (true) { if (!IsReleaseVersion && System.Environment.UserInteractive) { if (ConsoleAppHelper.TerminationRequestedEvent.WaitOne(1)) { if (RunningOperation != null && RunningOperation.IsRunning) { RunningOperation.Cancel(); } else { break; } } } if (RunningOperationEndedEvent.WaitOne(100)) { break; } RunningOperation.DoEvents(); } logger.Info("Operation finished."); Handler.Client.WaitUntilDone(); RunningOperation.SendReport(); } #if !DEBUG catch (Exception ex) { string message = ex.Message; Handler.Send(Commands.ReportError(0, message)); logger.Error(message); if (RunningOperation != null) { BaseOperationReport report = RunningOperation.GetReport() as BaseOperationReport; report.OperationStatus = OperationStatus.FAILED; report.AddErrorMessage(message); RunningOperation.SendReport(); } Environment.Exit(1); } #endif #if DEBUG // Wait 10 seconds before exiting, only for debugging purposes. Thread.Sleep(10000); #endif }
private void SchedulePlanExecution(Models.ISchedulablePlan plan, bool reschedule = false) { string taskName = BuildTaskName(plan); // Get the service on the local machine using (TaskService ts = new TaskService()) { // Find if there's already a task for the informed plan. Task existingTask = ts.FindTask(taskName, false); if (existingTask != null) { // Check if the plan changed after the existing task was scheduled. // It's important to convert the DateTime's to the same TimeZone before comparing them. bool changed = plan.UpdatedAt.ToLocalTime() > existingTask.Definition.RegistrationInfo.Date.ToLocalTime(); if (!changed) { return; } if (plan.IsRunManually) { Info("{0} is already scheduled - Deleting schedule because it's now Manual.", taskName); // Remove the task we found. ts.RootFolder.DeleteTask(taskName); return; } else { Info("{0} is already scheduled - {1}", taskName, reschedule ? "rescheduling..." : "rescheduling was not requested"); // If we're not rescheduling, stop now. if (!reschedule) { return; } // Do NOT delete the task we found - it will be updated by `RegisterTaskDefinition`. //ts.RootFolder.DeleteTask(taskName); } } else { if (plan.IsRunManually) { // Do not schedule anything. return; } } Info("Scheduling task {0} (plan last changed at {1})", taskName, plan.UpdatedAt.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ssK")); // If the task doesn't exist yet, create a new task definition and assign properties // This task will require Task Scheduler 2.0 (Windows >= Vista or Server >= 2008) or newer. TaskDefinition td = existingTask != null ? existingTask.Definition : ts.NewTask(); // Run this task even if the user is NOT logged on. if (td.LowestSupportedVersion == TaskCompatibility.V1) { td.Settings.RunOnlyIfLoggedOn = false; } // When running this task, use the System user account, if we have elevated privileges. if (IsElevated) { td.Principal.LogonType = TaskLogonType.InteractiveTokenOrPassword; } //td.Principal.RequiredPrivileges = new TaskPrincipalPrivilege[] { // TaskPrincipalPrivilege.SeBackupPrivilege, // TaskPrincipalPrivilege.SeRestorePrivilege, // TaskPrincipalPrivilege.SeChangeNotifyPrivilege, // TaskPrincipalPrivilege.SeCreateSymbolicLinkPrivilege, // TaskPrincipalPrivilege.SeManageVolumePrivilege, // TaskPrincipalPrivilege.SeCreateSymbolicLinkPrivilege, //}; // Run with highest privileges, if we have elevated privileges. if (IsElevated) { td.Principal.RunLevel = TaskRunLevel.Highest; } // If the task is not scheduled to run again, delete it after 24 hours -- This seem to require `EndBoundary` to be set. //td.Settings.DeleteExpiredTaskAfter = TimeSpan.FromHours(24); // Don't allow multipe instances of the task to run simultaneously. td.Settings.MultipleInstances = TaskInstancesPolicy.IgnoreNew; // Only run when a network is available. td.Settings.RunOnlyIfNetworkAvailable = true; td.RegistrationInfo.Author = string.Format(@"{0}\{1}", Environment.UserDomainName, Environment.UserName); // We identify the Scheduled task needs an update if this Date is older than `SchedulablePlan.UpdatedAt`. td.RegistrationInfo.Date = DateTime.UtcNow; string description = string.Format( "This task was automatically {0} by the {1} service at {2}", existingTask != null ? "updated" : "created", typeof(Teltec.Everest.Scheduler.Service).Namespace, td.RegistrationInfo.Date.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ssK")); td.RegistrationInfo.Description = description; // Create triggers to fire the task when planned. td.Triggers.Clear(); td.Triggers.AddRange(BuildTriggers(plan)); bool isBackup = plan is Models.BackupPlan; bool isRestore = plan is Models.RestorePlan; if (!isBackup && !isRestore) { throw new InvalidOperationException("Unhandled plan type"); } // Create an action that will launch the PlanExecutor string planType = isBackup ? PlanTypeEnum.BACKUP.ToString().ToLowerInvariant() : isRestore ? PlanTypeEnum.RESTORE.ToString().ToLowerInvariant() : string.Empty; PlanExecutorEnv env = BuildPlanExecutorEnv(planType, plan.ScheduleParamId, false); td.Actions.Clear(); td.Actions.Add(new ExecAction(env.Path, env.Arguments, env.Cwd)); // Register the task in the root folder const string username = "******"; const string password = null; const TaskLogonType logonType = TaskLogonType.ServiceAccount; try { ts.RootFolder.RegisterTaskDefinition(taskName, td, TaskCreation.CreateOrUpdate, username, password, logonType); } catch (Exception ex) { logger.Error("Failed to create/update scheduled task ({0}): {1}", taskName, ex.Message); } } }
private bool HasScheduledTask(Models.ISchedulablePlan plan) { return(HasScheduledTask(BuildTaskName(plan))); }
private Task FindScheduledTask(Models.ISchedulablePlan plan) { return(FindScheduledTask(BuildTaskName(plan))); }
private Trigger[] BuildTriggers(Models.ISchedulablePlan plan) { List <Trigger> triggers = new List <Trigger>(); Models.PlanSchedule schedule = plan.Schedule; switch (schedule.ScheduleType) { case Models.ScheduleTypeEnum.RUN_MANUALLY: { break; } case Models.ScheduleTypeEnum.SPECIFIC: { DateTime?optional = schedule.OccursSpecificallyAt; if (!optional.HasValue) { break; } DateTime whenToStart = optional.Value; Trigger tr = Trigger.CreateTrigger(TaskTriggerType.Time); // When to start? tr.StartBoundary = whenToStart.ToLocalTime(); triggers.Add(tr); break; } case Models.ScheduleTypeEnum.RECURRING: { if (!schedule.RecurrencyFrequencyType.HasValue) { break; } Trigger tr = null; switch (schedule.RecurrencyFrequencyType.Value) { case Models.FrequencyTypeEnum.DAILY: { tr = Trigger.CreateTrigger(TaskTriggerType.Daily); if (schedule.IsRecurrencyDailyFrequencySpecific) { // Repetition - Occurs every day tr.Repetition.Interval = TimeSpan.FromDays(1); } break; } case Models.FrequencyTypeEnum.WEEKLY: { if (schedule.OccursAtDaysOfWeek == null || schedule.OccursAtDaysOfWeek.Count == 0) { break; } tr = Trigger.CreateTrigger(TaskTriggerType.Weekly); WeeklyTrigger wt = tr as WeeklyTrigger; // IMPORTANT: The default constructed `WeeklyTrigger` sets Sunday. wt.DaysOfWeek = 0; Models.PlanScheduleDayOfWeek matchDay = null; matchDay = schedule.OccursAtDaysOfWeek.SingleOrDefault(p => p.DayOfWeek == DayOfWeek.Monday); if (matchDay != null) { wt.DaysOfWeek |= DaysOfTheWeek.Monday; } matchDay = schedule.OccursAtDaysOfWeek.SingleOrDefault(p => p.DayOfWeek == DayOfWeek.Tuesday); if (matchDay != null) { wt.DaysOfWeek |= DaysOfTheWeek.Tuesday; } matchDay = schedule.OccursAtDaysOfWeek.SingleOrDefault(p => p.DayOfWeek == DayOfWeek.Wednesday); if (matchDay != null) { wt.DaysOfWeek |= DaysOfTheWeek.Wednesday; } matchDay = schedule.OccursAtDaysOfWeek.SingleOrDefault(p => p.DayOfWeek == DayOfWeek.Thursday); if (matchDay != null) { wt.DaysOfWeek |= DaysOfTheWeek.Thursday; } matchDay = schedule.OccursAtDaysOfWeek.SingleOrDefault(p => p.DayOfWeek == DayOfWeek.Friday); if (matchDay != null) { wt.DaysOfWeek |= DaysOfTheWeek.Friday; } matchDay = schedule.OccursAtDaysOfWeek.SingleOrDefault(p => p.DayOfWeek == DayOfWeek.Saturday); if (matchDay != null) { wt.DaysOfWeek |= DaysOfTheWeek.Saturday; } matchDay = schedule.OccursAtDaysOfWeek.SingleOrDefault(p => p.DayOfWeek == DayOfWeek.Sunday); if (matchDay != null) { wt.DaysOfWeek |= DaysOfTheWeek.Sunday; } break; } case Models.FrequencyTypeEnum.MONTHLY: { if (!schedule.MonthlyOccurrenceType.HasValue || !schedule.OccursMonthlyAtDayOfWeek.HasValue) { break; } tr = Trigger.CreateTrigger(TaskTriggerType.MonthlyDOW); MonthlyDOWTrigger mt = tr as MonthlyDOWTrigger; switch (schedule.MonthlyOccurrenceType.Value) { case Models.MonthlyOccurrenceTypeEnum.FIRST: mt.WeeksOfMonth = WhichWeek.FirstWeek; break; case Models.MonthlyOccurrenceTypeEnum.SECOND: mt.WeeksOfMonth = WhichWeek.SecondWeek; break; case Models.MonthlyOccurrenceTypeEnum.THIRD: mt.WeeksOfMonth = WhichWeek.ThirdWeek; break; case Models.MonthlyOccurrenceTypeEnum.FOURTH: mt.WeeksOfMonth = WhichWeek.FourthWeek; break; case Models.MonthlyOccurrenceTypeEnum.PENULTIMATE: mt.WeeksOfMonth = WhichWeek.ThirdWeek; break; case Models.MonthlyOccurrenceTypeEnum.LAST: mt.WeeksOfMonth = WhichWeek.LastWeek; break; } switch (schedule.OccursMonthlyAtDayOfWeek.Value) { case DayOfWeek.Monday: mt.DaysOfWeek = DaysOfTheWeek.Monday; break; case DayOfWeek.Tuesday: mt.DaysOfWeek = DaysOfTheWeek.Tuesday; break; case DayOfWeek.Wednesday: mt.DaysOfWeek = DaysOfTheWeek.Wednesday; break; case DayOfWeek.Thursday: mt.DaysOfWeek = DaysOfTheWeek.Thursday; break; case DayOfWeek.Friday: mt.DaysOfWeek = DaysOfTheWeek.Friday; break; case DayOfWeek.Saturday: mt.DaysOfWeek = DaysOfTheWeek.Saturday; break; case DayOfWeek.Sunday: mt.DaysOfWeek = DaysOfTheWeek.Sunday; break; } break; } case Models.FrequencyTypeEnum.DAY_OF_MONTH: { if (!schedule.OccursAtDayOfMonth.HasValue) { break; } tr = Trigger.CreateTrigger(TaskTriggerType.Monthly); MonthlyTrigger mt = tr as MonthlyTrigger; // // TODO: What happens if the specified day is >=29 and we are in February? // mt.DaysOfMonth = new int[] { schedule.OccursAtDayOfMonth.Value }; break; } } if (tr == null) { break; } // When to start? DateTime now = DateTime.UtcNow; if (schedule.IsRecurrencyDailyFrequencySpecific) { TimeSpan?optional = schedule.RecurrencySpecificallyAtTime; if (!optional.HasValue) { break; } TimeSpan time = optional.Value; tr.StartBoundary = new DateTime(now.Year, now.Month, now.Day, time.Hours, time.Minutes, time.Seconds); } else { tr.StartBoundary = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0); // Start of day. } // Repetition - Occurs every interval if (!schedule.IsRecurrencyDailyFrequencySpecific) { switch (schedule.RecurrencyTimeUnit.Value) { case Models.TimeUnitEnum.HOURS: tr.Repetition.Interval = TimeSpan.FromHours(schedule.RecurrencyTimeInterval.Value); break; case Models.TimeUnitEnum.MINUTES: tr.Repetition.Interval = TimeSpan.FromMinutes(schedule.RecurrencyTimeInterval.Value); break; } } // Window limits if (!schedule.IsRecurrencyDailyFrequencySpecific) { if (schedule.RecurrencyWindowStartsAtTime.HasValue && schedule.RecurrencyWindowEndsAtTime.HasValue) { tr.Repetition.StopAtDurationEnd = false; TimeSpan window = schedule.RecurrencyWindowEndsAtTime.Value - schedule.RecurrencyWindowStartsAtTime.Value; tr.Repetition.Duration = window; //tr.ExecutionTimeLimit = window; } } triggers.Add(tr); break; } } if (triggers.Count == 0) { Warn("No task was created for {0}", BuildTaskName(plan)); } return(triggers.ToArray()); }
private string BuildTaskName(Models.ISchedulablePlan plan) { return(plan.ScheduleParamName); }