Agent/improve steps (#710)

* added stepInfo for editing jobs/steps

* added schedules to history requests

* added alerts and schedules to history

* formatting

* code review comments

* removed smo import

* changed and optimized histories, steps, alerts and operators
This commit is contained in:
Aditya Bist
2018-10-16 13:24:32 -07:00
committed by GitHub
parent 8fe3d06068
commit 0efed221ee
7 changed files with 180 additions and 93 deletions

View File

@@ -27,7 +27,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
/// </summary>
public class AgentService
{
private Dictionary<Guid, JobProperties> jobs = null;
private ConnectionService connectionService = null;
private static readonly Lazy<AgentService> instance = new Lazy<AgentService>(() => new AgentService());
@@ -148,11 +147,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
var serverConnection = new ServerConnection(sqlConnection);
var fetcher = new JobFetcher(serverConnection);
var filter = new JobActivityFilter();
this.jobs = fetcher.FetchJobs(filter);
var jobs = fetcher.FetchJobs(filter);
var agentJobs = new List<AgentJobInfo>();
if (this.jobs != null)
if (jobs != null)
{
foreach (var job in this.jobs.Values)
foreach (var job in jobs.Values)
{
agentJobs.Add(AgentUtilities.ConvertToAgentJobInfo(job));
}
@@ -186,42 +185,63 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
out connInfo);
if (connInfo != null)
{
ConnectionServiceInstance.TryFindConnection(parameters.OwnerUri, out connInfo);
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
var jobs = dataContainer.Server.JobServer.Jobs;
Tuple<SqlConnectionInfo, DataTable, ServerConnection> tuple = CreateSqlConnection(connInfo, parameters.JobId);
SqlConnectionInfo sqlConnInfo = tuple.Item1;
DataTable dt = tuple.Item2;
ServerConnection connection = tuple.Item3;
// Send Steps, Alerts and Schedules with job history in background
// Add steps to the job if any
JobStepCollection steps = jobs[parameters.JobName].JobSteps;
var jobSteps = new List<AgentJobStepInfo>();
foreach (JobStep step in steps)
{
jobSteps.Add(AgentUtilities.ConvertToAgentJobStepInfo(step, parameters.JobId, parameters.JobName));
}
result.Steps = jobSteps.ToArray();
// Add schedules to the job if any
JobScheduleCollection schedules = jobs[parameters.JobName].JobSchedules;
var jobSchedules = new List<AgentScheduleInfo>();
foreach (JobSchedule schedule in schedules)
{
jobSchedules.Add(AgentUtilities.ConvertToAgentScheduleInfo(schedule));
}
result.Schedules = jobSchedules.ToArray();
// Alerts
AlertCollection alerts = dataContainer.Server.JobServer.Alerts;
var jobAlerts = new List<Alert>();
foreach (Alert alert in alerts)
{
if (alert.JobName == parameters.JobName)
{
jobAlerts.Add(alert);
}
}
result.Alerts = AgentUtilities.ConvertToAgentAlertInfo(jobAlerts);
// Add histories
int count = dt.Rows.Count;
List<AgentJobHistoryInfo> jobHistories = new List<AgentJobHistoryInfo>();
if (count > 0)
{
var job = dt.Rows[0];
string jobName = Convert.ToString(job[AgentUtilities.UrnJobName], System.Globalization.CultureInfo.InvariantCulture);
Guid jobId = (Guid) job[AgentUtilities.UrnJobId];
Guid jobId = (Guid)job[AgentUtilities.UrnJobId];
int runStatus = Convert.ToInt32(job[AgentUtilities.UrnRunStatus], System.Globalization.CultureInfo.InvariantCulture);
var t = new LogSourceJobHistory(jobName, sqlConnInfo, null, runStatus, jobId, null);
var t = new LogSourceJobHistory(parameters.JobName, sqlConnInfo, null, runStatus, jobId, null);
var tlog = t as ILogSource;
tlog.Initialize();
var logEntries = t.LogEntries;
// Send Steps, Alerts and Schedules with job history in background
JobStepCollection steps = jobs[jobName].JobSteps;
JobScheduleCollection schedules = jobs[jobName].JobSchedules;
List<Alert> alerts = new List<Alert>();
foreach (Alert alert in dataContainer.Server.JobServer.Alerts)
{
if (alert.JobID == jobId && alert.JobName == jobName)
{
alerts.Add(alert);
}
}
jobHistories = AgentUtilities.ConvertToAgentJobHistoryInfo(logEntries, job, steps, schedules, alerts);
// Finally add the job histories
jobHistories = AgentUtilities.ConvertToAgentJobHistoryInfo(logEntries, job, steps);
result.Histories = jobHistories.ToArray();
result.Success = true;
tlog.CloseReader();
}
result.Jobs = jobHistories.ToArray();
result.Success = true;
connection.Disconnect();
await requestContext.SendResult(result);
}
@@ -320,12 +340,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
internal async Task HandleDeleteAgentJobRequest(DeleteAgentJobParams parameters, RequestContext<ResultStatus> requestContext)
{
var result = await ConfigureAgentJob(
parameters.OwnerUri,
parameters.Job.Name,
parameters.Job,
ConfigAction.Drop,
ManagementUtils.asRunType(parameters.TaskExecutionMode));
var result = await ConfigureAgentJob(
parameters.OwnerUri,
parameters.Job.Name,
parameters.Job,
ConfigAction.Drop,
ManagementUtils.asRunType(parameters.TaskExecutionMode));
await requestContext.SendResult(new ResultStatus()
{
@@ -418,7 +438,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
#endregion // "Jobs Handlers"
#region "Alert Handlers"
#region "Alert Handlers"
/// <summary>
/// Handle request to get the alerts list
@@ -1059,12 +1079,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
ConnectionInfo connInfo;
ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo);
dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
XmlDocument jobDoc = CreateJobXmlDocument(dataContainer.Server.Name.ToUpper(), jobName);
dataContainer.Init(jobDoc.InnerXml);
STParameters param = new STParameters(dataContainer.Document);
string originalName = jobInfo != null && !string.Equals(jobName, jobInfo.Name) ? jobName : string.Empty;
string originalName = jobInfo != null && !string.Equals(jobName, jobInfo.Name) ? jobName : string.Empty;
param.SetParam("job", configAction == ConfigAction.Update ? jobName : string.Empty);
param.SetParam("jobid", string.Empty);

View File

@@ -34,14 +34,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
public const string UrnServer = "Server";
internal const string UrnServerTime = "CurrentDate";
public static AgentJobInfo ConvertToAgentJobInfo(JobProperties job)
public static AgentJobInfo ConvertToAgentJobInfo(JobProperties job)
{
return new AgentJobInfo
{
Name = job.Name,
Description = job.Description,
CurrentExecutionStatus = job.CurrentExecutionStatus,
LastRunOutcome = job.LastRunOutcome,
CurrentExecutionStatus = (Contracts.JobExecutionStatus) job.CurrentExecutionStatus,
LastRunOutcome = (Contracts.CompletionResult) job.LastRunOutcome,
CurrentExecutionStep = job.CurrentExecutionStep,
Enabled = job.Enabled,
HasTarget = job.HasTarget,
@@ -57,7 +57,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
};
}
internal static AgentJobStep ConvertToAgentJobStepInfo(JobStep step, LogSourceJobHistory.LogEntryJobHistory logEntry, string jobId)
internal static AgentJobStep ConvertToAgentJobStep(JobStep step, LogSourceJobHistory.LogEntryJobHistory logEntry, string jobId)
{
AgentJobStepInfo stepInfo = new AgentJobStepInfo();
stepInfo.JobId = jobId;
@@ -88,6 +88,30 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
return jobStep;
}
internal static AgentJobStepInfo ConvertToAgentJobStepInfo(JobStep step, string jobId, string jobName)
{
AgentJobStepInfo stepInfo = new AgentJobStepInfo();
stepInfo.JobId = jobId;
stepInfo.JobName = jobName;
stepInfo.StepName = step.Name;
stepInfo.SubSystem = step.SubSystem.ToString();
stepInfo.Id = step.ID;
stepInfo.FailureAction = step.OnFailAction.ToString();
stepInfo.SuccessAction = step.OnSuccessAction.ToString();
stepInfo.FailStepId = step.OnFailStep;
stepInfo.SuccessStepId = step.OnSuccessStep;
stepInfo.Command = step.Command;
stepInfo.CommandExecutionSuccessCode = step.CommandExecutionSuccessCode;
stepInfo.DatabaseName = step.DatabaseName;
stepInfo.DatabaseUserName = step.DatabaseUserName;
stepInfo.Server = step.Server;
stepInfo.OutputFileName = step.OutputFileName;
stepInfo.RetryAttempts = step.RetryAttempts;
stepInfo.RetryInterval = step.RetryInterval;
stepInfo.ProxyName = step.ProxyName;
return stepInfo;
}
internal static AgentScheduleInfo ConvertToAgentScheduleInfo(JobSchedule schedule)
{
AgentScheduleInfo scheduleInfo = new AgentScheduleInfo();
@@ -113,37 +137,41 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
return scheduleInfo;
}
internal static AgentAlertInfo ConvertToAgentAlertInfo(Alert alert)
internal static AgentAlertInfo[] ConvertToAgentAlertInfo(List<Alert> alerts)
{
AgentAlertInfo alertInfo = new AgentAlertInfo();
alertInfo.Id = alert.ID;
alertInfo.Name = alert.Name;
alertInfo.DelayBetweenResponses = alert.DelayBetweenResponses;
alertInfo.EventDescriptionKeyword = alert.EventDescriptionKeyword;
alertInfo.EventSource = alert.EventSource;
alertInfo.HasNotification = alert.HasNotification;
alertInfo.IncludeEventDescription = (Contracts.NotifyMethods) alert.IncludeEventDescription;
alertInfo.IsEnabled = alert.IsEnabled;
alertInfo.JobId = alert.JobID.ToString();
alertInfo.JobName = alert.JobName;
alertInfo.LastOccurrenceDate = alert.LastOccurrenceDate.ToString();
alertInfo.LastResponseDate = alert.LastResponseDate.ToString();
alertInfo.MessageId = alert.MessageID;
alertInfo.NotificationMessage = alert.NotificationMessage;
alertInfo.OccurrenceCount = alert.OccurrenceCount;
alertInfo.PerformanceCondition = alert.PerformanceCondition;
alertInfo.Severity = alert.Severity;
alertInfo.DatabaseName = alert.DatabaseName;
alertInfo.CountResetDate = alert.CountResetDate.ToString();
alertInfo.CategoryName = alert.CategoryName;
alertInfo.AlertType = (Contracts.AlertType) alert.AlertType;
alertInfo.WmiEventNamespace = alert.WmiEventNamespace;
alertInfo.WmiEventQuery = alert.WmiEventQuery;
return alertInfo;
var result = new List<AgentAlertInfo>();
foreach(Alert alert in alerts)
{
AgentAlertInfo alertInfo = new AgentAlertInfo();
alertInfo.Id = alert.ID;
alertInfo.Name = alert.Name;
alertInfo.DelayBetweenResponses = alert.DelayBetweenResponses;
alertInfo.EventDescriptionKeyword = alert.EventDescriptionKeyword;
alertInfo.EventSource = alert.EventSource;
alertInfo.HasNotification = alert.HasNotification;
alertInfo.IncludeEventDescription = (Contracts.NotifyMethods) alert.IncludeEventDescription;
alertInfo.IsEnabled = alert.IsEnabled;
alertInfo.JobId = alert.JobID.ToString();
alertInfo.JobName = alert.JobName;
alertInfo.LastOccurrenceDate = alert.LastOccurrenceDate.ToString();
alertInfo.LastResponseDate = alert.LastResponseDate.ToString();
alertInfo.MessageId = alert.MessageID;
alertInfo.NotificationMessage = alert.NotificationMessage;
alertInfo.OccurrenceCount = alert.OccurrenceCount;
alertInfo.PerformanceCondition = alert.PerformanceCondition;
alertInfo.Severity = alert.Severity;
alertInfo.DatabaseName = alert.DatabaseName;
alertInfo.CountResetDate = alert.CountResetDate.ToString();
alertInfo.CategoryName = alert.CategoryName;
alertInfo.AlertType = (Contracts.AlertType) alert.AlertType;
alertInfo.WmiEventNamespace = alert.WmiEventNamespace;
alertInfo.WmiEventQuery = alert.WmiEventQuery;
result.Add(alertInfo);
}
return result.ToArray();
}
public static List<AgentJobHistoryInfo> ConvertToAgentJobHistoryInfo(List<ILogEntry> logEntries,
DataRow jobRow, JobStepCollection steps, JobScheduleCollection schedules, List<Alert> alerts)
public static List<AgentJobHistoryInfo> ConvertToAgentJobHistoryInfo(List<ILogEntry> logEntries, DataRow jobRow, JobStepCollection steps)
{
List<AgentJobHistoryInfo> jobs = new List<AgentJobHistoryInfo>();
// get all the values for a job history
@@ -174,26 +202,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
foreach (JobStep step in steps)
{
var jobId = jobRow[UrnJobId].ToString();
jobSteps.Add(AgentUtilities.ConvertToAgentJobStepInfo(step, logEntry, jobId));
jobSteps.Add(AgentUtilities.ConvertToAgentJobStep(step, logEntry, jobId));
}
jobHistoryInfo.Steps = jobSteps.ToArray();
// Add schedules to the job if any
var jobSchedules = new List<AgentScheduleInfo>();
foreach (JobSchedule schedule in schedules)
{
jobSchedules.Add(AgentUtilities.ConvertToAgentScheduleInfo(schedule));
}
jobHistoryInfo.Schedules = jobSchedules.ToArray();
// Add alerts to the job if any
var jobAlerts = new List<AgentAlertInfo>();
foreach (Alert alert in alerts)
{
jobAlerts.Add(AgentUtilities.ConvertToAgentAlertInfo(alert));
}
jobHistoryInfo.Alerts = jobAlerts.ToArray();
jobs.Add(jobHistoryInfo);
}
return jobs;

View File

@@ -8,6 +8,25 @@ using Microsoft.SqlTools.ServiceLayer.Agent;
namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
{
public enum JobCompletionActionCondition
{
Never = 0,
OnSuccess = 1,
OnFailure = 2,
Always = 3
}
public enum JobExecutionStatus
{
Executing = 1,
WaitingForWorkerThread = 2,
BetweenRetries = 3,
Idle = 4,
Suspended = 5,
WaitingForStepToFinish = 6,
PerformingCompletionAction = 7
}
/// <summary>
/// a class for storing various properties of agent jobs,
/// used by the Job Activity Monitor
@@ -17,8 +36,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
public string Name { get; set; }
public string Owner { get; set; }
public string Description { get; set; }
public int CurrentExecutionStatus { get; set; }
public int LastRunOutcome { get; set; }
public JobExecutionStatus CurrentExecutionStatus { get; set; }
public CompletionResult LastRunOutcome { get; set; }
public string CurrentExecutionStep { get; set; }
public bool Enabled { get; set; }
public bool HasTarget { get; set; }
@@ -31,5 +50,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
public string LastRun { get; set; }
public string NextRun { get; set; }
public string JobId { get; set; }
public string OperatorToEmail { get; set; }
public string OperatorToPage { get; set; }
public int StartStepID { get; set; }
public JobCompletionActionCondition EmailLevel { get; set; }
public JobCompletionActionCondition PageLevel { get; set; }
public JobCompletionActionCondition EventLogLevel { get; set; }
public JobCompletionActionCondition DeleteLevel { get; set; }
public AgentJobStepInfo[] JobSteps { get; set; }
public AgentScheduleInfo[] JobSchedules { get; set; }
public AgentAlertInfo[] Alerts { get; set; }
}
}

View File

@@ -135,6 +135,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
public string OwnerUri { get; set; }
public string JobId { get; set; }
public string JobName { get; set; }
}
/// <summary>
@@ -142,7 +143,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
/// </summary>
public class AgentJobHistoryResult : ResultStatus
{
public AgentJobHistoryInfo[] Jobs { get; set; }
public AgentJobHistoryInfo[] Histories { get; set; }
public AgentJobStepInfo[] Steps { get; set; }
public AgentScheduleInfo[] Schedules { get; set; }
public AgentAlertInfo[] Alerts { get; set ;}
}
/// <summary>

View File

@@ -379,15 +379,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
"HasSchedule",
"HasStep",
"HasServer",
"LastRunDate",
"NextRunDate",
"LastRunOutcome",
"JobID",
"Description"
"Description",
"LastRunDate",
"NextRunDate",
"OperatorToEmail",
"OperatorToNetSend",
"OperatorToPage",
"OwnerLoginName",
"PageLevel",
"StartStepID",
"NetSendLevel",
"EventLogLevel",
"EmailLevel",
"DeleteLevel"
};
DataTable dt = enumerator.Process(connection, request);
int numJobs = dt.Rows.Count;
if (numJobs == 0)
{
@@ -395,7 +404,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
}
Dictionary<Guid, JobProperties> foundJobs = new Dictionary<Guid, JobProperties>(numJobs);
for (int i = 0; i < numJobs; ++i)
{
JobProperties jobProperties = new JobProperties(dt.Rows[i]);

View File

@@ -16,7 +16,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
public class JobProperties
{
private string name;
private int currentExecutionStatus;
private int lastRunOutcome;
private string currentExecutionStep;
@@ -32,6 +31,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
private DateTime nextRun;
private Guid jobId;
private string description;
private string owner;
private string operatorToEmail;
private string operatorToPage;
private int startStepID;
private int emailLevel;
private int pageLevel;
private int eventLogLevel;
private int deleteLevel;
private JobProperties()
{
@@ -65,6 +72,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
this.lastRunOutcome = Convert.ToInt32(row["LastRunOutcome"], CultureInfo.InvariantCulture);
this.jobId = Guid.Parse(row["JobID"].ToString());
this.description = row["Description"].ToString();
this.owner = row["OwnerLoginName"].ToString();
this.operatorToEmail = row["OperatorToEmail"].ToString();
this.operatorToPage = row["OperatorToPage"].ToString();
this.startStepID = Convert.ToInt32(row["StartStepID"], CultureInfo.InvariantCulture);
this.emailLevel = Convert.ToInt32(row["EmailLevel"], CultureInfo.InvariantCulture);
this.pageLevel = Convert.ToInt32(row["PageLevel"], CultureInfo.InvariantCulture);
this.eventLogLevel = Convert.ToInt32(row["EventLogLevel"], CultureInfo.InvariantCulture);
this.deleteLevel = Convert.ToInt32(row["DeleteLevel"], CultureInfo.InvariantCulture);
// for a job to be runnable, it must:
// 1. have a target server