mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 01:25:40 -05:00
* Initial non-refactored SQL Agent alert classes (WIP) * Move agent classes into subdirectories * Refactor the agent config code a bit more * Add more implementation for handlers * Add more code to the create alert handler * Clean up agent alert class * Clean up alert methods a bit * Initial Operator contracts * Additonal SQL Agent config changes * More Proxy config cleanup * Cleanup AgentProxy class * Additional cleanups * Run SRGen * Add security service to create credential objects
977 lines
32 KiB
C#
977 lines
32 KiB
C#
//
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
//
|
|
|
|
using System;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Threading;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.ComponentModel;
|
|
using System.Xml;
|
|
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
|
using Microsoft.SqlServer.Management.Common;
|
|
using Microsoft.SqlServer.Management.Diagnostics;
|
|
using Microsoft.SqlServer.Management.Smo;
|
|
using Microsoft.SqlServer.Management.Smo.Agent;
|
|
using Microsoft.SqlServer.Management.UI;
|
|
using Microsoft.SqlTools.ServiceLayer.Admin;
|
|
|
|
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
|
{
|
|
|
|
#region AgentAction class
|
|
|
|
/// <summary>
|
|
/// Main class all af the "immediate" agent actions derive from. These actions execute immediately
|
|
/// are not scriptable. We use the progress reporting dialog to give the user feedback on progress
|
|
/// etc.
|
|
/// </summary>
|
|
internal abstract class AgentAction
|
|
{
|
|
#region private members
|
|
|
|
/// <summary>
|
|
/// Required designer variable.
|
|
/// </summary>
|
|
private System.ComponentModel.IContainer components = null;
|
|
|
|
protected Microsoft.SqlServer.Management.Smo.Server smoServer = null;
|
|
protected IManagedConnection managedConnection;
|
|
protected Urn[] urnParameters;
|
|
protected STParameters param = null;
|
|
protected ProgressItemCollection actions = new ProgressItemCollection();
|
|
|
|
#endregion
|
|
|
|
protected object ActionObject;
|
|
|
|
#region construction
|
|
|
|
public AgentAction(XmlDocument document, IServiceProvider source)
|
|
: this(document, source, null)
|
|
{
|
|
}
|
|
|
|
public AgentAction(XmlDocument document, IServiceProvider source, object actionObject)
|
|
{
|
|
// parameter check
|
|
if (document == null)
|
|
{
|
|
throw new ArgumentNullException("document");
|
|
}
|
|
|
|
if (source == null)
|
|
{
|
|
throw new ArgumentNullException("source");
|
|
}
|
|
|
|
if (actionObject != null)
|
|
{
|
|
this.ActionObject = actionObject;
|
|
}
|
|
|
|
// get the managed connection
|
|
managedConnection = source.GetService(typeof (IManagedConnection)) as IManagedConnection;
|
|
|
|
// get the connection
|
|
SqlOlapConnectionInfoBase ci = managedConnection.Connection;
|
|
// get the server connection
|
|
ServerConnection serverConnection =
|
|
((SqlConnectionInfoWithConnection) managedConnection.Connection).ServerConnection;
|
|
|
|
smoServer = new Microsoft.SqlServer.Management.Smo.Server(serverConnection);
|
|
|
|
// get the list or urn's that have been passed in
|
|
param = new STParameters(document);
|
|
StringCollection urnStrings = new StringCollection();
|
|
|
|
// get a list of urns that have been passed in.
|
|
param.GetParam("urn", urnStrings);
|
|
|
|
// store the Urn's as real Urns
|
|
urnParameters = new Urn[urnStrings.Count];
|
|
for (int i = 0; i < urnStrings.Count; i++)
|
|
{
|
|
urnParameters[i] = new Urn(urnStrings[i]);
|
|
}
|
|
}
|
|
|
|
protected void OnLoad(EventArgs e)
|
|
{
|
|
// ask derived classes to build a list of actions to be
|
|
// performed. Do not remove this call from OnLoad method!
|
|
GenerateActions();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region cleanup
|
|
|
|
/// <summary>
|
|
/// Clean up any resources being used.
|
|
/// </summary>
|
|
protected void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (components != null)
|
|
{
|
|
components.Dispose();
|
|
}
|
|
}
|
|
|
|
if (this.managedConnection != null)
|
|
{
|
|
try
|
|
{
|
|
if (disposing)
|
|
{
|
|
this.managedConnection.Close();
|
|
}
|
|
this.managedConnection = null;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region abstract methods
|
|
|
|
/// <summary>
|
|
/// Generate the actions the dialog will perform. Derived classes should add
|
|
/// IAction based actions to the actions collection.
|
|
/// </summary>
|
|
protected abstract void GenerateActions();
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Enable Alerts
|
|
|
|
/// <summary>
|
|
/// Enables one or more alerts.
|
|
/// </summary>
|
|
internal class EnableAgentAlerts : AgentAction
|
|
{
|
|
public EnableAgentAlerts(XmlDocument document, IServiceProvider source)
|
|
: base(document, source)
|
|
{
|
|
}
|
|
|
|
protected override void GenerateActions()
|
|
{
|
|
if (this.smoServer != null)
|
|
{
|
|
for (int i = 0; i < this.urnParameters.Length; i++)
|
|
{
|
|
Alert alert = this.smoServer.GetSmoObject(urnParameters[i]) as Alert;
|
|
|
|
// check that the urn really points to an alert
|
|
this.actions.AddAction(new EnableAlertAction(alert));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs the actual enabling
|
|
/// </summary>
|
|
internal class EnableAlertAction : IProgressItem
|
|
{
|
|
private Alert alert;
|
|
|
|
public EnableAlertAction(Alert alert)
|
|
{
|
|
if (alert == null)
|
|
{
|
|
throw new ArgumentNullException("alert");
|
|
}
|
|
|
|
this.alert = alert;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate a user friendly description of this task.Used in the description
|
|
/// of the progress dialog.
|
|
/// </summary>
|
|
/// <returns>Description of the aler</returns>
|
|
public override string ToString()
|
|
{
|
|
if (this.alert == null)
|
|
{
|
|
return base.ToString();
|
|
}
|
|
else
|
|
{
|
|
return "AgentActionSR.EnableAlertDescription(this.alert.Name)";
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Enable the alert
|
|
/// </summary>
|
|
/// <param name="actions">Actions collection</param>
|
|
/// <param name="index">this actions index into the actions collection</param>
|
|
/// <returns></returns>
|
|
public ProgressStatus DoAction(ProgressItemCollection actions, int index)
|
|
{
|
|
//parameter check
|
|
if (actions == null)
|
|
{
|
|
throw new ArgumentNullException("actions");
|
|
}
|
|
|
|
// in progress
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.InProgress);
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.EnablingAlert(this.alert.Name)");
|
|
|
|
this.alert.IsEnabled = true;
|
|
this.alert.Alter();
|
|
|
|
// done
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.EnabledAlert(this.alert.Name)");
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.Success);
|
|
return ProgressStatus.Success;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Disable Alerts
|
|
|
|
/// <summary>
|
|
/// Disable one or more alerts
|
|
/// </summary>
|
|
internal class DisableAgentAlerts : AgentAction
|
|
{
|
|
public DisableAgentAlerts(XmlDocument document, IServiceProvider source)
|
|
: base(document, source)
|
|
{
|
|
}
|
|
|
|
protected override void GenerateActions()
|
|
{
|
|
if (this.smoServer != null)
|
|
{
|
|
for (int i = 0; i < this.urnParameters.Length; i++)
|
|
{
|
|
Alert alert = this.smoServer.GetSmoObject(urnParameters[i]) as Alert;
|
|
|
|
// check that the urn really points to an alert
|
|
this.actions.AddAction(new DisableAlertAction(alert));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Actually disable the alert
|
|
/// </summary>
|
|
internal class DisableAlertAction : IProgressItem
|
|
{
|
|
private Alert alert;
|
|
|
|
public DisableAlertAction(Alert alert)
|
|
{
|
|
if (alert == null)
|
|
{
|
|
throw new ArgumentNullException("alert");
|
|
}
|
|
|
|
this.alert = alert;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
if (this.alert == null)
|
|
{
|
|
return base.ToString();
|
|
}
|
|
else
|
|
{
|
|
return "AgentActionSR.DisableAlertDescription(this.alert.Name)";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disable the alert
|
|
/// </summary>
|
|
/// <param name="actions">Actions collection</param>
|
|
/// <param name="index">this actions index into the actions collection</param>
|
|
/// <returns></returns>
|
|
public ProgressStatus DoAction(ProgressItemCollection actions, int index)
|
|
{
|
|
//parameter check
|
|
if (actions == null)
|
|
{
|
|
throw new ArgumentNullException("actions");
|
|
}
|
|
|
|
// in progress
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.InProgress);
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.DisablingAlert(this.alert.Name)");
|
|
|
|
this.alert.IsEnabled = false;
|
|
this.alert.Alter();
|
|
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.DisabledAlert(this.alert.Name)");
|
|
|
|
/// done
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.Success);
|
|
return ProgressStatus.Success;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region JobAction
|
|
|
|
internal class JobAction : AgentAction
|
|
{
|
|
public JobAction(XmlDocument document, IServiceProvider source)
|
|
: base(document, source)
|
|
{
|
|
|
|
}
|
|
|
|
protected override void GenerateActions()
|
|
{
|
|
return;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize context for actions on Jobs
|
|
/// Job Activity monitor can call with list if jobids.
|
|
/// All other existing callers may call with list of urns
|
|
/// To support above 2 scenarios, this method in base class initializes urnParameters if it was not initialized by
|
|
/// AgentAction class's constructor
|
|
/// </summary>
|
|
protected void InitializeContext()
|
|
{
|
|
// If Urn parameters were not initialized it is possible that
|
|
// jobids were passed in by caller instead of list of urns
|
|
if (null == urnParameters || urnParameters.Length == 0)
|
|
{
|
|
StringCollection jobIdStrings = new StringCollection();
|
|
|
|
// get list of job ids that were passed in
|
|
param.GetParam("jobid", jobIdStrings);
|
|
|
|
urnParameters = new Urn[jobIdStrings.Count];
|
|
int index = 0;
|
|
if (jobIdStrings.Count > 0)
|
|
{
|
|
foreach (string jobIdString in jobIdStrings)
|
|
{
|
|
Job job = smoServer.JobServer.Jobs.ItemById(Guid.Parse(jobIdString));
|
|
urnParameters[index++] = new Urn(job.Urn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Enable Jobs
|
|
|
|
internal class EnableAgentJobs : JobAction
|
|
{
|
|
public EnableAgentJobs(XmlDocument document, IServiceProvider source)
|
|
: base(document, source)
|
|
{
|
|
}
|
|
|
|
protected override void GenerateActions()
|
|
{
|
|
if (this.smoServer != null)
|
|
{
|
|
InitializeContext();
|
|
for (int i = 0; i < this.urnParameters.Length; i++)
|
|
{
|
|
Job job = this.smoServer.GetSmoObject(urnParameters[i]) as Job;
|
|
|
|
// check that the urn really points to a Job
|
|
this.actions.AddAction(new EnableJobAction(job));
|
|
}
|
|
}
|
|
}
|
|
|
|
// class that actually enables the job
|
|
internal class EnableJobAction : IProgressItem
|
|
{
|
|
private Job job;
|
|
|
|
public EnableJobAction(Job job)
|
|
{
|
|
if (job == null)
|
|
{
|
|
throw new ArgumentNullException("job");
|
|
}
|
|
|
|
this.job = job;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate user friendly description of the action. This is displayed in the
|
|
/// progress dialog.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override string ToString()
|
|
{
|
|
if (this.job == null)
|
|
{
|
|
return base.ToString();
|
|
}
|
|
else
|
|
{
|
|
return "AgentActionSR.EnableJobDescription(this.job.Name)";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enable the Job
|
|
/// </summary>
|
|
/// <param name="actions">Actions collection</param>
|
|
/// <param name="index">this actions index into the actions collection</param>
|
|
/// <returns></returns>
|
|
public ProgressStatus DoAction(ProgressItemCollection actions, int index)
|
|
{
|
|
//parameter check
|
|
if (actions == null)
|
|
{
|
|
throw new ArgumentNullException("actions");
|
|
}
|
|
|
|
// in progress
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.InProgress);
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.EnablingJob(this.job.Name)");
|
|
|
|
this.job.IsEnabled = true;
|
|
this.job.Alter();
|
|
|
|
|
|
// done
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.EnabledJob(this.job.Name)");
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.Success);
|
|
return ProgressStatus.Success;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Disable Jobs
|
|
|
|
/// <summary>
|
|
/// Disable a job
|
|
/// </summary>
|
|
internal class DisableAgentJobs : JobAction
|
|
{
|
|
public DisableAgentJobs(XmlDocument document, IServiceProvider source)
|
|
: base(document, source)
|
|
{
|
|
}
|
|
|
|
protected override void GenerateActions()
|
|
{
|
|
if (this.smoServer != null)
|
|
{
|
|
InitializeContext();
|
|
for (int i = 0; i < this.urnParameters.Length; i++)
|
|
{
|
|
Job job = this.smoServer.GetSmoObject(urnParameters[i]) as Job;
|
|
|
|
// check that the urn really points to an job
|
|
this.actions.AddAction(new DisableJobAction(job));
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class DisableJobAction : IProgressItem
|
|
{
|
|
private Job job;
|
|
|
|
public DisableJobAction(Job job)
|
|
{
|
|
if (job == null)
|
|
{
|
|
throw new ArgumentNullException("job");
|
|
}
|
|
|
|
this.job = job;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
if (this.job == null)
|
|
{
|
|
return base.ToString();
|
|
}
|
|
else
|
|
{
|
|
return "AgentActionSR.DisableJobDescription(this.job.Name)";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disable the Job
|
|
/// </summary>
|
|
/// <param name="actions">Actions collection</param>
|
|
/// <param name="index">this actions index into the actions collection</param>
|
|
/// <returns></returns>
|
|
public ProgressStatus DoAction(ProgressItemCollection actions, int index)
|
|
{
|
|
//parameter check
|
|
if (actions == null)
|
|
{
|
|
throw new ArgumentNullException("actions");
|
|
}
|
|
|
|
// in progress
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.InProgress);
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.DisablingJob(this.job.Name)");
|
|
|
|
this.job.IsEnabled = false;
|
|
this.job.Alter();
|
|
|
|
// done
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.DisabledJob(this.job.Name)");
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.Success);
|
|
return ProgressStatus.Success;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Start Job
|
|
|
|
/// <summary>
|
|
/// Start an agent job. If the jobs have multiple steps we will show a dialog that asks
|
|
/// which step the job should be started on.
|
|
/// </summary>
|
|
internal class StartAgentJobs : JobAction
|
|
{
|
|
public StartAgentJobs(XmlDocument document, IServiceProvider source)
|
|
: base(document, source)
|
|
{
|
|
this.actions.CloseOnUserCancel = true;
|
|
this.actions.QuitOnError = true;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// The method is generates list of actions and it is gets called from the OnLaod of base Form method
|
|
/// </summary>
|
|
protected override void GenerateActions()
|
|
{
|
|
if (this.smoServer != null)
|
|
{
|
|
InitializeContext();
|
|
|
|
for (int i = 0; i < this.urnParameters.Length; i++)
|
|
{
|
|
Job job = this.smoServer.GetSmoObject(urnParameters[i]) as Job;
|
|
|
|
|
|
string selectedStep = null;
|
|
|
|
DataTable dtSteps = GetJobDataSteps(job);
|
|
if (dtSteps == null || dtSteps.Rows == null)
|
|
continue;
|
|
|
|
if (dtSteps.Rows.Count > 1) //check if job is multi step job
|
|
{
|
|
// selectedStep = ShowStepDialog(job, dtSteps);
|
|
if (selectedStep == null) //check if the job was canceled
|
|
continue;
|
|
}
|
|
|
|
//Copy the LastRunTime of the job into prevRunTime before the job started.
|
|
DateTime prevRunTime = job.LastRunDate;
|
|
this.actions.AddAction(new StartJobAction(job, selectedStep));
|
|
this.actions.AddAction(new WaitForJobToFinishAction(job, prevRunTime));
|
|
}
|
|
|
|
if (this.actions.Count <= 0)
|
|
{
|
|
//This is a workaround for the class dialog invocation problem
|
|
//This dialog is invoked from two places
|
|
//JobsActivityMonitor (JobsPanel.cs) OnStartJobAtStep method
|
|
// and SSMS Context menu mpu\ssms\shared\SqlMgmt\src\RunningFormsTable.cs method StartFormExecution
|
|
//It is no way for us to prevent the dialog execution from the context menu (when job was canceled), besides redisgning the architecture
|
|
//this.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns list of steps of the given job
|
|
/// </summary>
|
|
/// <param name="job"></param>
|
|
/// <returns>returns list of steps</returns>
|
|
private DataTable GetJobDataSteps(Job job)
|
|
{
|
|
if (job == null || job.Parent == null || job.Parent.Parent == null)
|
|
return null;
|
|
|
|
// perform an enumerator query to get the steps. We could use the
|
|
// SMO step object but this is too inefficient as it generates a batch
|
|
// per step.
|
|
Request request = new Request();
|
|
|
|
request.Fields = new string[] {"Name", "ID", "SubSystem"};
|
|
request.Urn = job.Urn + "/Step";
|
|
request.OrderByList = new OrderBy[] {new OrderBy("ID", OrderBy.Direction.Asc)};
|
|
|
|
Enumerator en = new Enumerator();
|
|
return en.Process(job.Parent.Parent.ConnectionContext, request);
|
|
}
|
|
|
|
/// <summary>
|
|
/// This class implements the feature described in project tracking bug 37519.
|
|
/// The point is to poll the server for the status of the job to give the user
|
|
/// some indication of whether the job succeeded or failed. Polls every 3 seconds.
|
|
/// </summary>
|
|
internal class WaitForJobToFinishAction : IProgressItem
|
|
{
|
|
private Job job;
|
|
private DateTime prevRunTime;
|
|
private ManualResetEvent abortEvent;
|
|
private const int ServerPollingInterval = 3000;
|
|
|
|
public WaitForJobToFinishAction(Job job, DateTime prevRunTime)
|
|
{
|
|
this.job = job;
|
|
this.prevRunTime = prevRunTime;
|
|
this.abortEvent = new ManualResetEvent(false); //initial set to busy
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prevent default constructor
|
|
/// </summary>
|
|
private WaitForJobToFinishAction()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// generates a friendly description of this step. Used by the progress dialog
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override string ToString()
|
|
{
|
|
if (this.job == null)
|
|
{
|
|
return base.ToString();
|
|
}
|
|
else
|
|
{
|
|
return "AgentActionSR.ExecuteJob(job.Name)";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This method triggers abort event for the action thread
|
|
/// </summary>
|
|
public void Abort()
|
|
{
|
|
this.abortEvent.Set();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Perform the action for this class
|
|
/// </summary>
|
|
/// <param name="actions">Actions collection</param>
|
|
/// <param name="index">array index of this particular action</param>
|
|
/// <returns></returns>
|
|
public ProgressStatus DoAction(ProgressItemCollection actions, int index)
|
|
{
|
|
ProgressStatus status = ProgressStatus.Error;
|
|
|
|
bool jobFinished = false;
|
|
|
|
JobServer jobServer = job.Parent;
|
|
JobCategory category = jobServer.JobCategories[job.Category];
|
|
|
|
if (category.CategoryType == CategoryType.MultiServerJob)
|
|
{
|
|
actions.Progress.UpdateActionDescription(index, "AgentActionSR.RequestPostedToTargetServers");
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.Success);
|
|
return ProgressStatus.Success;
|
|
}
|
|
|
|
status = ProgressStatus.Aborted;
|
|
|
|
// now wait for job to finish...
|
|
while (!this.abortEvent.WaitOne(WaitForJobToFinishAction.ServerPollingInterval))
|
|
{
|
|
if (actions.Progress.IsAborted)
|
|
break;
|
|
|
|
this.job.Refresh();
|
|
// If this job hasn't started yet then don't check for its status
|
|
if (this.prevRunTime != job.LastRunDate)
|
|
{
|
|
switch (this.job.CurrentRunStatus)
|
|
{
|
|
case JobExecutionStatus.Idle:
|
|
|
|
actions.Progress.UpdateActionProgress(index, 100);
|
|
|
|
// see if the job succeeded.
|
|
if (this.job.LastRunOutcome == CompletionResult.Failed)
|
|
{
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.Error);
|
|
actions.Progress.AddActionException(index,
|
|
new Exception("AgentActionSR.JobFailed(job.Name)"));
|
|
status = ProgressStatus.Error;
|
|
}
|
|
else
|
|
{
|
|
actions.Progress.UpdateActionDescription(index, "AgentActionSR.ExecuteJob(job.Name)");
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.Success);
|
|
status = ProgressStatus.Success;
|
|
}
|
|
|
|
jobFinished = true;
|
|
|
|
break;
|
|
|
|
case JobExecutionStatus.Suspended:
|
|
|
|
actions.Progress.UpdateActionProgress(index, "AgentActionSR.Suspended");
|
|
break;
|
|
|
|
case JobExecutionStatus.BetweenRetries:
|
|
|
|
actions.Progress.UpdateActionProgress(index, "AgentActionSR.BetweenRetries");
|
|
break;
|
|
|
|
case JobExecutionStatus.Executing:
|
|
|
|
actions.Progress.UpdateActionProgress(index, "AgentActionSR.Executing");
|
|
break;
|
|
|
|
case JobExecutionStatus.PerformingCompletionAction:
|
|
|
|
actions.Progress.UpdateActionProgress(index, "AgentActionSR.PerformingCompletionAction");
|
|
break;
|
|
|
|
case JobExecutionStatus.WaitingForStepToFinish:
|
|
|
|
actions.Progress.UpdateActionProgress(index, "AgentActionSR.WaitingForStepToFinish");
|
|
break;
|
|
|
|
case JobExecutionStatus.WaitingForWorkerThread:
|
|
|
|
actions.Progress.UpdateActionProgress(index, "AgentActionSR.WaitingForWorkerThread");
|
|
break;
|
|
|
|
default:
|
|
// unknown JobExecutionStatus, keep waiting.
|
|
System.Diagnostics.Debug.Assert(false,
|
|
"Unknown JobExecutionStatus found while waiting for job execution to finish");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (jobFinished)
|
|
{
|
|
break;
|
|
}
|
|
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.InProgress);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// starts a job
|
|
/// </summary>
|
|
internal class StartJobAction : IProgressItem
|
|
{
|
|
private Job job;
|
|
//Represent selected job step if any
|
|
private string currentJobStep;
|
|
|
|
public StartJobAction(Job job, string jobStep)
|
|
{
|
|
// need a job. The delegate can be null
|
|
if (job == null)
|
|
{
|
|
throw new ArgumentNullException("job");
|
|
}
|
|
|
|
this.job = job;
|
|
this.currentJobStep = jobStep;
|
|
}
|
|
|
|
/// <summary>
|
|
/// generates a friendly description of this step. Used by the progress dialog
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override string ToString()
|
|
{
|
|
if (this.job == null)
|
|
{
|
|
return base.ToString();
|
|
}
|
|
else
|
|
{
|
|
return "AgentActionSR.StartJobDescription(this.job.Name)";
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Start the Job
|
|
/// </summary>
|
|
/// <param name="actions">Actions collection</param>
|
|
/// <param name="index">this actions index into the actions collection</param>
|
|
/// <returns></returns>
|
|
public ProgressStatus DoAction(ProgressItemCollection actions, int index)
|
|
{
|
|
ProgressStatus status = ProgressStatus.Success;
|
|
//parameter check
|
|
if (actions == null)
|
|
{
|
|
throw new ArgumentNullException("actions");
|
|
}
|
|
|
|
// in progress
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.InProgress);
|
|
|
|
// perform an enumerator query to get the steps. We could use the
|
|
// SMO step object but this is too inefficient as it generates a batch
|
|
// per step.
|
|
Request request = new Request();
|
|
|
|
request.Fields = new string[] {"Name", "ID", "SubSystem"};
|
|
request.Urn = this.job.Urn + "/Step";
|
|
request.OrderByList = new OrderBy[] {new OrderBy("ID", OrderBy.Direction.Asc)};
|
|
|
|
if (this.currentJobStep != null)
|
|
{
|
|
actions.Progress.AddActionInfoString(index,
|
|
"AgentActionSR.StartJobWithStep(this.job.Name, this.currentJobStep)");
|
|
this.job.Start(this.currentJobStep);
|
|
}
|
|
else
|
|
{
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.StartingJob(this.job.Name)");
|
|
this.job.Start();
|
|
}
|
|
|
|
// done
|
|
actions.Progress.UpdateActionStatus(index, status);
|
|
return status;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Stop Job
|
|
|
|
/// <summary>
|
|
/// stop a job
|
|
/// </summary>
|
|
internal class StopAgentJobs : JobAction
|
|
{
|
|
public StopAgentJobs(XmlDocument document, IServiceProvider source)
|
|
: base(document, source)
|
|
{
|
|
}
|
|
|
|
protected override void GenerateActions()
|
|
{
|
|
if (this.smoServer != null)
|
|
{
|
|
InitializeContext();
|
|
|
|
for (int i = 0; i < this.urnParameters.Length; i++)
|
|
{
|
|
Job job = this.smoServer.GetSmoObject(urnParameters[i]) as Job;
|
|
|
|
// check that the urn really points to an job
|
|
this.actions.AddAction(new StopJobAction(job));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// class that actually stops a running job
|
|
/// </summary>
|
|
internal class StopJobAction : IProgressItem
|
|
{
|
|
private Job job;
|
|
|
|
public StopJobAction(Job job)
|
|
{
|
|
if (job == null)
|
|
{
|
|
throw new ArgumentNullException("job");
|
|
}
|
|
|
|
this.job = job;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate a user friendly description of this task. Used in the description
|
|
/// of the progress dialog.
|
|
/// </summary>
|
|
/// <returns>Description of the action</returns>
|
|
public override string ToString()
|
|
{
|
|
if (this.job == null)
|
|
{
|
|
return base.ToString();
|
|
}
|
|
else
|
|
{
|
|
return "AgentActionSR.StopJobDescription(this.job.Name)";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stop the Job
|
|
/// </summary>
|
|
/// <param name="actions">Actions collection</param>
|
|
/// <param name="index">this actions index into the actions collection</param>
|
|
/// <returns></returns>
|
|
public ProgressStatus DoAction(ProgressItemCollection actions, int index)
|
|
{
|
|
//parameter check
|
|
if (actions == null)
|
|
{
|
|
throw new ArgumentNullException("actions");
|
|
}
|
|
|
|
// in progress
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.InProgress);
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.StoppingJob(this.job.Name)");
|
|
job.Stop();
|
|
|
|
// done
|
|
actions.Progress.AddActionInfoString(index, "AgentActionSR.StoppedJob(this.job.Name)");
|
|
actions.Progress.UpdateActionStatus(index, ProgressStatus.Success);
|
|
return ProgressStatus.Success;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|