// // 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.Collections.Generic; using System.Data; using System.IO; using System.Threading.Tasks; using System.Xml; using Microsoft.SqlServer.Management.Common; using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlServer.Management.Smo.Agent; using Microsoft.SqlTools.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Agent.Contracts; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Hosting; using Microsoft.SqlTools.ServiceLayer.Management; using Microsoft.SqlTools.ServiceLayer.Utility; namespace Microsoft.SqlTools.ServiceLayer.Agent { /// /// Main class for Agent Service functionality /// public class AgentService { private ConnectionService connectionService = null; private static readonly Lazy instance = new Lazy(() => new AgentService()); /// /// Construct a new AgentService instance with default parameters /// public AgentService() { } /// /// Gets the singleton instance object /// public static AgentService Instance { get { return instance.Value; } } /// /// Internal for testing purposes only /// internal ConnectionService ConnectionServiceInstance { get { if (connectionService == null) { connectionService = ConnectionService.Instance; } return connectionService; } set { connectionService = value; } } /// /// Service host object for sending/receiving requests/events. /// Internal for testing purposes. /// internal IProtocolEndpoint ServiceHost { get; set; } /// /// Initializes the service instance /// public void InitializeService(ServiceHost serviceHost) { this.ServiceHost = serviceHost; // Jobs request handlers this.ServiceHost.SetRequestHandler(AgentJobsRequest.Type, HandleAgentJobsRequest); this.ServiceHost.SetRequestHandler(AgentJobHistoryRequest.Type, HandleJobHistoryRequest); this.ServiceHost.SetRequestHandler(AgentJobActionRequest.Type, HandleJobActionRequest); this.ServiceHost.SetRequestHandler(CreateAgentJobRequest.Type, HandleCreateAgentJobRequest); this.ServiceHost.SetRequestHandler(UpdateAgentJobRequest.Type, HandleUpdateAgentJobRequest); this.ServiceHost.SetRequestHandler(DeleteAgentJobRequest.Type, HandleDeleteAgentJobRequest); this.ServiceHost.SetRequestHandler(AgentJobDefaultsRequest.Type, HandleAgentJobDefaultsRequest); // Job Steps request handlers this.ServiceHost.SetRequestHandler(CreateAgentJobStepRequest.Type, HandleCreateAgentJobStepRequest); this.ServiceHost.SetRequestHandler(UpdateAgentJobStepRequest.Type, HandleUpdateAgentJobStepRequest); this.ServiceHost.SetRequestHandler(DeleteAgentJobStepRequest.Type, HandleDeleteAgentJobStepRequest); // Alerts request handlers this.ServiceHost.SetRequestHandler(AgentAlertsRequest.Type, HandleAgentAlertsRequest); this.ServiceHost.SetRequestHandler(CreateAgentAlertRequest.Type, HandleCreateAgentAlertRequest); this.ServiceHost.SetRequestHandler(UpdateAgentAlertRequest.Type, HandleUpdateAgentAlertRequest); this.ServiceHost.SetRequestHandler(DeleteAgentAlertRequest.Type, HandleDeleteAgentAlertRequest); // Operators request handlers this.ServiceHost.SetRequestHandler(AgentOperatorsRequest.Type, HandleAgentOperatorsRequest); this.ServiceHost.SetRequestHandler(CreateAgentOperatorRequest.Type, HandleCreateAgentOperatorRequest); this.ServiceHost.SetRequestHandler(UpdateAgentOperatorRequest.Type, HandleUpdateAgentOperatorRequest); this.ServiceHost.SetRequestHandler(DeleteAgentOperatorRequest.Type, HandleDeleteAgentOperatorRequest); // Proxy Accounts request handlers this.ServiceHost.SetRequestHandler(AgentProxiesRequest.Type, HandleAgentProxiesRequest); this.ServiceHost.SetRequestHandler(CreateAgentProxyRequest.Type, HandleCreateAgentProxyRequest); this.ServiceHost.SetRequestHandler(UpdateAgentProxyRequest.Type, HandleUpdateAgentProxyRequest); this.ServiceHost.SetRequestHandler(DeleteAgentProxyRequest.Type, HandleDeleteAgentProxyRequest); // Schedule request handlers this.ServiceHost.SetRequestHandler(AgentSchedulesRequest.Type, HandleAgentSchedulesRequest); this.ServiceHost.SetRequestHandler(CreateAgentScheduleRequest.Type, HandleCreateAgentScheduleRequest); this.ServiceHost.SetRequestHandler(UpdateAgentScheduleRequest.Type, HandleUpdateAgentScheduleRequest); this.ServiceHost.SetRequestHandler(DeleteAgentScheduleRequest.Type, HandleDeleteAgentScheduleRequest); // Notebook request handlers this.ServiceHost.SetRequestHandler(AgentNotebooksRequest.Type, HandleAgentNotebooksRequest); this.ServiceHost.SetRequestHandler(AgentNotebookHistoryRequest.Type, HandleAgentNotebookHistoryRequest); this.ServiceHost.SetRequestHandler(AgentNotebookMaterializedRequest.Type, HandleAgentNotebookMaterializedRequest); this.ServiceHost.SetRequestHandler(AgentNotebookTemplateRequest.Type, HandleAgentNotebookTemplateRequest); this.ServiceHost.SetRequestHandler(CreateAgentNotebookRequest.Type, HandleCreateAgentNotebookRequest); this.ServiceHost.SetRequestHandler(DeleteAgentNotebookRequest.Type, HandleDeleteAgentNotebooksRequest); this.ServiceHost.SetRequestHandler(UpdateAgentNotebookRequest.Type, HandleUpdateAgentNotebookRequest); this.ServiceHost.SetRequestHandler(UpdateAgentNotebookRunPinRequest.Type, HandleUpdateAgentNotebookRunPinRequest); this.ServiceHost.SetRequestHandler(UpdateAgentNotebookRunNameRequest.Type, HandleUpdateAgentNotebookRunNameRequest); this.ServiceHost.SetRequestHandler(DeleteNotebookMaterializedRequest.Type, HandleDeleteNotebookMaterializedRequest); serviceHost.RegisterShutdownTask((_, _) => { DeleteAgentNotebooksTempFiles(); return Task.FromResult(0); }); } #region "Jobs Handlers" /// /// Handle request to get Agent job activities /// internal async Task HandleAgentJobsRequest(AgentJobsParams parameters, RequestContext requestContext) { try { var result = new AgentJobsResult(); ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); if (connInfo != null) { var serverConnection = ConnectionService.OpenServerConnection(connInfo); var fetcher = new JobFetcher(serverConnection); var filter = new JobActivityFilter(); var jobs = fetcher.FetchJobs(filter); var agentJobs = new List(); if (jobs != null) { foreach (var job in jobs.Values) { agentJobs.Add(AgentUtilities.ConvertToAgentJobInfo(job)); } } result.Success = true; result.Jobs = agentJobs.ToArray(); serverConnection.SqlConnectionObject.Close(); } await requestContext.SendResult(result); } catch (Exception e) { await requestContext.SendError(e); } } /// /// Handle request to get Agent Job history /// internal async Task HandleJobHistoryRequest(AgentJobHistoryParams parameters, RequestContext requestContext) { try { var result = new AgentJobHistoryResult(); ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); if (connInfo != null) { CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); var jobServer = dataContainer.Server.JobServer; var jobs = jobServer.Jobs; Tuple 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(); 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(); foreach (JobSchedule schedule in schedules) { jobSchedules.Add(AgentUtilities.ConvertToAgentScheduleInfo(schedule)); } result.Schedules = jobSchedules.ToArray(); // Alerts AlertCollection alerts = jobServer.Alerts; var jobAlerts = new List(); 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 jobHistories = new List(); if (count > 0) { var job = dt.Rows[0]; Guid jobId = (Guid)job[AgentUtilities.UrnJobId]; int runStatus = Convert.ToInt32(job[AgentUtilities.UrnRunStatus], System.Globalization.CultureInfo.InvariantCulture); var t = new LogSourceJobHistory(parameters.JobName, sqlConnInfo, null, runStatus, jobId, null); var tlog = t as ILogSource; tlog.Initialize(); var logEntries = t.LogEntries; // Finally add the job histories jobHistories = AgentUtilities.ConvertToAgentJobHistoryInfo(logEntries, job, steps); result.Histories = jobHistories.ToArray(); result.Success = true; tlog.CloseReader(); } await requestContext.SendResult(result); } } catch (Exception e) { await requestContext.SendError(e); } } /// /// Handle request to Run a Job /// internal async Task HandleJobActionRequest(AgentJobActionParams parameters, RequestContext requestContext) { var result = new ResultStatus(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); if (connInfo != null) { var serverConnection = ConnectionService.OpenServerConnection(connInfo); var jobHelper = new JobHelper(serverConnection); jobHelper.JobName = parameters.JobName; switch (parameters.Action) { case "run": jobHelper.Start(); break; case "stop": jobHelper.Stop(); break; case "delete": jobHelper.Delete(); break; case "enable": jobHelper.Enable(true); break; case "disable": jobHelper.Enable(false); break; default: break; } result.Success = true; await requestContext.SendResult(result); } } catch (Exception e) { result.Success = false; result.ErrorMessage = e.Message; Exception exception = e.InnerException; while (exception != null) { result.ErrorMessage += Environment.NewLine + "\t" + exception.Message; exception = exception.InnerException; } await requestContext.SendResult(result); } } internal async Task HandleCreateAgentJobRequest(CreateAgentJobParams parameters, RequestContext requestContext) { var result = await ConfigureAgentJob( parameters.OwnerUri, parameters.Job.Name, parameters.Job, ConfigAction.Create, ManagementUtils.asRunType(parameters.TaskExecutionMode)); await requestContext.SendResult(new CreateAgentJobResult() { Success = result.Item1, ErrorMessage = result.Item2 }); } internal async Task HandleUpdateAgentJobRequest(UpdateAgentJobParams parameters, RequestContext requestContext) { var result = await ConfigureAgentJob( parameters.OwnerUri, parameters.OriginalJobName, parameters.Job, ConfigAction.Update, ManagementUtils.asRunType(parameters.TaskExecutionMode)); await requestContext.SendResult(new UpdateAgentJobResult() { Success = result.Item1, ErrorMessage = result.Item2 }); } internal async Task HandleDeleteAgentJobRequest(DeleteAgentJobParams parameters, RequestContext requestContext) { var result = await ConfigureAgentJob( parameters.OwnerUri, parameters.Job.Name, parameters.Job, ConfigAction.Drop, ManagementUtils.asRunType(parameters.TaskExecutionMode)); await requestContext.SendResult(new ResultStatus() { Success = result.Item1, ErrorMessage = result.Item2 }); } internal async Task HandleCreateAgentJobStepRequest(CreateAgentJobStepParams parameters, RequestContext requestContext) { Tuple result = await ConfigureAgentJobStep( parameters.OwnerUri, parameters.Step, ConfigAction.Create, RunType.RunNow); await requestContext.SendResult(new CreateAgentJobStepResult() { Success = result.Item1, ErrorMessage = result.Item2 }); } internal async Task HandleUpdateAgentJobStepRequest(UpdateAgentJobStepParams parameters, RequestContext requestContext) { Tuple result = await ConfigureAgentJobStep( parameters.OwnerUri, parameters.Step, ConfigAction.Update, RunType.RunNow); await requestContext.SendResult(new UpdateAgentJobStepResult() { Success = result.Item1, ErrorMessage = result.Item2 }); } internal async Task HandleDeleteAgentJobStepRequest(DeleteAgentJobStepParams parameters, RequestContext requestContext) { Tuple result = await ConfigureAgentJobStep( parameters.OwnerUri, parameters.Step, ConfigAction.Drop, RunType.RunNow); await requestContext.SendResult(new ResultStatus() { Success = result.Item1, ErrorMessage = result.Item2 }); } internal async Task HandleAgentJobDefaultsRequest(AgentJobDefaultsParams parameters, RequestContext requestContext) { var result = new AgentJobDefaultsResult(); try { JobData jobData; CDataContainer dataContainer; CreateJobData(parameters.OwnerUri, "default", out dataContainer, out jobData); // current connection user name for result.Owner = dataContainer.ServerConnection.TrueLogin; var categories = jobData.Categories; result.Categories = new AgentJobCategory[categories.Length]; for (int i = 0; i < categories.Length; ++i) { result.Categories[i] = new AgentJobCategory { Id = categories[i].SmoCategory.ID, Name = categories[i].SmoCategory.Name }; } result.Success = true; } catch (Exception ex) { result.Success = false; result.ErrorMessage = ex.ToString(); } await requestContext.SendResult(result); } #endregion // "Jobs Handlers" #region "Alert Handlers" /// /// Handle request to get the alerts list /// internal async Task HandleAgentAlertsRequest(AgentAlertsParams parameters, RequestContext requestContext) { var result = new AgentAlertsResult(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection(parameters.OwnerUri, out connInfo); CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); int alertsCount = dataContainer.Server.JobServer.Alerts.Count; var alerts = new AgentAlertInfo[alertsCount]; for (int i = 0; i < alertsCount; ++i) { var alert = dataContainer.Server.JobServer.Alerts[i]; alerts[i] = new AgentAlertInfo { Id = alert.ID, Name = alert.Name, DelayBetweenResponses = alert.DelayBetweenResponses, EventDescriptionKeyword = alert.EventDescriptionKeyword, EventSource = alert.EventSource, HasNotification = alert.HasNotification, IncludeEventDescription = (Contracts.NotifyMethods)alert.IncludeEventDescription, IsEnabled = alert.IsEnabled, JobId = alert.JobID.ToString(), JobName = alert.JobName, LastOccurrenceDate = alert.LastOccurrenceDate.ToString(), LastResponseDate = alert.LastResponseDate.ToString(), MessageId = alert.MessageID, NotificationMessage = alert.NotificationMessage, OccurrenceCount = alert.OccurrenceCount, PerformanceCondition = alert.PerformanceCondition, Severity = alert.Severity, DatabaseName = alert.DatabaseName, CountResetDate = alert.CountResetDate.ToString(), CategoryName = alert.CategoryName, AlertType = (Contracts.AlertType)alert.AlertType, WmiEventNamespace = alert.WmiEventNamespace, WmiEventQuery = alert.WmiEventQuery }; } result.Alerts = alerts; result.Success = true; } catch (Exception ex) { result.Success = false; result.ErrorMessage = ex.ToString(); } await requestContext.SendResult(result); } /// /// Handle request to create an alert /// internal async Task HandleCreateAgentAlertRequest(CreateAgentAlertParams parameters, RequestContext requestContext) { var result = await ConfigureAgentAlert( parameters.OwnerUri, parameters.Alert.Name, parameters.Alert, ConfigAction.Create, RunType.RunNow); await requestContext.SendResult(new CreateAgentAlertResult() { Success = result.Item1, ErrorMessage = result.Item2 }); } /// /// Handle request to update an alert /// internal async Task HandleUpdateAgentAlertRequest(UpdateAgentAlertParams parameters, RequestContext requestContext) { var result = await ConfigureAgentAlert( parameters.OwnerUri, parameters.OriginalAlertName, parameters.Alert, ConfigAction.Update, RunType.RunNow); await requestContext.SendResult(new UpdateAgentAlertResult() { Success = result.Item1, ErrorMessage = result.Item2 }); } /// /// Handle request to delete an alert /// internal async Task HandleDeleteAgentAlertRequest(DeleteAgentAlertParams parameters, RequestContext requestContext) { var result = await ConfigureAgentAlert( parameters.OwnerUri, parameters.Alert.Name, parameters.Alert, ConfigAction.Drop, RunType.RunNow); await requestContext.SendResult(new ResultStatus() { Success = result.Item1, ErrorMessage = result.Item2 }); } #endregion // "Alert Handlers" #region "Operator Handlers" internal async Task HandleAgentOperatorsRequest(AgentOperatorsParams parameters, RequestContext requestContext) { var result = new AgentOperatorsResult(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection(parameters.OwnerUri, out connInfo); CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); int operatorCount = dataContainer.Server.JobServer.Operators.Count; var operators = new AgentOperatorInfo[operatorCount]; for (int i = 0; i < operatorCount; ++i) { var item = dataContainer.Server.JobServer.Operators[i]; operators[i] = new AgentOperatorInfo { Name = item.Name, Id = item.ID, EmailAddress = item.EmailAddress, Enabled = item.Enabled, LastEmailDate = item.LastEmailDate.ToString(), LastNetSendDate = item.LastNetSendDate.ToString(), LastPagerDate = item.LastPagerDate.ToString(), PagerAddress = item.PagerAddress, CategoryName = item.CategoryName, PagerDays = (Contracts.WeekDays)item.PagerDays, SaturdayPagerEndTime = item.SaturdayPagerEndTime.ToString(), SaturdayPagerStartTime = item.SaturdayPagerEndTime.ToString(), SundayPagerEndTime = item.SundayPagerEndTime.ToString(), SundayPagerStartTime = item.SundayPagerStartTime.ToString(), NetSendAddress = item.NetSendAddress, WeekdayPagerStartTime = item.WeekdayPagerStartTime.ToString(), WeekdayPagerEndTime = item.WeekdayPagerEndTime.ToString() }; } result.Operators = operators; result.Success = true; } catch (Exception ex) { result.Success = false; result.ErrorMessage = ex.ToString(); } await requestContext.SendResult(result); } internal async Task HandleCreateAgentOperatorRequest( CreateAgentOperatorParams parameters, RequestContext requestContext) { var result = await ConfigureAgentOperator( parameters.OwnerUri, parameters.Operator, ConfigAction.Create, RunType.RunNow); await requestContext.SendResult(new AgentOperatorResult() { Success = result.Item1, ErrorMessage = result.Item2, Operator = parameters.Operator }); } internal async Task HandleUpdateAgentOperatorRequest( UpdateAgentOperatorParams parameters, RequestContext requestContext) { var result = await ConfigureAgentOperator( parameters.OwnerUri, parameters.Operator, ConfigAction.Update, RunType.RunNow); await requestContext.SendResult(new AgentOperatorResult() { Success = result.Item1, ErrorMessage = result.Item2, Operator = parameters.Operator }); } internal async Task HandleDeleteAgentOperatorRequest( DeleteAgentOperatorParams parameters, RequestContext requestContext) { var result = await ConfigureAgentOperator( parameters.OwnerUri, parameters.Operator, ConfigAction.Drop, RunType.RunNow); await requestContext.SendResult(new ResultStatus() { Success = result.Item1, ErrorMessage = result.Item2 }); } #endregion // "Operator Handlers" #region "Proxy Handlers" internal async Task HandleAgentProxiesRequest(AgentProxiesParams parameters, RequestContext requestContext) { var result = new AgentProxiesResult(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection(parameters.OwnerUri, out connInfo); CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); int proxyCount = dataContainer.Server.JobServer.ProxyAccounts.Count; var proxies = new AgentProxyInfo[proxyCount]; for (int i = 0; i < proxyCount; ++i) { var proxy = dataContainer.Server.JobServer.ProxyAccounts[i]; proxies[i] = new AgentProxyInfo { Id = proxy.ID, AccountName = proxy.Name, Description = proxy.Description, CredentialName = proxy.CredentialName, CredentialIdentity = proxy.CredentialIdentity, CredentialId = proxy.CredentialID, IsEnabled = proxy.IsEnabled }; } result.Proxies = proxies; result.Success = true; } catch (Exception ex) { result.Success = false; result.ErrorMessage = ex.ToString(); } await requestContext.SendResult(result); } internal async Task HandleCreateAgentProxyRequest(CreateAgentProxyParams parameters, RequestContext requestContext) { var result = await ConfigureAgentProxy( parameters.OwnerUri, parameters.Proxy.AccountName, parameters.Proxy, ConfigAction.Create, RunType.RunNow); await requestContext.SendResult(new AgentProxyResult() { Success = result.Item1, ErrorMessage = result.Item2, Proxy = parameters.Proxy }); } internal async Task HandleUpdateAgentProxyRequest(UpdateAgentProxyParams parameters, RequestContext requestContext) { var result = await ConfigureAgentProxy( parameters.OwnerUri, parameters.Proxy.AccountName, parameters.Proxy, ConfigAction.Update, RunType.RunNow); await requestContext.SendResult(new AgentProxyResult() { Success = result.Item1, ErrorMessage = result.Item2, Proxy = parameters.Proxy }); } internal async Task HandleDeleteAgentProxyRequest(DeleteAgentProxyParams parameters, RequestContext requestContext) { var result = await ConfigureAgentProxy( parameters.OwnerUri, parameters.Proxy.AccountName, parameters.Proxy, ConfigAction.Drop, RunType.RunNow); await requestContext.SendResult(new ResultStatus() { Success = result.Item1, ErrorMessage = result.Item2 }); } #endregion // "Proxy Handlers" #region "Schedule Handlers" internal async Task HandleAgentSchedulesRequest(AgentSchedulesParams parameters, RequestContext requestContext) { var result = new AgentSchedulesResult(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection(parameters.OwnerUri, out connInfo); CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); int scheduleCount = dataContainer.Server.JobServer.SharedSchedules.Count; var schedules = new AgentScheduleInfo[scheduleCount]; for (int i = 0; i < scheduleCount; ++i) { var schedule = dataContainer.Server.JobServer.SharedSchedules[i]; var scheduleData = new JobScheduleData(schedule); schedules[i] = new AgentScheduleInfo(); schedules[i].Id = schedule.ID; schedules[i].Name = schedule.Name; schedules[i].IsEnabled = schedule.IsEnabled; schedules[i].FrequencyTypes = (Contracts.FrequencyTypes)schedule.FrequencyTypes; schedules[i].FrequencySubDayTypes = (Contracts.FrequencySubDayTypes)schedule.FrequencySubDayTypes; schedules[i].FrequencySubDayInterval = schedule.FrequencySubDayInterval; schedules[i].FrequencyRelativeIntervals = (Contracts.FrequencyRelativeIntervals)schedule.FrequencyRelativeIntervals; schedules[i].FrequencyRecurrenceFactor = schedule.FrequencyRecurrenceFactor; schedules[i].FrequencyInterval = schedule.FrequencyInterval; schedules[i].DateCreated = schedule.DateCreated; schedules[i].ActiveStartTimeOfDay = schedule.ActiveStartTimeOfDay; schedules[i].ActiveStartDate = schedule.ActiveStartDate; schedules[i].ActiveEndTimeOfDay = schedule.ActiveEndTimeOfDay; schedules[i].JobCount = schedule.JobCount; schedules[i].ActiveEndDate = schedule.ActiveEndDate; schedules[i].ScheduleUid = schedule.ScheduleUid; schedules[i].Description = scheduleData.Description; } result.Schedules = schedules; result.Success = true; } catch (Exception ex) { result.Success = false; result.ErrorMessage = ex.ToString(); } await requestContext.SendResult(result); } internal async Task HandleCreateAgentScheduleRequest(CreateAgentScheduleParams parameters, RequestContext requestContext) { var result = await ConfigureAgentSchedule( parameters.OwnerUri, parameters.Schedule, ConfigAction.Create, RunType.RunNow); await requestContext.SendResult(new AgentScheduleResult() { Success = result.Item1, ErrorMessage = result.Item2, Schedule = parameters.Schedule }); } internal async Task HandleUpdateAgentScheduleRequest(UpdateAgentScheduleParams parameters, RequestContext requestContext) { var result = await ConfigureAgentSchedule( parameters.OwnerUri, parameters.Schedule, ConfigAction.Update, RunType.RunNow); await requestContext.SendResult(new AgentScheduleResult() { Success = result.Item1, ErrorMessage = result.Item2, Schedule = parameters.Schedule }); } internal async Task HandleDeleteAgentScheduleRequest(DeleteAgentScheduleParams parameters, RequestContext requestContext) { var result = await ConfigureAgentSchedule( parameters.OwnerUri, parameters.Schedule, ConfigAction.Drop, RunType.RunNow); await requestContext.SendResult(new ResultStatus() { Success = result.Item1, ErrorMessage = result.Item2 }); } #endregion // "Schedule Handlers" #region "Helpers" internal void ExecuteAction(ManagementActionBase action, RunType runType) { var executionHandler = new ExecutonHandler(action); executionHandler.RunNow(runType, this); if (executionHandler.ExecutionResult == ExecutionMode.Failure) { if (executionHandler.ExecutionFailureException != null) { throw executionHandler.ExecutionFailureException; } else { throw new Exception("Failed to execute action"); } } } internal async Task> ConfigureAgentJob( string ownerUri, string originalJobName, AgentJobInfo jobInfo, ConfigAction configAction, RunType runType) { try { JobData jobData; CDataContainer dataContainer; CreateJobData(ownerUri, originalJobName, out dataContainer, out jobData, configAction, jobInfo); using (JobActions actions = new JobActions(dataContainer, jobData, configAction)) { ExecuteAction(actions, runType); } ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo); if (connInfo != null) { dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); } // Execute step actions if they exist if (configAction != ConfigAction.Drop && jobInfo.JobSteps != null && jobInfo.JobSteps.Length > 0) { foreach (AgentJobStepInfo step in jobInfo.JobSteps) { configAction = ConfigAction.Create; foreach (JobStep jobStep in dataContainer.Server.JobServer.Jobs[originalJobName].JobSteps) { // any changes made to step other than name or ordering if ((step.StepName == jobStep.Name && step.Id == jobStep.ID) || // if the step name was changed (step.StepName != jobStep.Name && step.Id == jobStep.ID) || // if the step ordering was changed (step.StepName == jobStep.Name && step.Id != jobStep.ID)) { configAction = ConfigAction.Update; break; } } await ConfigureAgentJobStep(ownerUri, step, configAction, runType, jobData, dataContainer); } } // Execute schedule actions if they exist if (jobInfo.JobSchedules != null && jobInfo.JobSchedules.Length > 0) { foreach (AgentScheduleInfo schedule in jobInfo.JobSchedules) { await ConfigureAgentSchedule(ownerUri, schedule, configAction, runType, jobData, dataContainer); } } // Execute alert actions if they exist if (jobInfo.Alerts != null && jobInfo.Alerts.Length > 0) { foreach (AgentAlertInfo alert in jobInfo.Alerts) { alert.JobId = jobData.Job.JobID.ToString(); await ConfigureAgentAlert(ownerUri, alert.Name, alert, configAction, runType, jobData, dataContainer); } } return new Tuple(true, string.Empty); } catch (Exception ex) { return new Tuple(false, ex.ToString()); } } internal Task> ConfigureAgentJobStep( string ownerUri, AgentJobStepInfo stepInfo, ConfigAction configAction, RunType runType, JobData jobData = null, CDataContainer dataContainer = null) { return Task.Run(() => { try { if (string.IsNullOrWhiteSpace(stepInfo.JobName)) { return new Tuple(false, "JobName cannot be null"); } if (jobData == null) { CreateJobData(ownerUri, stepInfo.JobName, out dataContainer, out jobData); } using (var actions = new JobStepsActions(dataContainer, jobData, stepInfo, configAction)) { ExecuteAction(actions, runType); } return new Tuple(true, string.Empty); } catch (Exception ex) { // log exception here return new Tuple(false, ex.ToString()); } }); } internal Task> ConfigureAgentAlert( string ownerUri, string alertName, AgentAlertInfo alert, ConfigAction configAction, RunType runType, JobData jobData = null, CDataContainer dataContainer = null) { return Task>.Run(() => { try { // If the alert is being created outside of a job if (string.IsNullOrWhiteSpace(alert.JobName)) { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo); dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); } else { if (jobData == null) { // If the alert is being created inside a job CreateJobData(ownerUri, alert.JobName, out dataContainer, out jobData); } } STParameters param = new STParameters(dataContainer.Document); param.SetParam("alert", alertName); if (alert != null) { using (AgentAlertActions actions = new AgentAlertActions(dataContainer, alertName, alert, configAction, jobData)) { ExecuteAction(actions, runType); } } return new Tuple(true, string.Empty); } catch (Exception ex) { return new Tuple(false, ex.ToString()); } }); } internal Task> ConfigureAgentOperator( string ownerUri, AgentOperatorInfo operatorInfo, ConfigAction configAction, RunType runType) { return Task.Run(() => { try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo); CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); STParameters param = new STParameters(dataContainer.Document); param.SetParam("operator", operatorInfo.Name); using (AgentOperatorActions actions = new AgentOperatorActions(dataContainer, operatorInfo, configAction)) { ExecuteAction(actions, runType); } return new Tuple(true, string.Empty); } catch (Exception ex) { return new Tuple(false, ex.ToString()); } }); } internal Task> ConfigureAgentProxy( string ownerUri, string accountName, AgentProxyInfo proxy, ConfigAction configAction, RunType runType) { return Task.Run(() => { try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo); CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); STParameters param = new STParameters(dataContainer.Document); param.SetParam("proxyaccount", accountName); using (AgentProxyAccountActions actions = new AgentProxyAccountActions(dataContainer, proxy, configAction)) { ExecuteAction(actions, runType); } return new Tuple(true, string.Empty); } catch (Exception ex) { return new Tuple(false, ex.ToString()); } }); } internal Task> ConfigureAgentSchedule( string ownerUri, AgentScheduleInfo schedule, ConfigAction configAction, RunType runType, JobData jobData = null, CDataContainer dataContainer = null) { return Task.Run(() => { try { if (jobData == null) { CreateJobData(ownerUri, schedule.JobName, out dataContainer, out jobData); } const string UrnFormatStr = "Server/JobServer[@Name='{0}']/Job[@Name='{1}']/Schedule[@Name='{2}']"; string serverName = dataContainer.Server.Name.ToUpper(); string scheduleUrn = string.Format(UrnFormatStr, serverName, jobData.Job.Name, schedule.Name); STParameters param = new STParameters(dataContainer.Document); param.SetParam("urn", scheduleUrn); using (JobSchedulesActions actions = new JobSchedulesActions(dataContainer, jobData, schedule, configAction)) { ExecuteAction(actions, runType); } return new Tuple(true, string.Empty); } catch (Exception ex) { return new Tuple(false, ex.ToString()); } }); } private void CreateJobData( string ownerUri, string jobName, out CDataContainer dataContainer, out JobData jobData, ConfigAction configAction = ConfigAction.Create, AgentJobInfo jobInfo = null) { 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; param.SetParam("job", configAction == ConfigAction.Update ? jobName : string.Empty); param.SetParam("jobid", string.Empty); jobData = new JobData(dataContainer, jobInfo, configAction); } public static XmlDocument CreateJobXmlDocument(string svrName, string jobName) { // XML element strings const string XmlFormDescElementName = "formdescription"; const string XmlParamsElementName = "params"; const string XmlJobElementName = "job"; const string XmlUrnElementName = "urn"; const string UrnFormatStr = "Server/JobServer[@Name='{0}']/Job[@Name='{1}']"; // Write out XML. StringWriter textWriter = new StringWriter(); XmlTextWriter xmlWriter = new XmlTextWriter(textWriter); xmlWriter.WriteStartElement(XmlFormDescElementName); xmlWriter.WriteStartElement(XmlParamsElementName); xmlWriter.WriteElementString(XmlJobElementName, jobName); xmlWriter.WriteElementString(XmlUrnElementName, string.Format(UrnFormatStr, svrName, jobName)); xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement(); xmlWriter.Close(); // Create an XML document. XmlDocument doc = new XmlDocument(); XmlTextReader rdr = new XmlTextReader(new System.IO.StringReader(textWriter.ToString())); rdr.MoveToContent(); doc.LoadXml(rdr.ReadOuterXml()); return doc; } private Tuple CreateSqlConnection(ConnectionInfo connInfo, String jobId) { var serverConnection = ConnectionService.OpenServerConnection(connInfo); var server = new Server(serverConnection); var filter = new JobHistoryFilter(); filter.JobID = new Guid(jobId); var dt = server.JobServer.EnumJobHistory(filter); var sqlConnInfo = new SqlConnectionInfo(serverConnection, SqlServer.Management.Common.ConnectionType.SqlConnection); return new Tuple(sqlConnInfo, dt, serverConnection); } internal async Task HandleAgentNotebooksRequest(AgentNotebooksParams parameters, RequestContext requestContext) { var result = new AgentNotebooksResult(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); result.Success = true; result.Notebooks = AgentNotebookHelper.GetAgentNotebooks(connInfo).Result; } catch (Exception e) { result.Success = false; result.ErrorMessage = e.ToString(); } await requestContext.SendResult(result); } internal async Task HandleAgentNotebookHistoryRequest( AgentNotebookHistoryParams parameters, RequestContext requestContext) { var result = new AgentNotebookHistoryResult(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); result = await GetAgentNotebookHistories( connInfo, parameters.JobId, parameters.JobName, parameters.TargetDatabase ); result.Success = true; } catch (Exception e) { result.Success = false; result.ErrorMessage = e.ToString(); } await requestContext.SendResult(result); } internal async Task HandleAgentNotebookMaterializedRequest(AgentNotebookMaterializedParams parameters, RequestContext requestContext) { var result = new AgentNotebookMaterializedResult(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); result.NotebookMaterialized = AgentNotebookHelper.GetMaterializedNotebook(connInfo, parameters.NotebookMaterializedId, parameters.TargetDatabase).Result; result.Success = true; } catch (Exception e) { result.Success = false; result.ErrorMessage = e.ToString(); } await requestContext.SendResult(result); } internal async Task HandleAgentNotebookTemplateRequest(AgentNotebookTemplateParams parameters, RequestContext requestContext) { var result = new AgentNotebookTemplateResult(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); result.NotebookTemplate = await AgentNotebookHelper.GetTemplateNotebook(connInfo, parameters.JobId, parameters.TargetDatabase); result.Success = true; } catch (Exception e) { result.Success = false; result.ErrorMessage = e.ToString(); } await requestContext.SendResult(result); } internal async Task HandleCreateAgentNotebookRequest(CreateAgentNotebookParams parameters, RequestContext requestContext) { var result = new CreateAgentNotebookResult(); try { // storing result result.Success = true; await AgentNotebookHelper.CreateNotebook( this, parameters.OwnerUri, parameters.Notebook, parameters.TemplateFilePath, ManagementUtils.asRunType(parameters.TaskExecutionMode) ); } catch (Exception e) { result.Success = false; result.ErrorMessage = e.ToString(); } await requestContext.SendResult(result); } internal async Task HandleDeleteAgentNotebooksRequest(DeleteAgentNotebookParams parameters, RequestContext requestContext) { var result = new ResultStatus(); try { // Calling delete notebook helper function await AgentNotebookHelper.DeleteNotebook( this, parameters.OwnerUri, parameters.Notebook, ManagementUtils.asRunType(parameters.TaskExecutionMode) ); result.Success = true; } catch (Exception e) { result.Success = false; result.ErrorMessage = e.ToString(); } await requestContext.SendResult(result); } internal async Task HandleUpdateAgentNotebookRequest(UpdateAgentNotebookParams parameters, RequestContext requestContext) { var result = new UpdateAgentNotebookResult(); try { // Calling update helper function await AgentNotebookHelper.UpdateNotebook( this, parameters.OwnerUri, parameters.OriginalNotebookName, parameters.Notebook, parameters.TemplateFilePath, ManagementUtils.asRunType(parameters.TaskExecutionMode)); result.Success = true; } catch (Exception e) { result.Success = false; result.ErrorMessage = e.ToString(); } await requestContext.SendResult(result); } internal async Task HandleUpdateAgentNotebookRunNameRequest(UpdateAgentNotebookRunNameParams parameters, RequestContext requestContext) { var result = new ResultStatus(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); // Calling update helper function await AgentNotebookHelper.UpdateMaterializedNotebookName( connInfo, parameters.agentNotebookHistory, parameters.TargetDatabase, parameters.MaterializedNotebookName); result.Success = true; } catch (Exception e) { result.Success = false; result.ErrorMessage = e.ToString(); } await requestContext.SendResult(result); } internal async Task HandleUpdateAgentNotebookRunPinRequest(UpdateAgentNotebookRunPinParams parameters, RequestContext requestContext) { var result = new ResultStatus(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); // Calling update helper function await AgentNotebookHelper.UpdateMaterializedNotebookPin( connInfo, parameters.agentNotebookHistory, parameters.TargetDatabase, parameters.MaterializedNotebookPin); result.Success = true; } catch (Exception e) { result.Success = false; result.ErrorMessage = e.ToString(); } await requestContext.SendResult(result); } internal async Task HandleDeleteNotebookMaterializedRequest(DeleteMaterializedNotebookParams parameters, RequestContext requestContext) { var result = new ResultStatus(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); // Calling update helper function await AgentNotebookHelper.DeleteMaterializedNotebook( connInfo, parameters.agentNotebookHistory, parameters.TargetDatabase); result.Success = true; } catch (Exception e) { result.Success = false; result.ErrorMessage = e.ToString(); } await requestContext.SendResult(result); } public async Task GetAgentNotebookHistories ( ConnectionInfo connInfo, string jobId, string jobName, string targetDatabase ) { AgentNotebookHistoryResult result = new AgentNotebookHistoryResult(); // fetching Job information CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); var jobServer = dataContainer.Server.JobServer; var jobs = jobServer.Jobs; Tuple tuple = CreateSqlConnection(connInfo, jobId); SqlConnectionInfo sqlConnInfo = tuple.Item1; DataTable dt = tuple.Item2; // add steps to the job if any JobStepCollection steps = jobs[jobName].JobSteps; var jobSteps = new List(); foreach (JobStep step in steps) { jobSteps.Add(AgentUtilities.ConvertToAgentJobStepInfo(step, jobId, jobName)); } result.Steps = jobSteps.ToArray(); // add schedules to the job if any JobScheduleCollection schedules = jobs[jobName].JobSchedules; var jobSchedules = new List(); foreach (JobSchedule schedule in schedules) { jobSchedules.Add(AgentUtilities.ConvertToAgentScheduleInfo(schedule)); } result.Schedules = jobSchedules.ToArray(); // add histories int count = dt.Rows.Count; List notebookHistories = new List(); if (count > 0) { var job = dt.Rows[0]; Guid tempjobId = (Guid)job[AgentUtilities.UrnJobId]; int runStatus = Convert.ToInt32(job[AgentUtilities.UrnRunStatus], System.Globalization.CultureInfo.InvariantCulture); var t = new LogSourceJobHistory(jobName, sqlConnInfo, null, runStatus, tempjobId, null); var tlog = t as ILogSource; tlog.Initialize(); var logEntries = t.LogEntries; var jobHistories = AgentUtilities.ConvertToAgentNotebookHistoryInfo(logEntries, job, steps); // fetching notebook part of histories Dictionary notebookHistoriesDict = new Dictionary(); DataTable materializedNotebookTable = await AgentNotebookHelper.GetAgentNotebookHistories(connInfo, jobId, targetDatabase); foreach (DataRow materializedNotebookRow in materializedNotebookTable.Rows) { notebookHistoriesDict.Add(materializedNotebookRow["job_runtime"].ToString(), materializedNotebookRow); } // adding notebook information to job histories foreach (var jobHistory in jobHistories) { string jobRuntime = jobHistory.RunDate.ToString("yyyyMMddHHmmss"); AgentNotebookHistoryInfo notebookHistory = jobHistory; if (notebookHistoriesDict.ContainsKey(jobRuntime)) { notebookHistory.MaterializedNotebookId = (int)notebookHistoriesDict[jobRuntime]["materialized_id"]; notebookHistory.MaterializedNotebookErrorInfo = notebookHistoriesDict[jobRuntime]["notebook_error"] as string; notebookHistory.MaterializedNotebookName = notebookHistoriesDict[jobRuntime]["notebook_name"] as string; notebookHistory.MaterializedNotebookPin = (bool)notebookHistoriesDict[jobRuntime]["pin"]; notebookHistory.MaterializedNotebookDeleted = (bool)notebookHistoriesDict[jobRuntime]["is_deleted"]; } if (notebookHistory.MaterializedNotebookDeleted) { continue; } notebookHistories.Add(notebookHistory); } result.Histories = notebookHistories.ToArray(); tlog.CloseReader(); } return result; } #endregion // "Helpers" internal void DeleteAgentNotebooksTempFiles() { if (FileUtilities.SafeDirectoryExists(FileUtilities.AgentNotebookTempFolder)) { FileUtilities.SafeDirectoryDelete(FileUtilities.AgentNotebookTempFolder, true); } } } }