mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-13 17:23:02 -05:00
SQL Agent configuration for Operators, Alerts and Proxies (WIP) (#621)
* 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
This commit is contained in:
@@ -190,12 +190,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create database task helper
|
||||
/// Create a data container object
|
||||
/// </summary>
|
||||
/// <param name="connInfo">connection info</param>
|
||||
/// <param name="databaseExists">flag indicating whether to create taskhelper for existing database or not</param>
|
||||
/// <returns></returns>
|
||||
internal static DatabaseTaskHelper CreateDatabaseTaskHelper(ConnectionInfo connInfo, bool databaseExists = false)
|
||||
internal static CDataContainer CreateDataContainer(ConnectionInfo connInfo, bool databaseExists = false)
|
||||
{
|
||||
XmlDocument xmlDoc = CreateDataContainerDocument(connInfo, databaseExists);
|
||||
CDataContainer dataContainer;
|
||||
@@ -232,6 +231,18 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
|
||||
xmlDoc.InnerXml);
|
||||
}
|
||||
|
||||
return dataContainer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create database task helper
|
||||
/// </summary>
|
||||
/// <param name="connInfo">connection info</param>
|
||||
/// <param name="databaseExists">flag indicating whether to create taskhelper for existing database or not</param>
|
||||
/// <returns></returns>
|
||||
internal static DatabaseTaskHelper CreateDatabaseTaskHelper(ConnectionInfo connInfo, bool databaseExists = false)
|
||||
{
|
||||
var dataContainer = CreateDataContainer(connInfo, databaseExists);
|
||||
var taskHelper = new DatabaseTaskHelper(dataContainer);
|
||||
return taskHelper;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
using System;
|
||||
//
|
||||
// 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;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Diagnostics;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
//
|
||||
// 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.Text;
|
||||
|
||||
@@ -13,6 +13,7 @@ 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.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
||||
@@ -21,10 +22,17 @@ using Microsoft.SqlTools.Utility;
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
/// <summary>
|
||||
/// Main class for Profiler Service functionality
|
||||
/// Main class for Agent Service functionality
|
||||
/// </summary>
|
||||
public sealed class AgentService
|
||||
public class AgentService
|
||||
{
|
||||
internal enum AgentConfigAction
|
||||
{
|
||||
Create,
|
||||
Update,
|
||||
Drop
|
||||
}
|
||||
|
||||
private Dictionary<Guid, JobProperties> jobs = null;
|
||||
private ConnectionService connectionService = null;
|
||||
private static readonly Lazy<AgentService> instance = new Lazy<AgentService>(() => new AgentService());
|
||||
@@ -64,7 +72,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Service host object for sending/receiving requests/events.
|
||||
/// Internal for testing purposes.
|
||||
@@ -84,47 +91,70 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
this.ServiceHost.SetRequestHandler(AgentJobsRequest.Type, HandleAgentJobsRequest);
|
||||
this.ServiceHost.SetRequestHandler(AgentJobHistoryRequest.Type, HandleJobHistoryRequest);
|
||||
this.ServiceHost.SetRequestHandler(AgentJobActionRequest.Type, HandleJobActionRequest);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
#region "Jobs Handlers"
|
||||
|
||||
/// <summary>
|
||||
/// Handle request to get Agent job activities
|
||||
/// </summary>
|
||||
internal async Task HandleAgentJobsRequest(AgentJobsParams parameters, RequestContext<AgentJobsResult> requestContext)
|
||||
{
|
||||
try
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var result = new AgentJobsResult();
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
|
||||
if (connInfo != null)
|
||||
try
|
||||
{
|
||||
var sqlConnection = ConnectionService.OpenSqlConnection(connInfo);
|
||||
var serverConnection = new ServerConnection(sqlConnection);
|
||||
var fetcher = new JobFetcher(serverConnection);
|
||||
var filter = new JobActivityFilter();
|
||||
this.jobs = fetcher.FetchJobs(filter);
|
||||
var agentJobs = new List<AgentJobInfo>();
|
||||
if (this.jobs != null)
|
||||
var result = new AgentJobsResult();
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
|
||||
if (connInfo != null)
|
||||
{
|
||||
|
||||
foreach (var job in this.jobs.Values)
|
||||
var sqlConnection = ConnectionService.OpenSqlConnection(connInfo);
|
||||
var serverConnection = new ServerConnection(sqlConnection);
|
||||
var fetcher = new JobFetcher(serverConnection);
|
||||
var filter = new JobActivityFilter();
|
||||
this.jobs = fetcher.FetchJobs(filter);
|
||||
var agentJobs = new List<AgentJobInfo>();
|
||||
if (this.jobs != null)
|
||||
{
|
||||
agentJobs.Add(JobUtilities.ConvertToAgentJobInfo(job));
|
||||
|
||||
foreach (var job in this.jobs.Values)
|
||||
{
|
||||
agentJobs.Add(JobUtilities.ConvertToAgentJobInfo(job));
|
||||
}
|
||||
}
|
||||
result.Succeeded = true;
|
||||
result.Jobs = agentJobs.ToArray();
|
||||
sqlConnection.Close();
|
||||
}
|
||||
result.Succeeded = true;
|
||||
result.Jobs = agentJobs.ToArray();
|
||||
sqlConnection.Close();
|
||||
await requestContext.SendResult(result);
|
||||
}
|
||||
await requestContext.SendResult(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -132,44 +162,47 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
/// </summary>
|
||||
internal async Task HandleJobHistoryRequest(AgentJobHistoryParams parameters, RequestContext<AgentJobHistoryResult> requestContext)
|
||||
{
|
||||
try
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var result = new AgentJobHistoryResult();
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
if (connInfo != null)
|
||||
try
|
||||
{
|
||||
Tuple<SqlConnectionInfo, DataTable, ServerConnection> tuple = CreateSqlConnection(connInfo, parameters.JobId);
|
||||
SqlConnectionInfo sqlConnInfo = tuple.Item1;
|
||||
DataTable dt = tuple.Item2;
|
||||
ServerConnection connection = tuple.Item3;
|
||||
int count = dt.Rows.Count;
|
||||
List<AgentJobHistoryInfo> jobHistories = new List<AgentJobHistoryInfo>();
|
||||
if (count > 0)
|
||||
var result = new AgentJobHistoryResult();
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
if (connInfo != null)
|
||||
{
|
||||
var job = dt.Rows[0];
|
||||
string jobName = Convert.ToString(job[JobUtilities.UrnJobName], System.Globalization.CultureInfo.InvariantCulture);
|
||||
Guid jobId = (Guid) job[JobUtilities.UrnJobId];
|
||||
int runStatus = Convert.ToInt32(job[JobUtilities.UrnRunStatus], System.Globalization.CultureInfo.InvariantCulture);
|
||||
var t = new LogSourceJobHistory(jobName, sqlConnInfo, null, runStatus, jobId, null);
|
||||
var tlog = t as ILogSource;
|
||||
tlog.Initialize();
|
||||
var logEntries = t.LogEntries;
|
||||
jobHistories = JobUtilities.ConvertToAgentJobHistoryInfo(logEntries, job);
|
||||
tlog.CloseReader();
|
||||
Tuple<SqlConnectionInfo, DataTable, ServerConnection> tuple = CreateSqlConnection(connInfo, parameters.JobId);
|
||||
SqlConnectionInfo sqlConnInfo = tuple.Item1;
|
||||
DataTable dt = tuple.Item2;
|
||||
ServerConnection connection = tuple.Item3;
|
||||
int count = dt.Rows.Count;
|
||||
List<AgentJobHistoryInfo> jobHistories = new List<AgentJobHistoryInfo>();
|
||||
if (count > 0)
|
||||
{
|
||||
var job = dt.Rows[0];
|
||||
string jobName = Convert.ToString(job[JobUtilities.UrnJobName], System.Globalization.CultureInfo.InvariantCulture);
|
||||
Guid jobId = (Guid) job[JobUtilities.UrnJobId];
|
||||
int runStatus = Convert.ToInt32(job[JobUtilities.UrnRunStatus], System.Globalization.CultureInfo.InvariantCulture);
|
||||
var t = new LogSourceJobHistory(jobName, sqlConnInfo, null, runStatus, jobId, null);
|
||||
var tlog = t as ILogSource;
|
||||
tlog.Initialize();
|
||||
var logEntries = t.LogEntries;
|
||||
jobHistories = JobUtilities.ConvertToAgentJobHistoryInfo(logEntries, job);
|
||||
tlog.CloseReader();
|
||||
}
|
||||
result.Jobs = jobHistories.ToArray();
|
||||
result.Succeeded = true;
|
||||
connection.Disconnect();
|
||||
await requestContext.SendResult(result);
|
||||
}
|
||||
result.Jobs = jobHistories.ToArray();
|
||||
result.Succeeded = true;
|
||||
connection.Disconnect();
|
||||
await requestContext.SendResult(result);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -177,49 +210,52 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
/// </summary>
|
||||
internal async Task HandleJobActionRequest(AgentJobActionParams parameters, RequestContext<AgentJobActionResult> requestContext)
|
||||
{
|
||||
var result = new AgentJobActionResult();
|
||||
try
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
if (connInfo != null)
|
||||
var result = new AgentJobActionResult();
|
||||
try
|
||||
{
|
||||
var sqlConnection = ConnectionService.OpenSqlConnection(connInfo);
|
||||
var serverConnection = new ServerConnection(sqlConnection);
|
||||
var jobHelper = new JobHelper(serverConnection);
|
||||
jobHelper.JobName = parameters.JobName;
|
||||
switch(parameters.Action)
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
if (connInfo != null)
|
||||
{
|
||||
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;
|
||||
var sqlConnection = ConnectionService.OpenSqlConnection(connInfo);
|
||||
var serverConnection = new ServerConnection(sqlConnection);
|
||||
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.Succeeded = true;
|
||||
await requestContext.SendResult(result);
|
||||
}
|
||||
result.Succeeded = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result.Succeeded = false;
|
||||
result.ErrorMessage = e.Message;
|
||||
await requestContext.SendResult(result);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result.Succeeded = false;
|
||||
result.ErrorMessage = e.Message;
|
||||
await requestContext.SendResult(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Tuple<SqlConnectionInfo, DataTable, ServerConnection> CreateSqlConnection(ConnectionInfo connInfo, String jobId)
|
||||
@@ -234,5 +270,268 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
return new Tuple<SqlConnectionInfo, DataTable, ServerConnection>(sqlConnInfo, dt, serverConnection);
|
||||
}
|
||||
|
||||
#endregion // "Jobs Handlers"
|
||||
|
||||
#region "Alert Handlers"
|
||||
|
||||
/// <summary>
|
||||
/// Handle request to get the alerts list
|
||||
/// </summary>
|
||||
internal async Task HandleAgentAlertsRequest(AgentAlertsParams parameters, RequestContext<AgentAlertsResult> requestContext)
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var result = new AgentAlertsResult();
|
||||
result.Alerts = new List<AgentAlertInfo>().ToArray();
|
||||
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
|
||||
if (connInfo != null)
|
||||
{
|
||||
CDataContainer dataContainer = AdminService.CreateDataContainer(connInfo, databaseExists: true);
|
||||
AlertCollection alerts = dataContainer.Server.JobServer.Alerts;
|
||||
|
||||
|
||||
}
|
||||
|
||||
await requestContext.SendResult(result);
|
||||
});
|
||||
}
|
||||
|
||||
private bool ValidateAgentAlertInfo(AgentAlertInfo alert)
|
||||
{
|
||||
return alert != null
|
||||
&& !string.IsNullOrWhiteSpace(alert.JobName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle request to create an alert
|
||||
/// </summary>
|
||||
internal async Task HandleCreateAgentAlertRequest(CreateAgentAlertParams parameters, RequestContext<CreateAgentAlertResult> requestContext)
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var result = new CreateAgentAlertResult();
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
|
||||
CreateOrUpdateAgentAlert(connInfo, parameters.Alert);
|
||||
|
||||
await requestContext.SendResult(result);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle request to update an alert
|
||||
/// </summary>
|
||||
internal async Task HandleUpdateAgentAlertRequest(UpdateAgentAlertParams parameters, RequestContext<UpdateAgentAlertResult> requestContext)
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var result = new UpdateAgentAlertResult();
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
|
||||
CreateOrUpdateAgentAlert(connInfo, parameters.Alert);
|
||||
|
||||
await requestContext.SendResult(result);
|
||||
});
|
||||
}
|
||||
|
||||
private void CreateOrUpdateAgentAlert(ConnectionInfo connInfo, AgentAlertInfo alert)
|
||||
{
|
||||
if (connInfo != null && ValidateAgentAlertInfo(alert))
|
||||
{
|
||||
CDataContainer dataContainer = AdminService.CreateDataContainer(connInfo, databaseExists: true);
|
||||
STParameters param = new STParameters(dataContainer.Document);
|
||||
param.SetParam("alert", alert.JobName);
|
||||
|
||||
using (AgentAlert agentAlert = new AgentAlert(dataContainer, alert))
|
||||
{
|
||||
agentAlert.CreateOrUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle request to delete an alert
|
||||
/// </summary>
|
||||
internal async Task HandleDeleteAgentAlertRequest(DeleteAgentAlertParams parameters, RequestContext<DeleteAgentAlertResult> requestContext)
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var result = new DeleteAgentAlertResult();
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
|
||||
AgentAlertInfo alert = parameters.Alert;
|
||||
if (connInfo != null && ValidateAgentAlertInfo(alert))
|
||||
{
|
||||
CDataContainer dataContainer = AdminService.CreateDataContainer(connInfo, databaseExists: true);
|
||||
STParameters param = new STParameters(dataContainer.Document);
|
||||
param.SetParam("alert", alert.JobName);
|
||||
|
||||
using (AgentAlert agentAlert = new AgentAlert(dataContainer, alert))
|
||||
{
|
||||
agentAlert.Drop();
|
||||
}
|
||||
}
|
||||
|
||||
await requestContext.SendResult(result);
|
||||
});
|
||||
}
|
||||
|
||||
#endregion // "Alert Handlers"
|
||||
|
||||
#region "Operator Handlers"
|
||||
|
||||
internal async Task HandleAgentOperatorsRequest(AgentOperatorsParams parameters, RequestContext<AgentOperatorsResult> requestContext)
|
||||
{
|
||||
await requestContext.SendResult(null);
|
||||
}
|
||||
|
||||
internal async Task HandleCreateAgentOperatorRequest(CreateAgentOperatorParams parameters, RequestContext<CreateAgentOperatorResult> requestContext)
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var result = new CreateAgentOperatorResult();
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
|
||||
AgentOperatorInfo operatorInfo = parameters.Operator;
|
||||
CDataContainer dataContainer = AdminService.CreateDataContainer(connInfo, databaseExists: true);
|
||||
STParameters param = new STParameters(dataContainer.Document);
|
||||
param.SetParam("operator", operatorInfo.Name);
|
||||
|
||||
using (AgentOperator agentOperator = new AgentOperator(dataContainer, operatorInfo))
|
||||
{
|
||||
agentOperator.CreateOrUpdate();
|
||||
}
|
||||
|
||||
await requestContext.SendResult(result);
|
||||
});
|
||||
}
|
||||
|
||||
internal async Task HandleUpdateAgentOperatorRequest(UpdateAgentOperatorParams parameters, RequestContext<UpdateAgentOperatorResult> requestContext)
|
||||
{
|
||||
await requestContext.SendResult(null);
|
||||
}
|
||||
|
||||
internal async Task HandleDeleteAgentOperatorRequest(DeleteAgentOperatorParams parameters, RequestContext<DeleteAgentOperatorResult> requestContext)
|
||||
{
|
||||
await requestContext.SendResult(null);
|
||||
}
|
||||
|
||||
#endregion // "Operator Handlers"
|
||||
|
||||
|
||||
#region "Proxy Handlers"
|
||||
|
||||
internal async Task HandleAgentProxiesRequest(AgentProxiesParams parameters, RequestContext<AgentProxiesResult> requestContext)
|
||||
{
|
||||
await requestContext.SendResult(null);
|
||||
}
|
||||
|
||||
internal async Task HandleCreateAgentProxyRequest(CreateAgentProxyParams parameters, RequestContext<CreateAgentProxyResult> requestContext)
|
||||
{
|
||||
bool succeeded = await ConfigureAgentProxy(
|
||||
parameters.OwnerUri,
|
||||
parameters.Proxy.AccountName,
|
||||
parameters.Proxy,
|
||||
AgentConfigAction.Create);
|
||||
|
||||
await requestContext.SendResult(new CreateAgentProxyResult()
|
||||
{
|
||||
Succeeded = succeeded
|
||||
});
|
||||
}
|
||||
|
||||
internal async Task HandleUpdateAgentProxyRequest(UpdateAgentProxyParams parameters, RequestContext<UpdateAgentProxyResult> requestContext)
|
||||
{
|
||||
bool succeeded = await ConfigureAgentProxy(
|
||||
parameters.OwnerUri,
|
||||
parameters.OriginalProxyName,
|
||||
parameters.Proxy,
|
||||
AgentConfigAction.Update);
|
||||
|
||||
await requestContext.SendResult(new UpdateAgentProxyResult()
|
||||
{
|
||||
Succeeded = succeeded
|
||||
});
|
||||
}
|
||||
|
||||
internal async Task HandleDeleteAgentProxyRequest(DeleteAgentProxyParams parameters, RequestContext<DeleteAgentProxyResult> requestContext)
|
||||
{
|
||||
bool succeeded = await ConfigureAgentProxy(
|
||||
parameters.OwnerUri,
|
||||
parameters.Proxy.AccountName,
|
||||
parameters.Proxy,
|
||||
AgentConfigAction.Drop);
|
||||
|
||||
await requestContext.SendResult(new DeleteAgentProxyResult()
|
||||
{
|
||||
Succeeded = succeeded
|
||||
});
|
||||
}
|
||||
|
||||
internal async Task<bool> ConfigureAgentProxy(
|
||||
string ownerUri,
|
||||
string accountName,
|
||||
AgentProxyInfo proxy,
|
||||
AgentConfigAction configAction)
|
||||
{
|
||||
return await Task<bool>.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
ownerUri,
|
||||
out connInfo);
|
||||
|
||||
CDataContainer dataContainer = AdminService.CreateDataContainer(connInfo, databaseExists: true);
|
||||
STParameters param = new STParameters(dataContainer.Document);
|
||||
param.SetParam("proxyaccount", accountName);
|
||||
|
||||
using (AgentProxyAccount agentProxy = new AgentProxyAccount(dataContainer, proxy))
|
||||
{
|
||||
if (configAction == AgentConfigAction.Create)
|
||||
{
|
||||
return agentProxy.Create();
|
||||
}
|
||||
else if (configAction == AgentConfigAction.Update)
|
||||
{
|
||||
return agentProxy.Update();
|
||||
}
|
||||
else if (configAction == AgentConfigAction.Drop)
|
||||
{
|
||||
return agentProxy.Drop();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// log exception here
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion // "Proxy Handlers"
|
||||
}
|
||||
}
|
||||
|
||||
976
src/Microsoft.SqlTools.ServiceLayer/Agent/Common/AgentActions.cs
Normal file
976
src/Microsoft.SqlTools.ServiceLayer/Agent/Common/AgentActions.cs
Normal file
@@ -0,0 +1,976 @@
|
||||
//
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
/// <summary>
|
||||
/// Execution mode enumeration Success if execution succeeded of Failure otherwise for now.
|
||||
/// This enumeration might be refined more as there are needs for it
|
||||
/// </summary>
|
||||
public enum ExecutionMode
|
||||
{
|
||||
/// <summary>
|
||||
/// indicates that the operation failed
|
||||
/// </summary>
|
||||
Failure = 0,
|
||||
|
||||
/// <summary>
|
||||
/// indicates that the operation succeded
|
||||
/// </summary>
|
||||
Success,
|
||||
|
||||
/// <summary>
|
||||
/// indicates that the operation was canceled
|
||||
/// </summary>
|
||||
Cancel
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
public class PreProcessExecutionInfo
|
||||
{
|
||||
private RunType runType;
|
||||
private string script;
|
||||
private PreProcessExecutionInfo() {}
|
||||
|
||||
internal PreProcessExecutionInfo(RunType runType)
|
||||
{
|
||||
this.runType = runType;
|
||||
}
|
||||
|
||||
public RunType RunType
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.runType;
|
||||
}
|
||||
}
|
||||
|
||||
public string Script
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.script;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.script = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IExecutionAwareSqlControlCollection allows control's container to do pre and post
|
||||
/// processing of the execution commands
|
||||
/// </summary>
|
||||
public interface IExecutionAwareSqlControlCollection : ISqlControlCollection
|
||||
{
|
||||
/// <summary>
|
||||
/// called before dialog's host executes actions on all panels in the dialog one by one.
|
||||
/// If something fails inside this function and the execution should be aborted,
|
||||
/// it can either raise an exception [in which case the framework will show message box with exception text]
|
||||
/// or set executionResult out parameter to be ExecutionMode.Failure
|
||||
/// NOTE: it might be called from worker thread
|
||||
/// </summary>
|
||||
/// <param name="executionInfo">information about execution action</param>
|
||||
/// <param name="executionResult">result of the execution</param>
|
||||
/// <returns>
|
||||
/// true if regular execution should take place, false if everything
|
||||
/// has been done by this function
|
||||
/// NOTE: in case of returning false during scripting operation
|
||||
/// PreProcessExecutionInfo.Script property of executionInfo parameter
|
||||
/// MUST be set by this function [if execution result is success]
|
||||
/// </returns>
|
||||
bool PreProcessExecution(PreProcessExecutionInfo executionInfo, out ExecutionMode executionResult);
|
||||
|
||||
/// <summary>
|
||||
/// called when the host received Cancel request. NOTE: this method can return while
|
||||
/// operation is still being canceled
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the host should do standard cancel for the currently running view or
|
||||
/// false if the Cancel operation was done entirely inside this method and there is nothing
|
||||
/// extra that should be done
|
||||
/// </returns>
|
||||
bool Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// called after dialog's host executes actions on all panels in the dialog one by one
|
||||
/// NOTE: it might be called from worker thread
|
||||
/// </summary>
|
||||
/// <param name="executionMode">result of the execution</param>
|
||||
/// <param name="runType">type of execution</param>
|
||||
void PostProcessExecution(RunType runType, ExecutionMode executionMode);
|
||||
|
||||
/// <summary>
|
||||
/// called before dialog's host executes OnReset method on all panels in the dialog one by one
|
||||
/// NOTE: it might be called from worker thread
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if regular execution should take place, false if everything
|
||||
/// has been done by this function
|
||||
/// </returns>
|
||||
bool PreProcessReset();
|
||||
|
||||
/// <summary>
|
||||
/// called after dialog's host executes OnReset method on all panels in the dialog one by one
|
||||
/// NOTE: it might be called from worker thread
|
||||
/// </summary>
|
||||
void PostProcessReset();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
#region interfaces
|
||||
/// <summary>
|
||||
/// Interface that supports the delegation of individual actions in the progress dialog
|
||||
/// to individual classes.
|
||||
/// </summary>
|
||||
public interface IProgressItem
|
||||
{
|
||||
/// <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>
|
||||
ProgressStatus DoAction(ProgressItemCollection actions, int index);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
/// <summary>
|
||||
/// defines notion of sitable object
|
||||
/// </summary>
|
||||
public interface IObjectWithSite
|
||||
{
|
||||
void SetSite(System.IServiceProvider sp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ISqlControlCollection allows access to a collection of dialog views
|
||||
/// </summary>
|
||||
public interface ISqlControlCollection : IObjectWithSite
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,644 @@
|
||||
//
|
||||
// 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.Drawing;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Specialized;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Diagnostics;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Management
|
||||
{
|
||||
/// <summary>
|
||||
/// base class that can be used to derived from for the main classes [containers] of the dialogs
|
||||
/// </summary>
|
||||
public class ManagementActionBase : IDisposable
|
||||
{
|
||||
#region Members
|
||||
|
||||
/// <summary>
|
||||
/// selected node as specified to SelectNode method
|
||||
/// </summary>
|
||||
//private TreeNode selectedNode;
|
||||
|
||||
/// <summary>
|
||||
/// service provider of our host. We should direct all host-specific requests to the services
|
||||
/// implemented by this provider
|
||||
/// </summary>
|
||||
private IServiceProvider serviceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// data container with initialization-related information
|
||||
/// </summary>
|
||||
private CDataContainer dataContainer;
|
||||
//whether we assume complete ownership over it.
|
||||
//We set this member once the dataContainer is set to be non-null
|
||||
private bool ownDataContainer = true;
|
||||
|
||||
//if derived class tries to call a protected method that relies on service provider,
|
||||
//and the service provider hasn't been set yet, we will cache the values and will
|
||||
//propagate them when we get the provider set
|
||||
//private System.Drawing.Icon cachedIcon = null;
|
||||
private string cachedCaption = null;
|
||||
|
||||
//SMO Server connection that MUST be used for all enumerator calls
|
||||
//We'll get this object out of CDataContainer, that must be initialized
|
||||
//property by the initialization code
|
||||
private ServerConnection serverConnection;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public ManagementActionBase()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable implementation
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
//BUGBUG - do we need finalizer
|
||||
Dispose(true);//call protected virtual method
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// do the deterministic cleanup
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
//dispose CDataContainer if needed
|
||||
if (this.dataContainer != null)
|
||||
{
|
||||
if (this.ownDataContainer)
|
||||
{
|
||||
this.dataContainer.Dispose();
|
||||
}
|
||||
this.dataContainer = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IObjectWithSite implementation
|
||||
|
||||
public virtual void SetSite(IServiceProvider sp)
|
||||
{
|
||||
if (sp == null)
|
||||
{
|
||||
throw new ArgumentNullException("sp");
|
||||
}
|
||||
|
||||
//allow to be sited only once
|
||||
if (this.serviceProvider == null)
|
||||
{
|
||||
//cache the service provider
|
||||
this.serviceProvider = sp;
|
||||
|
||||
//call protected virtual method to enable derived classes to do initialization
|
||||
//OnHosted();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IExecutionAwareSqlControlCollection implementation
|
||||
|
||||
/// <summary>
|
||||
/// called before dialog's host executes actions on all panels in the dialog one by one.
|
||||
/// If something fails inside this function and the execution should be aborted,
|
||||
/// it can either raise an exception [in which case the framework will show message box with exception text]
|
||||
/// or set executionResult out parameter to be ExecutionMode.Failure
|
||||
/// NOTE: it might be called from worker thread
|
||||
/// </summary>
|
||||
/// <param name="executionInfo">information about execution action</param>
|
||||
/// <param name="executionResult">result of the execution</param>
|
||||
/// <returns>
|
||||
/// true if regular execution should take place, false if everything
|
||||
/// has been done by this function
|
||||
/// NOTE: in case of returning false during scripting operation
|
||||
/// PreProcessExecutionInfo.Script property of executionInfo parameter
|
||||
/// MUST be set by this function [if execution result is success]
|
||||
/// </returns>
|
||||
public bool PreProcessExecution(PreProcessExecutionInfo executionInfo, out ExecutionMode executionResult)
|
||||
{
|
||||
//we start from failure
|
||||
executionResult = ExecutionMode.Failure;
|
||||
|
||||
//OK, we do server switching for scripting for SQL/Analysis Server execution here
|
||||
RunType runType = executionInfo.RunType;
|
||||
if (IsScripting(runType))
|
||||
{
|
||||
if (!PreProcessScripting(executionInfo, out executionResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (DataContainer != null)
|
||||
{
|
||||
//we take over execution here. We substitute the server here for AMO and SQL
|
||||
//dialogs
|
||||
if (DataContainer.ContainerServerType == CDataContainer.ServerType.SQL)
|
||||
{
|
||||
ExecuteForSql(executionInfo, out executionResult);
|
||||
return false;//execution of the entire control was done here
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// call virtual function to do regular execution
|
||||
return DoPreProcessExecution(executionInfo.RunType, out executionResult);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// whether we own our DataContainer or not. Depending on this value it will or won't be
|
||||
/// disposed in our Dispose method
|
||||
/// </summary>
|
||||
protected virtual bool OwnDataContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
//by default we own it
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// called by IExecutionAwareSqlControlCollection.PreProcessExecution to enable derived
|
||||
/// classes to take over execution of the dialog and do entire execution in this method
|
||||
/// rather than having the framework to execute dialog views one by one.
|
||||
///
|
||||
/// NOTE: it might be called from non-UI thread
|
||||
/// </summary>
|
||||
/// <param name="runType"></param>
|
||||
/// <param name="executionResult"></param>
|
||||
/// <returns>
|
||||
/// true if regular execution should take place, false if everything,
|
||||
/// has been done by this function
|
||||
/// </returns>
|
||||
protected virtual bool DoPreProcessExecution(RunType runType, out ExecutionMode executionResult)
|
||||
{
|
||||
//ask the framework to do normal execution by calling OnRunNOw methods
|
||||
//of the views one by one
|
||||
executionResult = ExecutionMode.Success;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// called before dialog's host executes OnReset method on all panels in the dialog one by one
|
||||
/// NOTE: it might be called from worker thread
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if regular execution should take place, false if everything
|
||||
/// has been done by this function
|
||||
/// </returns>
|
||||
/// <returns></returns>
|
||||
protected virtual bool DoPreProcessReset()
|
||||
{
|
||||
if ((this.dataContainer != null) && this.dataContainer.IsNewObject)
|
||||
{
|
||||
this.dataContainer.Reset();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// called after dialog's host executes OnReset method on all panels in the dialog one by one
|
||||
/// NOTE: it might be called from worker thread
|
||||
/// </summary>
|
||||
protected virtual void DoPostProcessReset()
|
||||
{
|
||||
//nothing in the base class
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to intercept scripting operation
|
||||
/// </summary>
|
||||
/// <param name="executionInfo"></param>
|
||||
/// <param name="executionResult"></param>
|
||||
/// <returns>
|
||||
/// true if regular execution should take place, false the script
|
||||
/// has been created by this function
|
||||
/// </returns>
|
||||
protected virtual bool PreProcessScripting(PreProcessExecutionInfo executionInfo, out ExecutionMode executionResult)
|
||||
{
|
||||
//we don't do anything here, but we enable derived classes to do something...
|
||||
executionResult = ExecutionMode.Success;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CDataContainer accessor
|
||||
/// </summary>
|
||||
protected CDataContainer DataContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.dataContainer;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.dataContainer = value;
|
||||
this.ownDataContainer = OwnDataContainer; //cache the value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// /// <summary>
|
||||
// /// SMO Server connection that MUST be used for all enumerator calls
|
||||
// /// We'll get this object out of CDataContainer, that must be initialized
|
||||
// /// property by the initialization code
|
||||
// /// </summary>
|
||||
protected ServerConnection ServerConnection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.serverConnection == null && this.dataContainer != null &&
|
||||
this.dataContainer.ContainerServerType == CDataContainer.ServerType.SQL)
|
||||
{
|
||||
this.serverConnection = this.dataContainer.ServerConnection;
|
||||
}
|
||||
|
||||
//it CAN be null here if dataContainer hasn't been set or the container type is non SQL
|
||||
return this.serverConnection;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// checks whether given run time represents one of scripting options
|
||||
/// </summary>
|
||||
/// <param name="runType"></param>
|
||||
/// <returns></returns>
|
||||
protected static bool IsScripting(RunType runType)
|
||||
{
|
||||
return(runType != RunType.RunNow && runType != RunType.RunNowAndExit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// calls DoPreProcessExecution and if it returns false, then it will execute all initialized views
|
||||
/// one by one.
|
||||
/// This method allows derived classes to do both preprocessing and normal execution in a way
|
||||
/// that the framework would normally do. Use this method for special cases when derived class
|
||||
/// should really handle entire execution while doing exactly the same actions as the framework
|
||||
/// would do
|
||||
/// </summary>
|
||||
/// <param name="runType"></param>
|
||||
/// <returns>
|
||||
/// result of the execution. It will let exception fly out if it was raised during execution
|
||||
/// </returns>
|
||||
protected ExecutionMode DoPreProcessExecutionAndRunViews(RunType runType)
|
||||
{
|
||||
ExecutionMode executionResult;
|
||||
if (DoPreProcessExecution(runType, out executionResult))
|
||||
{
|
||||
//true return value means that we need to do execution ourselves
|
||||
//executionResult = PanelExecutionHandler.Run(runType, this);
|
||||
}
|
||||
|
||||
return executionResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// determines whether we need to substitute SMO/AMO server objects with the
|
||||
/// temporary ones while doing scripting
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool NeedToSwitchServer
|
||||
{
|
||||
get
|
||||
{
|
||||
ServerSwitchingAttribute switchingAttrib =
|
||||
Utils.GetCustomAttribute(this, typeof(ServerSwitchingAttribute)) as ServerSwitchingAttribute;
|
||||
|
||||
if (DataContainer == null)
|
||||
{
|
||||
if (switchingAttrib != null)
|
||||
{
|
||||
return switchingAttrib.NeedToSwtichServerObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
if (DataContainer.ContainerServerType == CDataContainer.ServerType.SQL)
|
||||
{
|
||||
if (switchingAttrib != null)
|
||||
{
|
||||
return switchingAttrib.NeedToSwtichServerObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;//switch by default in SQL case
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual ServerConnection GetServerConnectionForScript()
|
||||
{
|
||||
return this.dataContainer.Server.ConnectionContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// builds a script string from SMO string collections. This function should
|
||||
/// probably be moved to SMO. Also we need a way to specify the tsql batch
|
||||
/// separator which for now is GO
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string BuildSqlScript()
|
||||
{
|
||||
SqlSmoObject sqlDialogSubject = null;
|
||||
try
|
||||
{
|
||||
sqlDialogSubject = this.DataContainer.SqlDialogSubject;
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
//We may not have a valid dialog subject here (such as if the object hasn't been created yet)
|
||||
//so in that case we'll just ignore it as that's a normal scenario.
|
||||
}
|
||||
|
||||
StringCollection sc = GetServerConnectionForScript().CapturedSql.Text;
|
||||
//Scripting may happen on either the server ExecutionManager or the
|
||||
//ExecutionManager of the object itself. So we make sure to check
|
||||
//the subject text if the server ExecutionManager didn't have any
|
||||
//scripts after doing the scripting
|
||||
if (sc.Count == 0 && sqlDialogSubject != null)
|
||||
{
|
||||
sc = sqlDialogSubject.ExecutionManager.ConnectionContext.CapturedSql.Text;
|
||||
}
|
||||
int i;
|
||||
StringBuilder script = new StringBuilder(4096);
|
||||
|
||||
if (sc != null)
|
||||
{
|
||||
for (i = 0; i < sc.Count; i ++)
|
||||
{
|
||||
script.AppendFormat("{0}\r\nGO\r\n", sc[i].ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return script.ToString();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// called when we need to script a Sql server dlg.
|
||||
/// </summary>
|
||||
/// <param name="executionInfo"></param>
|
||||
/// <param name="executionResult"></param>
|
||||
private void ExecuteForSql(PreProcessExecutionInfo executionInfo, out ExecutionMode executionResult)
|
||||
{
|
||||
Microsoft.SqlServer.Management.Smo.Server oldServer = null;
|
||||
if (NeedToSwitchServer)
|
||||
{
|
||||
// We use a new instance of the SMO Server object every time we script
|
||||
// so that any changes that are made to the SMO server while scripting are
|
||||
// not kept when the script operation is completed.
|
||||
oldServer = DataContainer.Server;
|
||||
|
||||
//BUGBUG - see if we can use copy ctor instead
|
||||
DataContainer.Server = new Microsoft.SqlServer.Management.Smo.Server(DataContainer.ServerConnection);
|
||||
}
|
||||
|
||||
String szScript = null;
|
||||
bool isScripting = IsScripting(executionInfo.RunType);
|
||||
var executionModeOriginal = GetServerConnectionForScript().SqlExecutionModes;
|
||||
//For Azure the ExecutionManager is different depending on which ExecutionManager
|
||||
//used - one at the Server level and one at the Database level. So to ensure we
|
||||
//don't use the wrong execution mode we need to set the mode for both (for on-prem
|
||||
//this will essentially be a no-op)
|
||||
SqlExecutionModes subjectExecutionModeOriginal = executionModeOriginal;
|
||||
SqlSmoObject sqlDialogSubject = null;
|
||||
try
|
||||
{
|
||||
sqlDialogSubject = this.DataContainer.SqlDialogSubject;
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
//We may not have a valid dialog subject here (such as if the object hasn't been created yet)
|
||||
//so in that case we'll just ignore it as that's a normal scenario.
|
||||
}
|
||||
|
||||
if (sqlDialogSubject != null)
|
||||
{
|
||||
subjectExecutionModeOriginal = sqlDialogSubject.ExecutionManager.ConnectionContext.SqlExecutionModes;
|
||||
}
|
||||
try
|
||||
{
|
||||
SqlExecutionModes newMode = isScripting
|
||||
? SqlExecutionModes.CaptureSql
|
||||
: SqlExecutionModes.ExecuteSql;
|
||||
//now, do the execution itself
|
||||
GetServerConnectionForScript().SqlExecutionModes = newMode;
|
||||
if (sqlDialogSubject != null)
|
||||
{
|
||||
sqlDialogSubject.ExecutionManager.ConnectionContext.SqlExecutionModes = newMode;
|
||||
}
|
||||
|
||||
executionResult = DoPreProcessExecutionAndRunViews(executionInfo.RunType);
|
||||
|
||||
if (isScripting)
|
||||
{
|
||||
if (executionResult == ExecutionMode.Success)
|
||||
{
|
||||
szScript = BuildSqlScript();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
GetServerConnectionForScript().SqlExecutionModes = executionModeOriginal;
|
||||
|
||||
if (isScripting)
|
||||
{
|
||||
GetServerConnectionForScript().CapturedSql.Clear();
|
||||
}
|
||||
|
||||
if (sqlDialogSubject != null)
|
||||
{
|
||||
sqlDialogSubject.ExecutionManager.ConnectionContext.SqlExecutionModes = subjectExecutionModeOriginal;
|
||||
if (isScripting)
|
||||
{
|
||||
sqlDialogSubject.ExecutionManager.ConnectionContext.CapturedSql.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
//see if we need to restore the server
|
||||
if (oldServer != null)
|
||||
{
|
||||
DataContainer.Server = oldServer;
|
||||
}
|
||||
}
|
||||
|
||||
if (isScripting)
|
||||
{
|
||||
executionInfo.Script = szScript;
|
||||
}
|
||||
}
|
||||
|
||||
// #region ICustomAttributeProvider
|
||||
// object[] System.Reflection.ICustomAttributeProvider.GetCustomAttributes(bool inherit)
|
||||
// {
|
||||
// //we merge attributes from 2 sources: type attributes and the derived classes, giving preference
|
||||
// //to the derived classes
|
||||
// return GetMergedArray(DoGetCustomAttributes(inherit), GetType().GetCustomAttributes(inherit));
|
||||
// }
|
||||
// object[] System.Reflection.ICustomAttributeProvider.GetCustomAttributes(Type attributeType, bool inherit)
|
||||
// {
|
||||
// //we merge attributes from 2 sources: type attributes and the derived classes, giving preference
|
||||
// //to the derived classes
|
||||
// return GetMergedArray(DoGetCustomAttributes(attributeType, inherit),
|
||||
// GetType().GetCustomAttributes(attributeType, inherit));
|
||||
// }
|
||||
// bool System.Reflection.ICustomAttributeProvider.IsDefined(Type attributeType, bool inherit)
|
||||
// {
|
||||
// //we merge attributes from 2 sources: type attributes and the derived classes, giving preference
|
||||
// //to the derived classes
|
||||
// if (!DoIsDefined(attributeType, inherit))
|
||||
// {
|
||||
// return GetType().IsDefined(attributeType, inherit);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// #endregion
|
||||
// #region ICustomAttributeProvider helpers
|
||||
// protected virtual object[] DoGetCustomAttributes(bool inherit)
|
||||
// {
|
||||
// return GetMergedArray(DoGetCustomAttributes(typeof(ScriptTypeAttribute), inherit),
|
||||
// DoGetCustomAttributes(typeof(DialogScriptableAttribute), inherit));
|
||||
// }
|
||||
// protected virtual object[] DoGetCustomAttributes(Type attributeType, bool inherit)
|
||||
// {
|
||||
// //if the type specifies this attribute, we don't bother - it overrides
|
||||
// //our behavior
|
||||
// object[] typeAttribs = GetType().GetCustomAttributes(attributeType, inherit);
|
||||
// if (typeAttribs != null && typeAttribs.Length > 0)
|
||||
// {
|
||||
// return null;
|
||||
// }
|
||||
// //we expose default custom attribute for script type
|
||||
// if (attributeType.Equals(typeof(ScriptTypeAttribute)))
|
||||
// {
|
||||
// string scriptType = ScriptType;
|
||||
// if (scriptType != null)
|
||||
// {
|
||||
// return new object[] {new ScriptTypeAttribute(scriptType)};
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
// else if (attributeType.Equals(typeof(DialogScriptableAttribute)))
|
||||
// {
|
||||
// bool canScriptToWindow = true;
|
||||
// bool canScriptToFile = true;
|
||||
// bool canScriptToClipboard = true;
|
||||
// bool canScriptToJob = true;
|
||||
// GetScriptableOptions(out canScriptToWindow,
|
||||
// out canScriptToFile,
|
||||
// out canScriptToClipboard,
|
||||
// out canScriptToJob);
|
||||
// return new object[] {new DialogScriptableAttribute(canScriptToWindow,
|
||||
// canScriptToFile,
|
||||
// canScriptToClipboard,
|
||||
// canScriptToJob)};
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// protected virtual bool DoIsDefined(Type attributeType, bool inherit)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// /// <summary>
|
||||
// /// detects whether script types are applicable for this dlg or not. By default
|
||||
// /// the framework relies on DialogScriptableAttribute set on the dlg class and won't
|
||||
// /// call this method if the attribute is specified
|
||||
// /// By default we assume that all script types are enabled
|
||||
// /// </summary>
|
||||
// /// <param name="?"></param>
|
||||
// /// <param name="?"></param>
|
||||
// /// <param name="?"></param>
|
||||
// protected virtual void GetScriptableOptions(out bool canScriptToWindow,
|
||||
// out bool canScriptToFile,
|
||||
// out bool canScriptToClipboard,
|
||||
// out bool canScriptToJob)
|
||||
// {
|
||||
// canScriptToWindow = canScriptToFile = canScriptToClipboard = canScriptToJob = true;
|
||||
// }
|
||||
// #endregion
|
||||
// protected IServiceProvider ServiceProvider
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// if (this.serviceProvider == null)
|
||||
// {
|
||||
// STrace.Assert(false, "Cannot work without service provider!");
|
||||
// STrace.LogExThrow();
|
||||
// //BUGBUG - should we have our own exception here?
|
||||
// throw new InvalidOperationException();
|
||||
// }
|
||||
// return this.serviceProvider;
|
||||
// }
|
||||
// }
|
||||
// /// <summary>
|
||||
// /// returns combination of the given 2 arrays
|
||||
// /// </summary>
|
||||
// /// <param name="array1"></param>
|
||||
// /// <param name="array2"></param>
|
||||
// /// <returns></returns>
|
||||
// protected object[] GetMergedArray(object[] array1, object[] array2)
|
||||
// {
|
||||
// if (array1 == null)
|
||||
// {
|
||||
// return array2;
|
||||
// }
|
||||
// else if (array2 == null)
|
||||
// {
|
||||
// return array1;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// object[] finalReturnValue = new object[array1.Length + array2.Length];
|
||||
// array1.CopyTo(finalReturnValue, 0);
|
||||
// array2.CopyTo(finalReturnValue, array1.Length);
|
||||
// return finalReturnValue;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
//
|
||||
// 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.Globalization;
|
||||
using System.Collections;
|
||||
using System.Threading;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows for the mapping of objects that implement IProgressItem to individual items in the
|
||||
/// progress dialog.
|
||||
/// </summary>
|
||||
public class ProgressItemCollection : ICollection
|
||||
{
|
||||
#region internal helper classes
|
||||
/// <summary>
|
||||
/// Allows us to map an action to its index in the progress dialog.
|
||||
/// </summary>
|
||||
public class ActionIndexMap
|
||||
{
|
||||
/// <summary>
|
||||
/// action
|
||||
/// </summary>
|
||||
public IProgressItem Action;
|
||||
/// <summary>
|
||||
/// index
|
||||
/// </summary>
|
||||
public int Index;
|
||||
|
||||
public ActionIndexMap(IProgressItem action)
|
||||
{
|
||||
this.Action = action;
|
||||
// index isn't known yet
|
||||
this.Index = -1;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region private data members
|
||||
/// <summary>
|
||||
/// list of actions we will perform.
|
||||
/// </summary>
|
||||
private ArrayList actions = new ArrayList();
|
||||
#endregion
|
||||
|
||||
#region construction
|
||||
public ProgressItemCollection()
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region properties
|
||||
|
||||
private bool closeOnUserCancel = false;
|
||||
/// <summary>
|
||||
/// Indicates whether to close the dialog immediately if the user cancels an operation
|
||||
/// </summary>
|
||||
public bool CloseOnUserCancel
|
||||
{
|
||||
get
|
||||
{
|
||||
return closeOnUserCancel;
|
||||
}
|
||||
set
|
||||
{
|
||||
closeOnUserCancel = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool automaticClose = false;
|
||||
/// <summary>
|
||||
/// Indicates whether to automatically close the dialog when all actions are complete
|
||||
/// successfully.
|
||||
/// </summary>
|
||||
public bool CloseOnSuccessfulCompletion
|
||||
{
|
||||
get
|
||||
{
|
||||
return automaticClose;
|
||||
}
|
||||
set
|
||||
{
|
||||
automaticClose = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool quitOnError = false;
|
||||
/// <summary>
|
||||
/// Indicates whether the operation should be terminated if any individual step fails.
|
||||
/// </summary>
|
||||
public bool QuitOnError
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.quitOnError;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.quitOnError = value;
|
||||
}
|
||||
}
|
||||
private OperationStatus operationStatus = OperationStatus.Invalid;
|
||||
/// <summary>
|
||||
/// Indicates the status of the operation.
|
||||
/// </summary>
|
||||
public OperationStatus OperationStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.operationStatus;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Progress object this action collection will work with
|
||||
/// </summary>
|
||||
private IProgress progress = null;
|
||||
public IProgress Progress
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.progress;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (this.progress != value)
|
||||
{
|
||||
this.progress = value;
|
||||
if (this.progress != null)
|
||||
{
|
||||
// add the actions to the progress dialog, and
|
||||
// fixup our event handler
|
||||
FixUpActionsToProgress();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region public overrides
|
||||
/// <summary>
|
||||
/// Generate a string representaion of this object. It will convert all of it's IProgressItem members
|
||||
/// to strings in a new line.
|
||||
/// </summary>
|
||||
/// <returns>string description of the actions this object contains</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
// if there are no actions then just return the default ToString
|
||||
if (this.actions == null || this.actions.Count == 0)
|
||||
{
|
||||
return base.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// convert all of the actions to strings on their own line
|
||||
StringBuilder sb = new StringBuilder(((ActionIndexMap)actions[0]).Action.ToString());
|
||||
for (int i = 1; i < this.actions.Count; i++)
|
||||
{
|
||||
sb.AppendFormat(CultureInfo.InvariantCulture, "\r\n{0}", ((ActionIndexMap)actions[i]).Action.ToString());
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ICollection implementation
|
||||
/// <summary>
|
||||
/// Gets the number of actions in this collection
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.actions.Count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// not supported
|
||||
/// </summary>
|
||||
public bool IsSynchronized
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// not supported
|
||||
/// </summary>
|
||||
public object SyncRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
public void CopyTo(IProgressItem[] array, int start)
|
||||
{
|
||||
this.actions.CopyTo(array, start);
|
||||
}
|
||||
public void CopyTo(Array array, int start)
|
||||
{
|
||||
this.actions.CopyTo(array, start);
|
||||
}
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
return this.actions.GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region public methods
|
||||
/// <summary>
|
||||
/// Add an action to the collection
|
||||
/// </summary>
|
||||
/// <param name="action">action to be added</param>
|
||||
public void AddAction(IProgressItem action)
|
||||
{
|
||||
ActionIndexMap map = new ActionIndexMap(action);
|
||||
this.actions.Add(map);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region internal implementation
|
||||
/// <summary>
|
||||
/// delegate called when the progress dialog wants us to perform work on a new thread.
|
||||
/// </summary>
|
||||
private void DoWorkOnThread()
|
||||
{
|
||||
if (this.Progress == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
System.Threading.Thread.CurrentThread.Name = "Worker thread for " + progress.GetType();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{ }
|
||||
|
||||
// default to succeeded.
|
||||
operationStatus = OperationStatus.Success;
|
||||
|
||||
// carry out each action.
|
||||
foreach (ActionIndexMap map in this.actions)
|
||||
{
|
||||
// abort if the user has decided to cancel.
|
||||
if (this.Progress.IsAborted)
|
||||
{
|
||||
this.Progress.UpdateActionStatus(map.Index, ProgressStatus.Aborted);
|
||||
operationStatus = OperationStatus.Aborted;
|
||||
break;
|
||||
}
|
||||
ProgressStatus stepStatus = ProgressStatus.Invalid;
|
||||
try
|
||||
{
|
||||
// perform the action.
|
||||
stepStatus = map.Action.DoAction(this, map.Index);
|
||||
this.Progress.UpdateActionStatus(map.Index, stepStatus);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// fail the step with errors, add the error messages to the control.
|
||||
this.Progress.AddActionException(map.Index, e);
|
||||
this.Progress.UpdateActionStatus(map.Index, ProgressStatus.Error);
|
||||
stepStatus = ProgressStatus.Error;
|
||||
}
|
||||
if (stepStatus == ProgressStatus.Error)
|
||||
{
|
||||
// see if we're supposed to fail if any step fails
|
||||
if (this.QuitOnError == true)
|
||||
{
|
||||
// fail and quit
|
||||
this.operationStatus = OperationStatus.Error;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.operationStatus = OperationStatus.CompletedWithErrors;
|
||||
}
|
||||
}
|
||||
else if (stepStatus != ProgressStatus.Success)
|
||||
{
|
||||
this.operationStatus = OperationStatus.CompletedWithErrors;
|
||||
}
|
||||
}
|
||||
|
||||
// tell the dialog we're finishing.
|
||||
this.Progress.WorkerThreadExiting(operationStatus);
|
||||
|
||||
// close the dialog if asked to. We have to put this after
|
||||
// the WorkerThreadExiting call because the progress dialog
|
||||
// won't allow itself to be closed until worker thread says
|
||||
// it's finished.
|
||||
if ((this.CloseOnSuccessfulCompletion && (this.operationStatus == OperationStatus.Success)) ||
|
||||
(this.CloseOnUserCancel && this.Progress.IsAborted))
|
||||
{
|
||||
//((Form)this.Progress).BeginInvoke(new CloseProgressWindowCallback(CloseProgressWindowHandler), new object[] { this.Progress });
|
||||
}
|
||||
}
|
||||
|
||||
private delegate void CloseProgressWindowCallback(IProgress progress);
|
||||
private void CloseProgressWindowHandler(IProgress progress)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the actions to an IProgress interface.
|
||||
/// </summary>
|
||||
private void FixUpActionsToProgress()
|
||||
{
|
||||
if (this.Progress == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// add actions
|
||||
foreach (ActionIndexMap map in this.actions)
|
||||
{
|
||||
map.Index = this.Progress.AddAction(map.Action.ToString());
|
||||
}
|
||||
// add our delegate
|
||||
this.Progress.WorkerThreadStart = new ThreadStart(this.DoWorkOnThread);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
//
|
||||
// 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.Drawing;
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumeration for status of individual actions
|
||||
/// </summary>
|
||||
public enum ProgressStatus
|
||||
{
|
||||
Invalid = -1,
|
||||
NotStarted, // Not started
|
||||
InProgress, // In progress
|
||||
Success, // Completed
|
||||
SuccessWithInfo, // Completed, display additional info
|
||||
Warning, // Completed with warning, display exceptions
|
||||
Error, // Not completed because of error, display exceptions
|
||||
Aborted, // Aborted
|
||||
RolledBack, // Rolled back because of a subsequent error
|
||||
StatusCount // = Number of status values - For validation only
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumeration for status of the overall operation
|
||||
/// </summary>
|
||||
public enum OperationStatus
|
||||
{
|
||||
Invalid = -1,
|
||||
InProgress, // In progress
|
||||
Success, // Completed successfully
|
||||
CompletedWithErrors, // Completed with non-fatal errors
|
||||
Error, // Not completed because of error
|
||||
Aborted, // Abort complete
|
||||
StatusCount // = Number of status values - For validation only
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface defining core functionality of a progress control container
|
||||
///
|
||||
/// NOTE: Refer to the comments for each method/property individually to determine
|
||||
/// whether it is thread-safe and may be used from the worker thread. Also note
|
||||
/// that some members are asynchronous.
|
||||
/// </summary>
|
||||
public interface IProgress
|
||||
{
|
||||
//-----------
|
||||
// Properties
|
||||
//-----------
|
||||
|
||||
/// <summary>
|
||||
/// The property that determines if the user should be allowed to abort the
|
||||
/// operation. The default value is true.
|
||||
///
|
||||
/// NOTE: This property is not thread safe. Set from UI thread.
|
||||
/// </summary>
|
||||
bool AllowAbort
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The confirmation prompt to display if the user hits the Abort button.
|
||||
/// The abort prompt should be worded such that the abort is confirmed
|
||||
/// if the user hits "Yes".
|
||||
///
|
||||
/// NOTE: This property is not thread safe. Set from UI thread.
|
||||
/// </summary>
|
||||
string AbortPrompt
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The ThreadStart delegate. The method referenced by this delegate is run by
|
||||
/// the worker thread to perform the operation.
|
||||
///
|
||||
/// NOTE: This property is not thread safe. Set from UI thread.
|
||||
/// </summary>
|
||||
ThreadStart WorkerThreadStart
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aborted status of the operation.
|
||||
///
|
||||
/// NOTE: This property is thread safe and may be called from the worker
|
||||
/// thread. Accessing this property may cause caller to block if UI
|
||||
/// is waiting for user confirmation of abort.
|
||||
/// </summary>
|
||||
bool IsAborted
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This property determines whether updates should be allowed for
|
||||
/// actions. If this is set to false, any calls that are made
|
||||
/// to add or update an action are ignored. The default value is true.
|
||||
///
|
||||
/// NOTE: This property is thread safe and may be called from the worker
|
||||
/// thread.
|
||||
/// </summary>
|
||||
bool ActionUpdateEnabled
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
//--------
|
||||
// Methods
|
||||
//--------
|
||||
|
||||
/// <summary>
|
||||
/// Add an action to the displayed list of actions. Actions are
|
||||
/// displayed in the order they are added. An action can be referenced
|
||||
/// in future calls using the zero-based index that is returned.
|
||||
///
|
||||
/// The description must be a non-empty string.
|
||||
///
|
||||
/// NOTE: This method is not thread safe. Call from the UI thread.
|
||||
/// </summary>
|
||||
/// <param name="description">Description of the action</param>
|
||||
/// <returns>The index of the newly added action.</returns>
|
||||
int AddAction(string description);
|
||||
|
||||
/// <summary>
|
||||
/// Add an action to the displayed list of actions. This is meant
|
||||
/// to be called from the worker thread to add an action after
|
||||
/// the operation is already in progress.
|
||||
///
|
||||
/// Actions are displayed in the order they are added. Use the
|
||||
/// zero-based index of the action based on past actions added
|
||||
/// to reference it in future calls. The description must be a
|
||||
/// non-empty string.
|
||||
///
|
||||
/// NOTE: This method is thread safe and asynchronous. It may be
|
||||
/// called from the worker thread.
|
||||
/// </summary>
|
||||
/// <param name="description">Description of the action</param>
|
||||
void AddActionDynamic(string description);
|
||||
|
||||
/// <summary>
|
||||
/// Update the description of an action
|
||||
///
|
||||
/// The description must be a non-empty string.
|
||||
///
|
||||
/// NOTE: This method is thread safe and asynchronous. It may be
|
||||
/// called from the worker thread.
|
||||
/// </summary>
|
||||
/// <param name="actionIndex">Index of the action</param>
|
||||
/// <param name="description">New description of the action</param>
|
||||
void UpdateActionDescription(int actionIndex, string description);
|
||||
|
||||
/// <summary>
|
||||
/// Update the status of an action
|
||||
///
|
||||
/// NOTE: This method is thread safe and asynchronous. It may be
|
||||
/// called from the worker thread.
|
||||
/// </summary>
|
||||
/// <param name="actionIndex">Index of the action</param>
|
||||
/// <param name="status">New status of the action</param>
|
||||
void UpdateActionStatus(int actionIndex, ProgressStatus status);
|
||||
|
||||
/// <summary>
|
||||
/// Update the progress of an action in terms of percentage complete
|
||||
///
|
||||
/// NOTE: This method is thread safe and asynchronous. It may be
|
||||
/// called from the worker thread.
|
||||
/// </summary>
|
||||
/// <param name="actionIndex">Index of the action</param>
|
||||
/// <param name="percentComplete">Percentage of the action that is complete (0-100)</param>
|
||||
void UpdateActionProgress(int actionIndex, int percentComplete);
|
||||
|
||||
/// <summary>
|
||||
/// Update the progress of an action with a text description of
|
||||
/// the progress
|
||||
///
|
||||
/// The description must be a non-empty string.
|
||||
///
|
||||
/// NOTE: This method is thread safe and asynchronous. It may be
|
||||
/// called from the worker thread.
|
||||
/// </summary>
|
||||
/// <param name="actionIndex">Index of the action</param>
|
||||
/// <param name="description">Description of progress</param>
|
||||
void UpdateActionProgress(int actionIndex, string description);
|
||||
|
||||
/// <summary>
|
||||
/// Add an exception to an action
|
||||
///
|
||||
/// Exceptions are displayed in the action grid only for actions
|
||||
/// with "Error" or "Warning" status.
|
||||
///
|
||||
/// NOTE: This method is thread safe and asynchronous. It may be
|
||||
/// called from the worker thread.
|
||||
/// </summary>
|
||||
/// <param name="actionIndex">Index of the action</param>
|
||||
/// <param name="e">Exception to be added</param>
|
||||
void AddActionException(int actionIndex, Exception e);
|
||||
|
||||
/// <summary>
|
||||
/// Add an info string to an action in the progress report control
|
||||
///
|
||||
/// Information strings are displayed in the action grid only for
|
||||
/// actions with "SuccessWithInfo" status. The info string must
|
||||
/// be a non-empty string. It should not be formatted or contain
|
||||
/// newline characters.
|
||||
///
|
||||
/// NOTE: This method is thread safe and asynchronous. It may be
|
||||
/// called from the worker thread.
|
||||
/// </summary>
|
||||
/// <param name="actionIndex">Index of the action</param>
|
||||
/// <param name="infoString">Information string to be added</param>
|
||||
void AddActionInfoString(int actionIndex, string infoString);
|
||||
|
||||
/// <summary>
|
||||
/// Call this method when the worker thread performing the operation
|
||||
/// is about to exit. The final result of the operation is supplied in
|
||||
/// the form of a OperationStatus value.
|
||||
///
|
||||
/// NOTE: This method is thread safe and asynchronous. It may be
|
||||
/// called from the worker thread.
|
||||
/// </summary>
|
||||
/// <param name="result">Result of the operation</param>
|
||||
void WorkerThreadExiting(OperationStatus result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumeration for status of the progress report control w.r.t the operation
|
||||
/// </summary>
|
||||
[System.Runtime.InteropServices.ComVisible(false)]
|
||||
public enum ProgressCtrlStatus
|
||||
{
|
||||
Invalid = -1,
|
||||
InProgress, // In progress
|
||||
Success, // Completed successfully
|
||||
CompletedWithErrors, // Completed with non-fatal errors
|
||||
Error, // Not completed because of error
|
||||
Aborting, // User clicked "Abort", aborting operation
|
||||
Aborted, // Abort complete
|
||||
Closed, // User clicked "Close"
|
||||
StatusCount // = Number of status values - For validation only
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delegate used with ProgressCtrlStatusChanged event.
|
||||
/// </summary>
|
||||
public delegate void ProgressCtrlStatusChangedEventHandler(object source, ProgressCtrlStatusChangedEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// EventArgs class for use with ProgressCtrlStatusChanged event
|
||||
/// </summary>
|
||||
sealed public class ProgressCtrlStatusChangedEventArgs : EventArgs
|
||||
{
|
||||
//------------------
|
||||
// Public Properties
|
||||
//------------------
|
||||
public ProgressCtrlStatus Status
|
||||
{
|
||||
get { return m_status; }
|
||||
set { m_status = value; }
|
||||
}
|
||||
|
||||
//-------------
|
||||
// Private Data
|
||||
//-------------
|
||||
private ProgressCtrlStatus m_status = ProgressCtrlStatus.Invalid;
|
||||
}
|
||||
|
||||
// Enumeration for progress action grid columns
|
||||
internal enum ProgressActionColumn
|
||||
{
|
||||
Invalid = -1,
|
||||
ActionStatusBitmap,
|
||||
ActionDescription,
|
||||
ActionStatusText,
|
||||
ActionMessage,
|
||||
ActionColumnCount // = Number of columns - For validation only
|
||||
}
|
||||
|
||||
// Enumeration for progress action display filter
|
||||
internal enum ProgressActionDisplayMode
|
||||
{
|
||||
Invalid = -1,
|
||||
DisplayAllActions,
|
||||
DisplayErrors,
|
||||
DisplaySuccess,
|
||||
DisplayWarnings,
|
||||
ActionDisplayModeCount // = Number of display modes - For validation only
|
||||
}
|
||||
}
|
||||
23
src/Microsoft.SqlTools.ServiceLayer/Agent/Common/RunType.cs
Normal file
23
src/Microsoft.SqlTools.ServiceLayer/Agent/Common/RunType.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
/// <summary>
|
||||
/// what type of actions does the worker know to execute
|
||||
/// </summary>
|
||||
public enum RunType
|
||||
{
|
||||
RunNow = 0,
|
||||
RunNowAndExit,
|
||||
ScriptToFile,
|
||||
ScriptToWindow,
|
||||
ScriptToClipboard,
|
||||
ScriptToJob
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom attribute that can be applied on particular DB commander to
|
||||
/// indicate whether the base class should switch SMO servers before
|
||||
/// execution or not.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class ServerSwitchingAttribute : Attribute
|
||||
{
|
||||
private bool needToSwitch = false;
|
||||
|
||||
private ServerSwitchingAttribute() {}
|
||||
|
||||
public ServerSwitchingAttribute(bool needToSwitchServer)
|
||||
{
|
||||
this.needToSwitch = needToSwitchServer;
|
||||
}
|
||||
|
||||
public bool NeedToSwtichServerObject
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.needToSwitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// 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 Microsoft.SqlTools.ServiceLayer.Agent;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
|
||||
{
|
||||
[Flags]
|
||||
public enum NotifyMethods
|
||||
{
|
||||
None = 0,
|
||||
NotifyEmail = 1,
|
||||
Pager = 2,
|
||||
NetSend = 4,
|
||||
NotifyAll = 7
|
||||
}
|
||||
|
||||
public enum AlertType
|
||||
{
|
||||
SqlServerEvent = 1,
|
||||
SqlServerPerformanceCondition = 2,
|
||||
NonSqlServerEvent = 3,
|
||||
WmiEvent = 4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// a class for storing various properties of agent alerts
|
||||
/// </summary>
|
||||
public class AgentAlertInfo
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int DelayBetweenResponses { get; set; }
|
||||
public string EventDescriptionKeyword { get; set; }
|
||||
public string EventSource { get; set; }
|
||||
public int HasNotification { get; set; }
|
||||
public NotifyMethods IncludeEventDescription { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
public Guid JobId { get; set; }
|
||||
public string JobName { get; set; }
|
||||
public DateTime LastOccurrenceDate { get; set; }
|
||||
public DateTime LastResponseDate { get; set; }
|
||||
public int MessageId { get; set; }
|
||||
public string NotificationMessage { get; set; }
|
||||
public int OccurrenceCount { get; }
|
||||
public string PerformanceCondition { get; set; }
|
||||
public int Severity { get; set; }
|
||||
public string DatabaseName { get; set; }
|
||||
public DateTime CountResetDate { get; }
|
||||
public string CategoryName { get; set; }
|
||||
public AlertType AlertType { get; set; }
|
||||
public string WmiEventNamespace { get; set; }
|
||||
public string WmiEventQuery { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// SQL Agent Job activity parameters
|
||||
/// </summary>
|
||||
public class AgentAlertsParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent Job activity result
|
||||
/// </summary>
|
||||
public class AgentAlertsResult
|
||||
{
|
||||
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public AgentAlertInfo[] Alerts { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent Alerts request type
|
||||
/// </summary>
|
||||
public class AgentAlertsRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<AgentAlertsParams, AgentAlertsResult> Type =
|
||||
RequestType<AgentAlertsParams, AgentAlertsResult>.Create("agent/alerts");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent create Alert params
|
||||
/// </summary>
|
||||
public class CreateAgentAlertParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public AgentAlertInfo Alert { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent create Alert result
|
||||
/// </summary>
|
||||
public class CreateAgentAlertResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent create Alert request type
|
||||
/// </summary>
|
||||
public class CreateAgentAlertRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<CreateAgentAlertParams, CreateAgentAlertResult> Type =
|
||||
RequestType<CreateAgentAlertParams, CreateAgentAlertResult>.Create("agent/createalert");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent delete Alert params
|
||||
/// </summary>
|
||||
public class DeleteAgentAlertParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public AgentAlertInfo Alert { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent delete Alert result
|
||||
/// </summary>
|
||||
public class DeleteAgentAlertResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent delete Alert request type
|
||||
/// </summary>
|
||||
public class DeleteAgentAlertRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<DeleteAgentAlertParams, DeleteAgentAlertResult> Type =
|
||||
RequestType<DeleteAgentAlertParams, DeleteAgentAlertResult>.Create("agent/deletealert");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent update Alert params
|
||||
/// </summary>
|
||||
public class UpdateAgentAlertParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public AgentAlertInfo Alert { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent update Alert result
|
||||
/// </summary>
|
||||
public class UpdateAgentAlertResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent update Alert request type
|
||||
/// </summary>
|
||||
public class UpdateAgentAlertRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<UpdateAgentAlertParams, UpdateAgentAlertResult> Type =
|
||||
RequestType<UpdateAgentAlertParams, UpdateAgentAlertResult>.Create("agent/updatealert");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// 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 Microsoft.SqlTools.ServiceLayer.Agent;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
|
||||
{
|
||||
[Flags]
|
||||
public enum WeekDays
|
||||
{
|
||||
Sunday = 1,
|
||||
Monday = 2,
|
||||
Tuesday = 4,
|
||||
Wednesday = 8,
|
||||
Thursday = 16,
|
||||
Friday = 32,
|
||||
WeekDays = 62,
|
||||
Saturday = 64,
|
||||
WeekEnds = 65,
|
||||
EveryDay = 127
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// a class for storing various properties of agent operators
|
||||
/// </summary>
|
||||
public class AgentOperatorInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Id { get; set; }
|
||||
public string EmailAddress { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public DateTime LastEmailDate { get; set; }
|
||||
public DateTime LastNetSendDate { get; set; }
|
||||
public DateTime LastPagerDate { get; set; }
|
||||
public string PagerAddress { get; set; }
|
||||
public string CategoryName { get; set; }
|
||||
public WeekDays PagerDays { get; set; }
|
||||
public TimeSpan SaturdayPagerEndTime { get; set; }
|
||||
public TimeSpan SaturdayPagerStartTime { get; set; }
|
||||
public TimeSpan SundayPagerEndTime { get; set; }
|
||||
public TimeSpan SundayPagerStartTime { get; set; }
|
||||
public string NetSendAddress { get; set; }
|
||||
public TimeSpan WeekdayPagerStartTime { get; set; }
|
||||
public TimeSpan WeekdayPagerEndTime { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// SQL Agent Operators request parameters
|
||||
/// </summary>
|
||||
public class AgentOperatorsParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent Operators request result
|
||||
/// </summary>
|
||||
public class AgentOperatorsResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public AgentOperatorInfo[] Operators { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent Operators request type
|
||||
/// </summary>
|
||||
public class AgentOperatorsRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<AgentOperatorsParams, AgentOperatorsResult> Type =
|
||||
RequestType<AgentOperatorsParams, AgentOperatorsResult>.Create("agent/operators");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent create Operator params
|
||||
/// </summary>
|
||||
public class CreateAgentOperatorParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public AgentOperatorInfo Operator { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent create Operator result
|
||||
/// </summary>
|
||||
public class CreateAgentOperatorResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent create Operator request type
|
||||
/// </summary>
|
||||
public class CreateAgentOperatorRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<CreateAgentOperatorParams, CreateAgentOperatorResult> Type =
|
||||
RequestType<CreateAgentOperatorParams, CreateAgentOperatorResult>.Create("agent/createoperator");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent delete Operator params
|
||||
/// </summary>
|
||||
public class DeleteAgentOperatorParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public AgentOperatorInfo Operator { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent delete Operator result
|
||||
/// </summary>
|
||||
public class DeleteAgentOperatorResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent delete Operator request type
|
||||
/// </summary>
|
||||
public class DeleteAgentOperatorRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<DeleteAgentOperatorParams, DeleteAgentOperatorResult> Type =
|
||||
RequestType<DeleteAgentOperatorParams, DeleteAgentOperatorResult>.Create("agent/deleteoperator");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent update Operator params
|
||||
/// </summary>
|
||||
public class UpdateAgentOperatorParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public AgentOperatorInfo Operator { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent update Operator result
|
||||
/// </summary>
|
||||
public class UpdateAgentOperatorResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent update Operator request type
|
||||
/// </summary>
|
||||
public class UpdateAgentOperatorRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<UpdateAgentOperatorParams, UpdateAgentOperatorResult> Type =
|
||||
RequestType<UpdateAgentOperatorParams, UpdateAgentOperatorResult>.Create("agent/updateoperator");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// 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 Microsoft.SqlTools.ServiceLayer.Agent;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// a class for storing various properties of agent proxy accounts
|
||||
/// </summary>
|
||||
public class AgentProxyInfo
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string AccountName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string CredentialName { get; set; }
|
||||
public string CredentialIdentity { get; set; }
|
||||
public int CredentialId { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// SQL Agent proxy accounts parameters
|
||||
/// </summary>
|
||||
public class AgentProxiesParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent proxy accounts result
|
||||
/// </summary>
|
||||
public class AgentProxiesResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public AgentProxyInfo[] Proxies { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent Proxy Accounts request type
|
||||
/// </summary>
|
||||
public class AgentProxiesRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<AgentProxiesParams, AgentProxiesResult> Type =
|
||||
RequestType<AgentProxiesParams, AgentProxiesResult>.Create("agent/proxies");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent create Proxy Account params
|
||||
/// </summary>
|
||||
public class CreateAgentProxyParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public AgentProxyInfo Proxy { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent create Proxy result
|
||||
/// </summary>
|
||||
public class CreateAgentProxyResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent create Proxy request type
|
||||
/// </summary>
|
||||
public class CreateAgentProxyRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<CreateAgentProxyParams, CreateAgentProxyResult> Type =
|
||||
RequestType<CreateAgentProxyParams, CreateAgentProxyResult>.Create("agent/createproxy");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent delete Proxy params
|
||||
/// </summary>
|
||||
public class DeleteAgentProxyParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public AgentProxyInfo Proxy { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent delete Proxy result
|
||||
/// </summary>
|
||||
public class DeleteAgentProxyResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent delete Proxy request type
|
||||
/// </summary>
|
||||
public class DeleteAgentProxyRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<DeleteAgentProxyParams, DeleteAgentProxyResult> Type =
|
||||
RequestType<DeleteAgentProxyParams, DeleteAgentProxyResult>.Create("agent/deleteproxy");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent update Proxy params
|
||||
/// </summary>
|
||||
public class UpdateAgentProxyParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public string OriginalProxyName { get; set; }
|
||||
|
||||
public AgentProxyInfo Proxy { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent update Proxy result
|
||||
/// </summary>
|
||||
public class UpdateAgentProxyResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL Agent update Proxy request type
|
||||
/// </summary>
|
||||
public class UpdateAgentProxyRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<UpdateAgentProxyParams, UpdateAgentProxyResult> Type =
|
||||
RequestType<UpdateAgentProxyParams, UpdateAgentProxyResult>.Create("agent/updateproxy");
|
||||
}
|
||||
}
|
||||
166
src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/AgentAlert.cs
Normal file
166
src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/AgentAlert.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// 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;
|
||||
using System.Data;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Diagnostics;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.Smo.Agent;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
/// <summary>
|
||||
/// AgentAlert class
|
||||
/// </summary>
|
||||
internal class AgentAlert : ManagementActionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Agent alert info instance
|
||||
/// </summary>
|
||||
private AgentAlertInfo alertInfo = null;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor that will be used to create dialog
|
||||
/// </summary>
|
||||
/// <param name="dataContainer"></param>
|
||||
public AgentAlert(CDataContainer dataContainer, AgentAlertInfo alertInfo)
|
||||
{
|
||||
this.alertInfo = alertInfo;
|
||||
this.DataContainer = dataContainer;
|
||||
}
|
||||
|
||||
private static string GetAlertName(CDataContainer container)
|
||||
{
|
||||
string alertName = null;
|
||||
STParameters parameters = new STParameters();
|
||||
parameters.SetDocument(container.Document);
|
||||
if (parameters.GetParam("alert", ref alertName) == false || string.IsNullOrWhiteSpace(alertName))
|
||||
{
|
||||
throw new Exception("SRError.AlertNameCannotBeBlank");
|
||||
}
|
||||
return alertName.Trim();
|
||||
}
|
||||
|
||||
public bool Drop()
|
||||
{
|
||||
// fail if the user is not in the sysadmin role
|
||||
if (!this.DataContainer.Server.ConnectionContext.IsInFixedServerRole(FixedServerRoles.SysAdmin))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string alertName = GetAlertName(this.DataContainer);
|
||||
if (this.DataContainer.Server.JobServer.Alerts.Contains(alertName))
|
||||
{
|
||||
this.DataContainer.Server.JobServer.Alerts.Refresh();
|
||||
if (this.DataContainer.Server.JobServer.Alerts.Contains(alertName))
|
||||
{
|
||||
Alert alert = this.DataContainer.Server.JobServer.Alerts[alertName];
|
||||
if (alert != null)
|
||||
{
|
||||
alert.DropIfExists();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CreateOrUpdate()
|
||||
{
|
||||
Alert alert = null;
|
||||
string alertName = GetAlertName(this.DataContainer);
|
||||
bool createNewAlert = true;
|
||||
|
||||
try
|
||||
{
|
||||
// check if alert already exists
|
||||
if (this.DataContainer.Server.JobServer.Alerts.Contains(alertName))
|
||||
{
|
||||
this.DataContainer.Server.JobServer.Alerts.Refresh(); // Try to recover
|
||||
if (this.DataContainer.Server.JobServer.Alerts.Contains(alertName)) // If still no luck
|
||||
{
|
||||
// use the existing alert
|
||||
alert = this.DataContainer.Server.JobServer.Alerts[alertName];
|
||||
createNewAlert = false;
|
||||
}
|
||||
}
|
||||
|
||||
// create a new alert
|
||||
if (createNewAlert)
|
||||
{
|
||||
alert = new Alert(this.DataContainer.Server.JobServer, alertName);
|
||||
}
|
||||
|
||||
// apply changes from input parameter to SMO alert object
|
||||
UpdateAlertProperties(alert);
|
||||
|
||||
if (createNewAlert)
|
||||
{
|
||||
alert.Create();
|
||||
}
|
||||
else
|
||||
{
|
||||
// don't bother trying to update the alert unless they are sysadmin.
|
||||
if (!this.DataContainer.Server.ConnectionContext.IsInFixedServerRole(FixedServerRoles.SysAdmin))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
alert.Alter();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ApplicationException applicationException;
|
||||
if (createNewAlert)
|
||||
{
|
||||
applicationException = new ApplicationException("AgentAlertSR.CannotCreateNewAlert", e);
|
||||
}
|
||||
else
|
||||
{
|
||||
applicationException = new ApplicationException("AgentAlertSR.CannotAlterAlert", e);
|
||||
}
|
||||
throw applicationException;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAlertProperties(Alert alert)
|
||||
{
|
||||
if (alert == null)
|
||||
{
|
||||
throw new ArgumentNullException("alert");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(this.DataContainer.ConnectionInfo.DatabaseName))
|
||||
{
|
||||
alert.DatabaseName = this.DataContainer.ConnectionInfo.DatabaseName;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(this.alertInfo.CategoryName))
|
||||
{
|
||||
alert.CategoryName = this.alertInfo.CategoryName;
|
||||
}
|
||||
|
||||
alert.IsEnabled = this.alertInfo.IsEnabled;
|
||||
|
||||
if (alertInfo.AlertType == Contracts.AlertType.SqlServerEvent)
|
||||
{
|
||||
alert.Severity = this.alertInfo.Severity;
|
||||
alert.MessageID = this.alertInfo.MessageId;
|
||||
if (!string.IsNullOrWhiteSpace(this.alertInfo.EventDescriptionKeyword))
|
||||
{
|
||||
alert.EventDescriptionKeyword = this.alertInfo.EventDescriptionKeyword;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
947
src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/AgentOperator.cs
Normal file
947
src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/AgentOperator.cs
Normal file
@@ -0,0 +1,947 @@
|
||||
//
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Diagnostics;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.Smo.Agent;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
/// <summary>
|
||||
/// Agent Operators management class
|
||||
/// </summary>
|
||||
internal class AgentOperator : ManagementActionBase
|
||||
{
|
||||
private AgentOperatorInfo operatorInfo;
|
||||
|
||||
AgentOperatorsData operatorsData = null;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public AgentOperator(CDataContainer dataContainer, AgentOperatorInfo operatorInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (dataContainer == null)
|
||||
{
|
||||
throw new ArgumentNullException("dataContainer");
|
||||
}
|
||||
|
||||
if (operatorInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException("operatorInfo");
|
||||
}
|
||||
|
||||
this.operatorInfo = operatorInfo;
|
||||
this.DataContainer = dataContainer;
|
||||
|
||||
STParameters parameters = new STParameters();
|
||||
parameters.SetDocument(dataContainer.Document);
|
||||
|
||||
string agentOperatorName = null;
|
||||
if (parameters.GetParam("operator", ref agentOperatorName))
|
||||
{
|
||||
this.operatorsData = new AgentOperatorsData(dataContainer, agentOperatorName);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentNullException("agentOperatorName");
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new ApplicationException("AgentOperatorsSR.FailedToCreateInitializeAgentOperatorDialog", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if(disposing)
|
||||
{
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public bool CreateOrUpdate()
|
||||
{
|
||||
this.operatorsData.ApplyChanges(this.operatorInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#region internal structures
|
||||
/// <summary>
|
||||
/// Provides data to be consumed in the job notification grid
|
||||
/// </summary>
|
||||
internal struct AgentJobNotificationHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="name">job name</param>
|
||||
/// <param name="notifyEmail"></param>
|
||||
/// <param name="notifyPager"></param>
|
||||
public AgentJobNotificationHelper(string name, CompletionAction notifyEmail, CompletionAction notifyPager)
|
||||
{
|
||||
this.Name = name;
|
||||
this.NotifyEmail = notifyEmail;
|
||||
this.NotifyPager = notifyPager;
|
||||
}
|
||||
/// <summary>
|
||||
/// Name of the job
|
||||
/// </summary>
|
||||
public string Name;
|
||||
/// <summary>
|
||||
/// job email notification action
|
||||
/// </summary>
|
||||
public CompletionAction NotifyEmail;
|
||||
/// <summary>
|
||||
/// job pager notification action
|
||||
/// </summary>
|
||||
public CompletionAction NotifyPager;
|
||||
}
|
||||
/// <summary>
|
||||
/// Provides data to be consumed in the alert notification grid
|
||||
/// </summary>
|
||||
internal struct AgentAlertNotificationHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the alert</param>
|
||||
/// <param name="notifyEmail"></param>
|
||||
/// <param name="notifyPager"></param>
|
||||
/// <param name="alert">Alert object</param>
|
||||
public AgentAlertNotificationHelper(string name, bool notifyEmail, bool notifyPager, Alert alert)
|
||||
{
|
||||
this.Name = name;
|
||||
this.NotifyEmail = notifyEmail;
|
||||
this.NotifyPager = notifyPager;
|
||||
this.Alert = alert;
|
||||
}
|
||||
/// <summary>
|
||||
/// Alert name
|
||||
/// </summary>
|
||||
public string Name;
|
||||
/// <summary>
|
||||
/// Indicates whether the alert will notify the operator through email
|
||||
/// </summary>
|
||||
public bool NotifyEmail;
|
||||
/// <summary>
|
||||
/// Indicates whether the alert will notify the operator through pager
|
||||
/// </summary>
|
||||
public bool NotifyPager;
|
||||
/// <summary>
|
||||
/// Alert object. optimisation to stop us having to lookup the alert object when needed
|
||||
/// </summary>
|
||||
public Alert Alert;
|
||||
}
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Proxy class for the AgentOperators dialog and property pages.
|
||||
/// Performs lazy instantiation of groups of data based around the operators dialog property pages
|
||||
/// </summary>
|
||||
internal class AgentOperatorsData
|
||||
{
|
||||
#region members
|
||||
/// <summary>
|
||||
/// Data container
|
||||
/// </summary>
|
||||
CDataContainer dataContainer;
|
||||
/// <summary>
|
||||
/// Original operator name. Empty if we are creating a new operator
|
||||
/// </summary>
|
||||
string originalOperatorName = String.Empty;
|
||||
/// <summary>
|
||||
/// Indicates whether we are creating an operator or not
|
||||
/// </summary>
|
||||
bool createMode;
|
||||
|
||||
/// <summary>
|
||||
/// Has then data for the general page been initialised
|
||||
/// </summary>
|
||||
bool generalInitialized = false;
|
||||
/// <summary>
|
||||
/// has the data for the history page been initialised
|
||||
/// </summary>
|
||||
bool historyInitialized = false;
|
||||
|
||||
/// <summary>
|
||||
/// True if this operator cannot be modified
|
||||
/// </summary>
|
||||
bool readOnly = false;
|
||||
|
||||
#region general items
|
||||
string name;
|
||||
bool enabled;
|
||||
string emailAddress;
|
||||
string pagerAddress;
|
||||
SqlServer.Management.Smo.Agent.WeekDays pagerDays;
|
||||
DateTime weekdayStartTime;
|
||||
DateTime weekdayEndTime;
|
||||
DateTime saturdayStartTime;
|
||||
DateTime saturdayEndTime;
|
||||
DateTime sundayStartTime;
|
||||
DateTime sundayEndTime;
|
||||
#endregion
|
||||
|
||||
#region notification items
|
||||
/// <summary>
|
||||
/// will be null if the alert notifications have not been initialised
|
||||
/// </summary>
|
||||
IList<AgentAlertNotificationHelper> alertNotifications;
|
||||
/// <summary>
|
||||
/// will be null if the job notifications have not been initialised
|
||||
/// </summary>
|
||||
IList<AgentJobNotificationHelper> jobNotifications;
|
||||
#endregion
|
||||
|
||||
#region history items
|
||||
DateTime lastEmailDate;
|
||||
DateTime lastPagerDate;
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region properties
|
||||
/// <summary>
|
||||
/// indicates if the data is in create mode
|
||||
/// </summary>
|
||||
public bool Creating
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.createMode;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// name of the object
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return name;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
name = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Indicates if the dataobject is readonly
|
||||
/// </summary>
|
||||
public bool ReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.readOnly;
|
||||
}
|
||||
}
|
||||
#region general items
|
||||
/// <summary>
|
||||
/// indicates whether or not the operator is enabled
|
||||
/// </summary>
|
||||
public bool Enabled
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return enabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
enabled = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// email address of this operator
|
||||
/// </summary>
|
||||
public string EmailAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return this.emailAddress;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
this.emailAddress = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// pager address of this operator
|
||||
/// </summary>
|
||||
public string PagerAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return this.pagerAddress;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
this.pagerAddress = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// the days of the week the operator is active
|
||||
/// </summary>
|
||||
public SqlServer.Management.Smo.Agent.WeekDays PagerDays
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return this.pagerDays;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
this.pagerDays = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Weekday start time for this operator to be active
|
||||
/// </summary>
|
||||
public DateTime WeekdayStartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return this.weekdayStartTime;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
this.weekdayStartTime = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Weekday end time for this operator to be active
|
||||
/// </summary>
|
||||
public DateTime WeekdayEndTime
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return this.weekdayEndTime;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
this.weekdayEndTime = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Saturday start time for this operator to be active
|
||||
/// </summary>
|
||||
public DateTime SaturdayStartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return this.saturdayStartTime;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
this.saturdayStartTime = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Saturday end time for this operator to be active
|
||||
/// </summary>
|
||||
public DateTime SaturdayEndTime
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return this.saturdayEndTime;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
this.saturdayEndTime = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Sunday start time for this operator to be active
|
||||
/// </summary>
|
||||
public DateTime SundayStartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return this.sundayStartTime;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
this.sundayStartTime = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Saturday end time for this operator to be active
|
||||
/// </summary>
|
||||
public DateTime SundayEndTime
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadGeneralData();
|
||||
return this.sundayEndTime;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadGeneralData();
|
||||
this.sundayEndTime = value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region notification items
|
||||
/// <summary>
|
||||
/// Alerts that notify this operator
|
||||
/// </summary>
|
||||
public IList<AgentAlertNotificationHelper> AlertNotifications
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadAlertNotificationData();
|
||||
return this.alertNotifications;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.alertNotifications = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Jobs that notify this operator. This has to be set through the jobs dialog and is read only
|
||||
/// </summary>
|
||||
public IList<AgentJobNotificationHelper> JobNotifications
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadJobNotificationData();
|
||||
return this.jobNotifications;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region history items
|
||||
/// <summary>
|
||||
/// Date this operator was last emailed
|
||||
/// </summary>
|
||||
public DateTime LastEmailDate
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadHistoryData();
|
||||
return this.lastEmailDate;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Date this operator was last paged
|
||||
/// </summary>
|
||||
public DateTime LastPagerDate
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadHistoryData();
|
||||
return this.lastPagerDate;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public AgentOperatorsData(CDataContainer dataContainer, string operatorName)
|
||||
{
|
||||
if (dataContainer == null)
|
||||
{
|
||||
throw new ArgumentNullException("dataContainer");
|
||||
}
|
||||
if (operatorName == null)
|
||||
{
|
||||
throw new ArgumentNullException("operatorName");
|
||||
}
|
||||
|
||||
this.dataContainer = dataContainer;
|
||||
|
||||
this.readOnly = !this.dataContainer.Server.ConnectionContext.IsInFixedServerRole(FixedServerRoles.SysAdmin);
|
||||
this.originalOperatorName = operatorName;
|
||||
this.name = operatorName;
|
||||
|
||||
this.createMode = operatorName.Length == 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region data loading
|
||||
/// <summary>
|
||||
/// load data for the general tab. This can be called multiple times but will only load the data once intially
|
||||
/// or after a reset
|
||||
/// </summary>
|
||||
private void LoadGeneralData()
|
||||
{
|
||||
if(this.generalInitialized)
|
||||
return;
|
||||
|
||||
// load defaults if we're creating
|
||||
if(createMode)
|
||||
{
|
||||
LoadGeneralDefaults();
|
||||
return;
|
||||
}
|
||||
|
||||
// lookup the operator this will throw if it has been deleted.
|
||||
Microsoft.SqlServer.Management.Smo.Agent.Operator currentOperator = GetCurrentOperator();
|
||||
|
||||
// setup the members
|
||||
this.name = currentOperator.Name;
|
||||
this.enabled = currentOperator.Enabled;
|
||||
this.emailAddress = currentOperator.EmailAddress;
|
||||
this.pagerAddress = currentOperator.PagerAddress;
|
||||
|
||||
this.pagerDays = currentOperator.PagerDays;
|
||||
|
||||
this.weekdayStartTime = ConvertAgentTime(currentOperator.WeekdayPagerStartTime);
|
||||
this.weekdayEndTime = ConvertAgentTime(currentOperator.WeekdayPagerEndTime);
|
||||
|
||||
this.saturdayStartTime = ConvertAgentTime(currentOperator.SaturdayPagerStartTime);
|
||||
this.saturdayEndTime = ConvertAgentTime(currentOperator.SaturdayPagerEndTime);
|
||||
|
||||
this.sundayStartTime = ConvertAgentTime(currentOperator.SundayPagerStartTime);
|
||||
this.sundayEndTime = ConvertAgentTime(currentOperator.SundayPagerEndTime);
|
||||
|
||||
this.generalInitialized = true;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Load the data for the jobs that notify this operator. Can be called multiple times and will
|
||||
/// only load the data initially, or after a reset.
|
||||
/// </summary>
|
||||
private void LoadJobNotificationData()
|
||||
{
|
||||
if(this.jobNotifications != null)
|
||||
return;
|
||||
|
||||
// just set defaults if we're creating as no jobs will point to this operator yet.
|
||||
if(createMode)
|
||||
{
|
||||
LoadJobNotificationDefaults();
|
||||
return;
|
||||
}
|
||||
|
||||
JobServer jobServer = GetJobServer();
|
||||
|
||||
this.jobNotifications = new List<AgentJobNotificationHelper>();
|
||||
|
||||
// we have to loop through each job and see if it notifies us.
|
||||
foreach(Job job in jobServer.Jobs)
|
||||
{
|
||||
bool emailOperator = (job.OperatorToEmail == this.originalOperatorName);
|
||||
bool pageOperator = (job.OperatorToPage == this.originalOperatorName);
|
||||
if(emailOperator || pageOperator )
|
||||
{
|
||||
// only return jobs that notify this operator
|
||||
AgentJobNotificationHelper notification = new AgentJobNotificationHelper(job.Name
|
||||
, job.EmailLevel
|
||||
, job.PageLevel
|
||||
);
|
||||
this.jobNotifications.Add(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Load alerts that notify this operator
|
||||
/// </summary>
|
||||
private void LoadAlertNotificationData()
|
||||
{
|
||||
if (this.alertNotifications != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// defaults in create ode
|
||||
if (createMode)
|
||||
{
|
||||
LoadAlertNotificationDefaults();
|
||||
return;
|
||||
}
|
||||
|
||||
this.alertNotifications = new List<AgentAlertNotificationHelper>();
|
||||
|
||||
Microsoft.SqlServer.Management.Smo.Agent.Operator agentOperator = GetCurrentOperator();
|
||||
JobServer jobServer = GetJobServer();
|
||||
|
||||
// see all alerts that notifuy this operator
|
||||
DataTable notifications = agentOperator.EnumNotifications();
|
||||
DataRow alertRow;
|
||||
bool notifyEmail;
|
||||
bool notifyPager;
|
||||
AgentAlertNotificationHelper alertNotification;
|
||||
|
||||
// Add every alert to the structure
|
||||
foreach (Alert alert in jobServer.Alerts)
|
||||
{
|
||||
alertRow = null;
|
||||
|
||||
// see if the alert notifies us already
|
||||
foreach (DataRow row in notifications.Rows)
|
||||
{
|
||||
if((string)row["AlertName"] == alert.Name)
|
||||
{
|
||||
alertRow = row;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// set if the current alert notifies this operator
|
||||
// if so so how
|
||||
if (alertRow != null)
|
||||
{
|
||||
notifyEmail = (bool)alertRow["UseEmail"];
|
||||
notifyPager = (bool)alertRow["UsePager"];
|
||||
}
|
||||
else
|
||||
{ notifyEmail = false;
|
||||
notifyPager = false;
|
||||
}
|
||||
|
||||
alertNotification = new AgentAlertNotificationHelper(alert.Name
|
||||
,notifyEmail
|
||||
,notifyPager
|
||||
,alert);
|
||||
|
||||
this.alertNotifications.Add(alertNotification);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// load the notifiaction history for the operator
|
||||
/// </summary>
|
||||
private void LoadHistoryData()
|
||||
{
|
||||
if (this.historyInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.createMode)
|
||||
{
|
||||
LoadHistoryDefaults();
|
||||
return;
|
||||
}
|
||||
|
||||
Microsoft.SqlServer.Management.Smo.Agent.Operator currentOperator = GetCurrentOperator();
|
||||
|
||||
this.lastEmailDate = currentOperator.LastEmailDate;
|
||||
this.lastPagerDate = currentOperator.LastPagerDate;
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region saving
|
||||
/// <summary>
|
||||
/// apply any changes to the operator. If the operator does not exist create it.
|
||||
/// </summary>
|
||||
public void ApplyChanges(AgentOperatorInfo operatorInfo)
|
||||
{
|
||||
// do nothing if we are read only
|
||||
if (this.readOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
JobServer jobServer = GetJobServer();
|
||||
|
||||
// get the operator. This will create a new one if it does not already exist
|
||||
Microsoft.SqlServer.Management.Smo.Agent.Operator currentOperator = GetCurrentOperator();
|
||||
|
||||
// general tab
|
||||
currentOperator.Enabled = operatorInfo.Enabled;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(operatorInfo.EmailAddress))
|
||||
{
|
||||
currentOperator.EmailAddress = operatorInfo.EmailAddress;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(operatorInfo.PagerAddress))
|
||||
{
|
||||
currentOperator.PagerAddress = operatorInfo.PagerAddress;
|
||||
}
|
||||
|
||||
currentOperator.PagerDays = this.pagerDays;
|
||||
|
||||
if ((operatorInfo.PagerDays & Contracts.WeekDays.WeekDays) > 0)
|
||||
{
|
||||
currentOperator.WeekdayPagerStartTime = operatorInfo.WeekdayPagerStartTime;
|
||||
currentOperator.WeekdayPagerEndTime = operatorInfo.WeekdayPagerEndTime;
|
||||
}
|
||||
|
||||
if ((operatorInfo.PagerDays & Contracts.WeekDays.Saturday) > 0)
|
||||
{
|
||||
currentOperator.SaturdayPagerStartTime = operatorInfo.SaturdayPagerStartTime;
|
||||
currentOperator.SaturdayPagerEndTime = operatorInfo.SaturdayPagerEndTime;
|
||||
}
|
||||
|
||||
if ((operatorInfo.PagerDays & Contracts.WeekDays.Sunday) > 0)
|
||||
{
|
||||
currentOperator.SundayPagerStartTime = operatorInfo.SundayPagerStartTime;
|
||||
currentOperator.SundayPagerEndTime = operatorInfo.SundayPagerEndTime;
|
||||
}
|
||||
|
||||
if (this.createMode)
|
||||
{
|
||||
// create the object
|
||||
currentOperator.Create();
|
||||
this.originalOperatorName = this.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// alter the object
|
||||
currentOperator.Alter();
|
||||
}
|
||||
|
||||
// only set this up if the notifications has been set
|
||||
if (this.alertNotifications != null)
|
||||
{
|
||||
SqlServer.Management.Smo.Agent.NotifyMethods notifyMethods;
|
||||
for (int i = 0; i < alertNotifications.Count; ++i)
|
||||
{
|
||||
notifyMethods = 0;
|
||||
|
||||
if (alertNotifications[i].NotifyEmail)
|
||||
{
|
||||
notifyMethods |= SqlServer.Management.Smo.Agent.NotifyMethods.NotifyEmail;
|
||||
}
|
||||
if (alertNotifications[i].NotifyPager)
|
||||
{
|
||||
notifyMethods |= SqlServer.Management.Smo.Agent.NotifyMethods.Pager;
|
||||
}
|
||||
|
||||
bool alertAlreadyNotifiesOperator = false;
|
||||
|
||||
// if we're not creating see if the current alert already notifies this operator
|
||||
if (!createMode)
|
||||
{
|
||||
DataTable notifications = alertNotifications[i].Alert.EnumNotifications(this.originalOperatorName);
|
||||
if (notifications.Rows.Count > 0)
|
||||
{
|
||||
alertAlreadyNotifiesOperator = true;
|
||||
}
|
||||
}
|
||||
|
||||
// either update or clear existing notifications
|
||||
if (alertAlreadyNotifiesOperator)
|
||||
{
|
||||
if(notifyMethods != SqlServer.Management.Smo.Agent.NotifyMethods.None)
|
||||
{
|
||||
alertNotifications[i].Alert.UpdateNotification(this.originalOperatorName, notifyMethods);
|
||||
}
|
||||
else
|
||||
{
|
||||
alertNotifications[i].Alert.RemoveNotification(this.originalOperatorName);
|
||||
}
|
||||
}
|
||||
else if(notifyMethods != SqlServer.Management.Smo.Agent.NotifyMethods.None)
|
||||
{
|
||||
// add a new notification
|
||||
alertNotifications[i].Alert.AddNotification(this.originalOperatorName, notifyMethods);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// see if we need to rename. This has to be done last otherwise any scripts generated will be incorrect.
|
||||
if (!this.createMode && currentOperator.Name != this.originalOperatorName)
|
||||
{
|
||||
currentOperator.Rename(this.name);
|
||||
if(this.dataContainer.Server.ConnectionContext.SqlExecutionModes != SqlExecutionModes.CaptureSql)
|
||||
{
|
||||
this.originalOperatorName = this.name;
|
||||
}
|
||||
}
|
||||
// update state if we aren't scripting
|
||||
if (this.createMode && this.dataContainer.Server.ConnectionContext.SqlExecutionModes != SqlExecutionModes.CaptureSql)
|
||||
{
|
||||
this.createMode = false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region reset
|
||||
/// <summary>
|
||||
/// Reset the object to it's original state / reload any data from the erver
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
JobServer jobServer = GetJobServer();
|
||||
this.generalInitialized = false;
|
||||
if (this.jobNotifications != null)
|
||||
{
|
||||
// ensure the individual jobs are reset also
|
||||
jobServer.Jobs.Refresh(true);
|
||||
this.jobNotifications = null;
|
||||
}
|
||||
if (this.alertNotifications != null)
|
||||
{
|
||||
// ensure the individual jobs are reset also
|
||||
jobServer.Alerts.Refresh(true);
|
||||
this.alertNotifications = null;
|
||||
}
|
||||
this.historyInitialized = false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region defaults
|
||||
/// <summary>
|
||||
/// set general tab defaults
|
||||
/// </summary>
|
||||
private void LoadGeneralDefaults()
|
||||
{
|
||||
name = String.Empty;
|
||||
this.emailAddress = String.Empty;
|
||||
this.pagerAddress = String.Empty;
|
||||
enabled = true;
|
||||
pagerDays = 0;
|
||||
|
||||
weekdayStartTime = saturdayStartTime = sundayStartTime = new DateTime(2000, 1, 1, 8, 0, 0);
|
||||
weekdayEndTime = saturdayEndTime = sundayEndTime = new DateTime(2000, 1, 1, 18, 0, 0);
|
||||
|
||||
this.generalInitialized = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Set job notification defaults. This is just an empty list
|
||||
/// </summary>
|
||||
private void LoadJobNotificationDefaults()
|
||||
{
|
||||
this.jobNotifications = new List<AgentJobNotificationHelper>();
|
||||
}
|
||||
/// <summary>
|
||||
/// set the alert notification defaults. This list will contain all of the alerts
|
||||
/// </summary>
|
||||
private void LoadAlertNotificationDefaults()
|
||||
{
|
||||
this.alertNotifications = new List<AgentAlertNotificationHelper>();
|
||||
|
||||
JobServer jobServer = GetJobServer();
|
||||
|
||||
AgentAlertNotificationHelper alertNotification;
|
||||
foreach(Alert alert in jobServer.Alerts)
|
||||
{
|
||||
alertNotification = new AgentAlertNotificationHelper(alert.Name, notifyEmail:false, notifyPager:false, alert: alert);
|
||||
this.alertNotifications.Add(alertNotification);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// load defaults for the history page
|
||||
/// </summary>
|
||||
private void LoadHistoryDefaults()
|
||||
{
|
||||
this.lastEmailDate = DateTime.MinValue;
|
||||
this.lastPagerDate = DateTime.MinValue;
|
||||
|
||||
this.historyInitialized = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region helpers
|
||||
/// <summary>
|
||||
/// Get the job server. Will throw if it is not available
|
||||
/// </summary>
|
||||
/// <returns>Job server object</returns>
|
||||
private JobServer GetJobServer()
|
||||
{
|
||||
JobServer jobServer = this.dataContainer.Server.JobServer;
|
||||
if(jobServer == null)
|
||||
{
|
||||
throw new ApplicationException("AgentOperatorsSR.JobServerIsNotAvailable");
|
||||
}
|
||||
return jobServer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current operator. If we are creating this will be a new operator. If we are modifying
|
||||
/// an existing operator it will be the existing operator, and will throw if the operator has been
|
||||
/// deleted.
|
||||
/// </summary>
|
||||
/// <returns>Operator object</returns>
|
||||
private Operator GetCurrentOperator()
|
||||
{
|
||||
JobServer jobServer = GetJobServer();
|
||||
|
||||
Operator currentOperator = jobServer.Operators[this.originalOperatorName];
|
||||
this.createMode = (currentOperator == null);
|
||||
if (this.createMode)
|
||||
{
|
||||
currentOperator = new Microsoft.SqlServer.Management.Smo.Agent.Operator(jobServer, this.name);
|
||||
}
|
||||
return currentOperator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
static public TimeSpan ConvertAgentTime(DateTime dateTime)
|
||||
{
|
||||
return new TimeSpan(dateTime.Hour, dateTime.Minute, dateTime.Second);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
static public DateTime ConvertAgentTime(TimeSpan dateTime)
|
||||
{
|
||||
return new DateTime(2000, 1, 1, dateTime.Hours, dateTime.Minutes, dateTime.Seconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
static public int ConvertAgentTimeToInt(DateTime dateTime)
|
||||
{
|
||||
return dateTime.Hour * 10000 + dateTime.Minute * 100 + dateTime.Second;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
static public DateTime ConvertAgentTime(int dateTime)
|
||||
{
|
||||
return new DateTime(2000, 1, 1, (int)(dateTime / 10000), (int)((dateTime - (dateTime / 10000) * 10000) / 100), (int)(dateTime - (dateTime / 100) * 100));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
//
|
||||
// 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.ComponentModel;
|
||||
using System.Collections;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Diagnostics;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.Smo.Agent;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
internal class AgentProxyAccount : ManagementActionBase
|
||||
{
|
||||
#region Constants
|
||||
internal const string ProxyAccountPropertyName = "proxyaccount";
|
||||
internal const string ProxyAccountSubsystem = "SubSystem";
|
||||
internal const string ProxyAccountMode = "Mode";
|
||||
internal const string ProxyAccountDuplicateMode = "Duplicate";
|
||||
internal const int SysnameLength = 256;
|
||||
internal const int DescriptionLength = 512;
|
||||
#endregion
|
||||
|
||||
internal enum ProxyPrincipalType
|
||||
{
|
||||
SqlLogin,
|
||||
MsdbRole,
|
||||
ServerRole
|
||||
}
|
||||
|
||||
// Collections of principals for logins/server roles/msdb roles
|
||||
private ArrayList[] principals;
|
||||
|
||||
// Name of the proxy account we work with
|
||||
private string proxyAccountName;
|
||||
|
||||
private AgentProxyInfo proxyInfo;
|
||||
|
||||
// Flag indicating that proxy account should be duplicated
|
||||
private bool duplicate;
|
||||
|
||||
public static string SysadminAccount
|
||||
{
|
||||
get { return "AgentProxyAccountSR.SysadminAccount"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main constructor. Creates all pages and adds them
|
||||
/// to the tree control.
|
||||
/// </summary>
|
||||
public AgentProxyAccount(CDataContainer dataContainer, AgentProxyInfo proxyInfo)
|
||||
{
|
||||
this.DataContainer = dataContainer;
|
||||
this.proxyInfo = proxyInfo;
|
||||
|
||||
// Find out if we are creating a new proxy account or
|
||||
// modifying an existing one.
|
||||
GetProxyAccountName(dataContainer, ref this.proxyAccountName, ref this.duplicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// It creates a new ProxyAccount or gets an existing
|
||||
/// one from JobServer and updates all properties.
|
||||
/// </summary>
|
||||
private bool CreateOrUpdateProxyAccount(
|
||||
AgentProxyInfo proxyInfo,
|
||||
bool isUpdate)
|
||||
{
|
||||
ProxyAccount proxyAccount = null;
|
||||
if (!isUpdate)
|
||||
{
|
||||
proxyAccount = new ProxyAccount(this.DataContainer.Server.JobServer,
|
||||
proxyInfo.AccountName,
|
||||
proxyInfo.CredentialName,
|
||||
proxyInfo.IsEnabled,
|
||||
proxyInfo.Description);
|
||||
|
||||
UpdateProxyAccount(proxyAccount);
|
||||
proxyAccount.Create();
|
||||
}
|
||||
else if (this.DataContainer.Server.JobServer.ProxyAccounts.Contains(this.proxyAccountName))
|
||||
{
|
||||
// Try refresh and check again
|
||||
this.DataContainer.Server.JobServer.ProxyAccounts.Refresh();
|
||||
if (this.DataContainer.Server.JobServer.ProxyAccounts.Contains(this.proxyAccountName))
|
||||
{
|
||||
// fail since account exists and asked to create a new one
|
||||
if (!isUpdate)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
proxyAccount = AgentProxyAccount.GetProxyAccount(this.proxyAccountName, this.DataContainer.Server.JobServer);
|
||||
// Set the other properties
|
||||
proxyAccount.CredentialName = proxyInfo.CredentialName;
|
||||
proxyAccount.Description = proxyInfo.Description;
|
||||
|
||||
UpdateProxyAccount(proxyAccount);
|
||||
proxyAccount.Alter();
|
||||
|
||||
// Rename the proxy if needed
|
||||
// This has to be done after Alter, in order to
|
||||
// work correcly when scripting this action.
|
||||
if (this.proxyAccountName != proxyInfo.AccountName)
|
||||
{
|
||||
proxyAccount.Rename(proxyInfo.AccountName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
#if false // @TODO - reenable subsystem code below
|
||||
|
||||
// Update the subsystems
|
||||
foreach (AgentSubSystem subsystem in this.addSubSystems)
|
||||
{
|
||||
proxyAccount.AddSubSystem(subsystem);
|
||||
}
|
||||
|
||||
foreach (AgentSubSystem subsystem in this.removeSubSystems)
|
||||
{
|
||||
proxyAccount.RemoveSubSystem(subsystem);
|
||||
|
||||
// Update jobsteps that use this proxy accunt
|
||||
// when some subsystems are removed from it
|
||||
string reassignToProxyName = this.reassignToProxyNames[(int)subsystem];
|
||||
|
||||
if (reassignToProxyName != null)
|
||||
{
|
||||
// if version is sql 11 and above call SMO API to reassign proxy account
|
||||
if (Utils.IsSql11OrLater(this.DataContainer.Server.ServerVersion))
|
||||
{
|
||||
proxyAccount.Reassign(reassignToProxyName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// legacy code
|
||||
// Get a list of all job step objects that use this proxy and this subsystem
|
||||
Request req = new Request();
|
||||
req.Urn = string.Format(System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Server/JobServer/Job/Step[@ProxyName=\'{0}\' and @SubSystem={1}]",
|
||||
Urn.EscapeString(proxyAccount.Name),
|
||||
(int)subsystem);
|
||||
req.Fields = new string[] { "Name" };
|
||||
req.ParentPropertiesRequests = new PropertiesRequest[1] { new PropertiesRequest() };
|
||||
req.ParentPropertiesRequests[0].Fields = new string[] { "Name" };
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
DataTable table = en.Process(this.DataContainer.ServerConnection, req);
|
||||
foreach (DataRow row in table.Rows)
|
||||
{
|
||||
// Get the actual job step object using urn
|
||||
string urnString = string.Format(System.Globalization.CultureInfo.InvariantCulture, "Server/JobServer/Job[@Name=\"{0}\"/Step[@Name=\"{1}\"", row["Job_Name"], row["Name"]);
|
||||
Urn urn = new Urn(urnString);
|
||||
JobStep jobStep = (JobStep)this.DataContainer.Server.GetSmoObject(urn);
|
||||
|
||||
jobStep.ProxyName = reassignToProxyName;
|
||||
jobStep.Alter();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool Create()
|
||||
{
|
||||
CreateOrUpdateProxyAccount(this.proxyInfo, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Update()
|
||||
{
|
||||
CreateOrUpdateProxyAccount(this.proxyInfo, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Drop()
|
||||
{
|
||||
if (this.DataContainer.Server.JobServer.ProxyAccounts.Contains(this.proxyAccountName))
|
||||
{
|
||||
// Try refresh and check again
|
||||
this.DataContainer.Server.JobServer.ProxyAccounts.Refresh();
|
||||
if (this.DataContainer.Server.JobServer.ProxyAccounts.Contains(this.proxyAccountName))
|
||||
{
|
||||
ProxyAccount proxyAccount = AgentProxyAccount.GetProxyAccount(this.proxyAccountName, this.DataContainer.Server.JobServer);
|
||||
proxyAccount.DropIfExists();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to update the proxy object with properties
|
||||
/// from this page.
|
||||
/// </summary>
|
||||
public void UpdateProxyAccount(ProxyAccount proxyAccount)
|
||||
{
|
||||
if (proxyAccount == null)
|
||||
{
|
||||
throw new ArgumentNullException("proxyAccount");
|
||||
}
|
||||
|
||||
ArrayList principalsToAdd = new ArrayList();
|
||||
ArrayList principalsToRemove = new ArrayList();
|
||||
|
||||
// Process Sql Logins
|
||||
if (ExtractPermissionsToAddAndRemove(this.proxyAccountName != null? proxyAccount.EnumLogins() : null, this.principals[(int) ProxyPrincipalType.SqlLogin], principalsToAdd, principalsToRemove))
|
||||
{
|
||||
foreach (string principal in principalsToRemove)
|
||||
{
|
||||
proxyAccount.RemoveLogin(principal);
|
||||
}
|
||||
|
||||
foreach (string principal in principalsToAdd)
|
||||
{
|
||||
proxyAccount.AddLogin(principal);
|
||||
}
|
||||
}
|
||||
|
||||
// Process Server Roles
|
||||
if (ExtractPermissionsToAddAndRemove(this.proxyAccountName != null? proxyAccount.EnumServerRoles() : null, this.principals[(int) ProxyPrincipalType.ServerRole], principalsToAdd, principalsToRemove))
|
||||
{
|
||||
foreach (string principal in principalsToRemove)
|
||||
{
|
||||
proxyAccount.RemoveServerRole(principal);
|
||||
}
|
||||
|
||||
foreach (string principal in principalsToAdd)
|
||||
{
|
||||
proxyAccount.AddServerRole(principal);
|
||||
}
|
||||
}
|
||||
|
||||
// Process Msdb Roles
|
||||
if (ExtractPermissionsToAddAndRemove(this.proxyAccountName != null? proxyAccount.EnumMsdbRoles() : null, this.principals[(int) ProxyPrincipalType.MsdbRole], principalsToAdd, principalsToRemove))
|
||||
{
|
||||
foreach (string principal in principalsToRemove)
|
||||
{
|
||||
proxyAccount.RemoveMsdbRole(principal);
|
||||
}
|
||||
|
||||
foreach (string principal in principalsToAdd)
|
||||
{
|
||||
proxyAccount.AddMsdbRole(principal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This method scans two list of principals - an existing one extracted from ProxyAccount object
|
||||
/// and a new one obtained from this panel and then it creates a two differential lists: one of
|
||||
/// principals to add and the other of principals to remove.
|
||||
/// </summary>
|
||||
/// <returns>true if there are any changes between existingPermissions and newPermissions lists</returns>
|
||||
private bool ExtractPermissionsToAddAndRemove(DataTable existingPermissions, ArrayList newPermissions, ArrayList principalsToAdd, ArrayList principalsToRemove)
|
||||
{
|
||||
// Reset both output lists
|
||||
principalsToAdd.Clear();
|
||||
principalsToRemove.Clear();
|
||||
|
||||
// Sort both input lists
|
||||
DataRow[] existingRows = existingPermissions != null? existingPermissions.Select(string.Empty, "Name DESC") : new DataRow[] {};
|
||||
newPermissions.Sort();
|
||||
|
||||
// Go through both lists at the same time and find differences
|
||||
int existingPos = 0;
|
||||
int newPos = 0;
|
||||
|
||||
while (newPos < newPermissions.Count && existingPos < existingRows.Length)
|
||||
{
|
||||
int result = string.Compare(existingRows[existingPos]["Name"] as string, newPermissions[newPos] as string,StringComparison.Ordinal);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
// element in existingRows is lower then element in newPermissions
|
||||
// mark element in existingRows for removal
|
||||
principalsToRemove.Add(existingRows[existingPos]["Name"]);
|
||||
++existingPos;
|
||||
}
|
||||
else if (result > 0)
|
||||
{
|
||||
// element in existingRows is greater then element in newPermissions
|
||||
// mark element in newPermissions for adding
|
||||
principalsToAdd.Add(newPermissions[newPos]);
|
||||
++newPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Both elements are equal.
|
||||
// Advance to the next element
|
||||
++existingPos;
|
||||
++newPos;
|
||||
}
|
||||
}
|
||||
|
||||
while (newPos < newPermissions.Count)
|
||||
{
|
||||
// Some elements are still left
|
||||
// Copy them all to Add collection
|
||||
principalsToAdd.Add(newPermissions[newPos++]);
|
||||
}
|
||||
|
||||
while (existingPos < existingRows.Length)
|
||||
{
|
||||
// Some elements are still left
|
||||
// Copy them all to Remove collection
|
||||
principalsToRemove.Add(existingRows[existingPos++]["Name"]);
|
||||
}
|
||||
|
||||
return(principalsToAdd.Count > 0 || principalsToRemove.Count > 0);
|
||||
}
|
||||
|
||||
private void RefreshData()
|
||||
{
|
||||
// List all the jobsteps that use current
|
||||
// proxy account
|
||||
Request req = new Request();
|
||||
req.Urn = string.Format(System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Server/JobServer/Job/Step[@ProxyName=\'{0}\']",
|
||||
Urn.EscapeString(this.proxyAccountName));
|
||||
req.ResultType = ResultType.IDataReader;
|
||||
req.Fields = new string[] {"Name", "SubSystem"};
|
||||
req.ParentPropertiesRequests = new PropertiesRequest[1];
|
||||
req.ParentPropertiesRequests[0] = new PropertiesRequest(new string[] {"Name"});
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
using (IDataReader reader = en.Process(this.DataContainer.ServerConnection, req).Data as IDataReader)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
//JobStepSubSystems.
|
||||
// @TODO - write to output collection
|
||||
// new GridCell(reader.GetString(0)), // Job Name (parent property is first)
|
||||
// new GridCell(reader.GetString(1)), // JobStep Name
|
||||
// new GridCell(JobStepSubSystems.LookupFriendlyName((AgentSubSystem) reader.GetInt32(2))) // JobStep SubSystem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Static methods
|
||||
/// <summary>
|
||||
/// Retrieves an instance of ProxyAccount from job server using name provided.
|
||||
/// If proxy does not exist it throws an exception.
|
||||
/// </summary>
|
||||
/// <param name="proxyAccountName">Name of the proxy to get</param>
|
||||
/// <param name="jobServer">Job server to get the proxy from</param>
|
||||
/// <returns>A valid proxy account.</returns>
|
||||
internal static ProxyAccount GetProxyAccount(string proxyAccountName, JobServer jobServer)
|
||||
{
|
||||
if (proxyAccountName == null || proxyAccountName.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("proxyAccountName");
|
||||
}
|
||||
|
||||
if (jobServer == null)
|
||||
{
|
||||
throw new ArgumentNullException("jobServer");
|
||||
}
|
||||
|
||||
ProxyAccount proxyAccount = jobServer.ProxyAccounts[proxyAccountName];
|
||||
if (proxyAccount == null)
|
||||
{
|
||||
// proxy not found. Try refreshing the collection
|
||||
jobServer.ProxyAccounts.Refresh();
|
||||
proxyAccount = jobServer.ProxyAccounts[proxyAccountName];
|
||||
|
||||
// if still cannot get the proxy throw an exception
|
||||
if (proxyAccount == null)
|
||||
{
|
||||
throw new ApplicationException("SRError.ProxyAccountNotFound(proxyAccountName)");
|
||||
}
|
||||
}
|
||||
return proxyAccount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a proxy account name from shared data containter.
|
||||
/// </summary>
|
||||
internal static void GetProxyAccountName(CDataContainer dataContainer, ref string proxyAccountName, ref bool duplicate)
|
||||
{
|
||||
STParameters parameters = new STParameters();
|
||||
parameters.SetDocument(dataContainer.Document);
|
||||
|
||||
// Get proxy name
|
||||
parameters.GetParam(AgentProxyAccount.ProxyAccountPropertyName, ref proxyAccountName);
|
||||
if (proxyAccountName != null && proxyAccountName.Length == 0)
|
||||
{
|
||||
// Reset empty name back to null
|
||||
proxyAccountName = null;
|
||||
}
|
||||
|
||||
// Get duplicate flag
|
||||
string mode = string.Empty;
|
||||
if (parameters.GetParam(AgentProxyAccount.ProxyAccountMode, ref mode) &&
|
||||
0 == string.Compare(mode, AgentProxyAccount.ProxyAccountDuplicateMode, StringComparison.Ordinal))
|
||||
{
|
||||
duplicate = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses enumerator to list names of all proxy accounts that use specified Agent SubSystem.
|
||||
/// </summary>
|
||||
/// <param name="serverConnection">Connection to use.</param>
|
||||
/// <param name="subsystemName">Requested SubSystem name</param>
|
||||
/// <param name="includeSysadmin">If set to true, 'sysadmin' account is added as a first entry in
|
||||
/// the list of proxy accounts.</param>
|
||||
/// <returns>An array containing names of proxy accounts</returns>
|
||||
internal static string[] ListProxyAccountsForSubsystem(
|
||||
ServerConnection serverConnection,
|
||||
string subsystemName,
|
||||
bool includeSysadmin)
|
||||
{
|
||||
ArrayList proxyAccounts = new ArrayList();
|
||||
|
||||
// This method is valid only on Yukon and later
|
||||
if (serverConnection.ServerVersion.Major >= 9)
|
||||
{
|
||||
if (includeSysadmin)
|
||||
{
|
||||
proxyAccounts.Add(AgentProxyAccount.SysadminAccount);
|
||||
}
|
||||
|
||||
// Get the list of proxy accounts
|
||||
Request req = new Request();
|
||||
|
||||
req.Urn = string.Format(System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Server/JobServer/ProxyAccount/AgentSubSystem[@Name = \"{0}\"]",
|
||||
Urn.EscapeString(subsystemName));
|
||||
req.ResultType = ResultType.IDataReader;
|
||||
req.Fields = new string[] { "Name" };
|
||||
req.ParentPropertiesRequests = new PropertiesRequest[1] { new PropertiesRequest() };
|
||||
req.ParentPropertiesRequests[0].Fields = new string[] { "Name" };
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
|
||||
using (IDataReader reader = en.Process(serverConnection, req).Data as IDataReader)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
proxyAccounts.Add(reader.GetString(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (string[]) proxyAccounts.ToArray(typeof(string));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -403,153 +403,4 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
return foundJobs;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// a class for storing various properties of agent jobs,
|
||||
/// used by the Job Activity Monitor
|
||||
/// </summary>
|
||||
public class JobProperties
|
||||
{
|
||||
private string name;
|
||||
private int currentExecutionStatus;
|
||||
private int lastRunOutcome;
|
||||
private string currentExecutionStep;
|
||||
private bool enabled;
|
||||
private bool hasTarget;
|
||||
private bool hasSchedule;
|
||||
private bool hasStep;
|
||||
private bool runnable;
|
||||
private string category;
|
||||
private int categoryID;
|
||||
private int categoryType;
|
||||
private DateTime lastRun;
|
||||
private DateTime nextRun;
|
||||
private Guid jobId;
|
||||
|
||||
private JobProperties()
|
||||
{
|
||||
}
|
||||
|
||||
public JobProperties(DataRow row)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(row["Name"] != DBNull.Value, "Name is null!");
|
||||
System.Diagnostics.Debug.Assert(row["IsEnabled"] != DBNull.Value, "IsEnabled is null!");
|
||||
System.Diagnostics.Debug.Assert(row["Category"] != DBNull.Value, "Category is null!");
|
||||
System.Diagnostics.Debug.Assert(row["CategoryID"] != DBNull.Value, "CategoryID is null!");
|
||||
System.Diagnostics.Debug.Assert(row["CategoryType"] != DBNull.Value, "CategoryType is null!");
|
||||
System.Diagnostics.Debug.Assert(row["CurrentRunStatus"] != DBNull.Value, "CurrentRunStatus is null!");
|
||||
System.Diagnostics.Debug.Assert(row["CurrentRunStep"] != DBNull.Value, "CurrentRunStep is null!");
|
||||
System.Diagnostics.Debug.Assert(row["HasSchedule"] != DBNull.Value, "HasSchedule is null!");
|
||||
System.Diagnostics.Debug.Assert(row["HasStep"] != DBNull.Value, "HasStep is null!");
|
||||
System.Diagnostics.Debug.Assert(row["HasServer"] != DBNull.Value, "HasServer is null!");
|
||||
System.Diagnostics.Debug.Assert(row["LastRunOutcome"] != DBNull.Value, "LastRunOutcome is null!");
|
||||
System.Diagnostics.Debug.Assert(row["JobID"] != DBNull.Value, "JobID is null!");
|
||||
|
||||
this.name = row["Name"].ToString();
|
||||
this.enabled = Convert.ToBoolean(row["IsEnabled"], CultureInfo.InvariantCulture);
|
||||
this.category = row["Category"].ToString();
|
||||
this.categoryID = Convert.ToInt32(row["CategoryID"], CultureInfo.InvariantCulture);
|
||||
this.categoryType = Convert.ToInt32(row["CategoryType"], CultureInfo.InvariantCulture);
|
||||
this.currentExecutionStatus = Convert.ToInt32(row["CurrentRunStatus"], CultureInfo.InvariantCulture);
|
||||
this.currentExecutionStep = row["CurrentRunStep"].ToString();
|
||||
this.hasSchedule = Convert.ToBoolean(row["HasSchedule"], CultureInfo.InvariantCulture);
|
||||
this.hasStep = Convert.ToBoolean(row["HasStep"], CultureInfo.InvariantCulture);
|
||||
this.hasTarget = Convert.ToBoolean(row["HasServer"], CultureInfo.InvariantCulture);
|
||||
this.lastRunOutcome = Convert.ToInt32(row["LastRunOutcome"], CultureInfo.InvariantCulture);
|
||||
this.jobId = Guid.Parse(row["JobID"].ToString()); ;
|
||||
|
||||
// for a job to be runnable, it must:
|
||||
// 1. have a target server
|
||||
// 2. have some steps
|
||||
this.runnable = this.hasTarget && this.hasStep;
|
||||
|
||||
if (row["LastRunDate"] != DBNull.Value)
|
||||
{
|
||||
this.lastRun = Convert.ToDateTime(row["LastRunDate"], CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (row["NextRunDate"] != DBNull.Value)
|
||||
{
|
||||
this.nextRun = Convert.ToDateTime(row["NextRunDate"], CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Runnable
|
||||
{
|
||||
get{ return runnable;}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get{ return name;}
|
||||
}
|
||||
|
||||
public string Category
|
||||
{
|
||||
get{ return category;}
|
||||
}
|
||||
|
||||
public int CategoryID
|
||||
{
|
||||
get{ return categoryID;}
|
||||
}
|
||||
|
||||
public int CategoryType
|
||||
{
|
||||
get{ return categoryType;}
|
||||
}
|
||||
|
||||
public int LastRunOutcome
|
||||
{
|
||||
get{ return lastRunOutcome;}
|
||||
}
|
||||
|
||||
public int CurrentExecutionStatus
|
||||
{
|
||||
get{ return currentExecutionStatus;}
|
||||
}
|
||||
|
||||
public string CurrentExecutionStep
|
||||
{
|
||||
get{ return currentExecutionStep;}
|
||||
}
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get{ return enabled;}
|
||||
}
|
||||
|
||||
public bool HasTarget
|
||||
{
|
||||
get{ return hasTarget;}
|
||||
}
|
||||
|
||||
public bool HasStep
|
||||
{
|
||||
get{ return hasStep;}
|
||||
}
|
||||
|
||||
public bool HasSchedule
|
||||
{
|
||||
get{ return hasSchedule;}
|
||||
}
|
||||
|
||||
public DateTime NextRun
|
||||
{
|
||||
get{ return nextRun;}
|
||||
}
|
||||
|
||||
public DateTime LastRun
|
||||
{
|
||||
get{ return lastRun;}
|
||||
}
|
||||
|
||||
public Guid JobID
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.jobId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
167
src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/JobProperties.cs
Normal file
167
src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/JobProperties.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// 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.Text;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo.Agent;
|
||||
using SMO = Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Agent
|
||||
{
|
||||
/// <summary>
|
||||
/// a class for storing various properties of agent jobs,
|
||||
/// used by the Job Activity Monitor
|
||||
/// </summary>
|
||||
public class JobProperties
|
||||
{
|
||||
private string name;
|
||||
private int currentExecutionStatus;
|
||||
private int lastRunOutcome;
|
||||
private string currentExecutionStep;
|
||||
private bool enabled;
|
||||
private bool hasTarget;
|
||||
private bool hasSchedule;
|
||||
private bool hasStep;
|
||||
private bool runnable;
|
||||
private string category;
|
||||
private int categoryID;
|
||||
private int categoryType;
|
||||
private DateTime lastRun;
|
||||
private DateTime nextRun;
|
||||
private Guid jobId;
|
||||
|
||||
private JobProperties()
|
||||
{
|
||||
}
|
||||
|
||||
public JobProperties(DataRow row)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(row["Name"] != DBNull.Value, "Name is null!");
|
||||
System.Diagnostics.Debug.Assert(row["IsEnabled"] != DBNull.Value, "IsEnabled is null!");
|
||||
System.Diagnostics.Debug.Assert(row["Category"] != DBNull.Value, "Category is null!");
|
||||
System.Diagnostics.Debug.Assert(row["CategoryID"] != DBNull.Value, "CategoryID is null!");
|
||||
System.Diagnostics.Debug.Assert(row["CategoryType"] != DBNull.Value, "CategoryType is null!");
|
||||
System.Diagnostics.Debug.Assert(row["CurrentRunStatus"] != DBNull.Value, "CurrentRunStatus is null!");
|
||||
System.Diagnostics.Debug.Assert(row["CurrentRunStep"] != DBNull.Value, "CurrentRunStep is null!");
|
||||
System.Diagnostics.Debug.Assert(row["HasSchedule"] != DBNull.Value, "HasSchedule is null!");
|
||||
System.Diagnostics.Debug.Assert(row["HasStep"] != DBNull.Value, "HasStep is null!");
|
||||
System.Diagnostics.Debug.Assert(row["HasServer"] != DBNull.Value, "HasServer is null!");
|
||||
System.Diagnostics.Debug.Assert(row["LastRunOutcome"] != DBNull.Value, "LastRunOutcome is null!");
|
||||
System.Diagnostics.Debug.Assert(row["JobID"] != DBNull.Value, "JobID is null!");
|
||||
|
||||
this.name = row["Name"].ToString();
|
||||
this.enabled = Convert.ToBoolean(row["IsEnabled"], CultureInfo.InvariantCulture);
|
||||
this.category = row["Category"].ToString();
|
||||
this.categoryID = Convert.ToInt32(row["CategoryID"], CultureInfo.InvariantCulture);
|
||||
this.categoryType = Convert.ToInt32(row["CategoryType"], CultureInfo.InvariantCulture);
|
||||
this.currentExecutionStatus = Convert.ToInt32(row["CurrentRunStatus"], CultureInfo.InvariantCulture);
|
||||
this.currentExecutionStep = row["CurrentRunStep"].ToString();
|
||||
this.hasSchedule = Convert.ToBoolean(row["HasSchedule"], CultureInfo.InvariantCulture);
|
||||
this.hasStep = Convert.ToBoolean(row["HasStep"], CultureInfo.InvariantCulture);
|
||||
this.hasTarget = Convert.ToBoolean(row["HasServer"], CultureInfo.InvariantCulture);
|
||||
this.lastRunOutcome = Convert.ToInt32(row["LastRunOutcome"], CultureInfo.InvariantCulture);
|
||||
this.jobId = Guid.Parse(row["JobID"].ToString()); ;
|
||||
|
||||
// for a job to be runnable, it must:
|
||||
// 1. have a target server
|
||||
// 2. have some steps
|
||||
this.runnable = this.hasTarget && this.hasStep;
|
||||
|
||||
if (row["LastRunDate"] != DBNull.Value)
|
||||
{
|
||||
this.lastRun = Convert.ToDateTime(row["LastRunDate"], CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (row["NextRunDate"] != DBNull.Value)
|
||||
{
|
||||
this.nextRun = Convert.ToDateTime(row["NextRunDate"], CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Runnable
|
||||
{
|
||||
get{ return runnable;}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get{ return name;}
|
||||
}
|
||||
|
||||
public string Category
|
||||
{
|
||||
get{ return category;}
|
||||
}
|
||||
|
||||
public int CategoryID
|
||||
{
|
||||
get{ return categoryID;}
|
||||
}
|
||||
|
||||
public int CategoryType
|
||||
{
|
||||
get{ return categoryType;}
|
||||
}
|
||||
|
||||
public int LastRunOutcome
|
||||
{
|
||||
get{ return lastRunOutcome;}
|
||||
}
|
||||
|
||||
public int CurrentExecutionStatus
|
||||
{
|
||||
get{ return currentExecutionStatus;}
|
||||
}
|
||||
|
||||
public string CurrentExecutionStep
|
||||
{
|
||||
get{ return currentExecutionStep;}
|
||||
}
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get{ return enabled;}
|
||||
}
|
||||
|
||||
public bool HasTarget
|
||||
{
|
||||
get{ return hasTarget;}
|
||||
}
|
||||
|
||||
public bool HasStep
|
||||
{
|
||||
get{ return hasStep;}
|
||||
}
|
||||
|
||||
public bool HasSchedule
|
||||
{
|
||||
get{ return hasSchedule;}
|
||||
}
|
||||
|
||||
public DateTime NextRun
|
||||
{
|
||||
get{ return nextRun;}
|
||||
}
|
||||
|
||||
public DateTime LastRun
|
||||
{
|
||||
get{ return lastRun;}
|
||||
}
|
||||
|
||||
public Guid JobID
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.jobId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ using Microsoft.SqlTools.ServiceLayer.Metadata;
|
||||
using Microsoft.SqlTools.ServiceLayer.Profiler;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.Scripting;
|
||||
using Microsoft.SqlTools.ServiceLayer.Security;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
|
||||
@@ -106,6 +107,9 @@ namespace Microsoft.SqlTools.ServiceLayer
|
||||
ProfilerService.Instance.InitializeService(serviceHost);
|
||||
serviceProvider.RegisterSingleService(ProfilerService.Instance);
|
||||
|
||||
SecurityService.Instance.InitializeService(serviceHost);
|
||||
serviceProvider.RegisterSingleService(SecurityService.Instance);
|
||||
|
||||
InitializeHostedServices(serviceProvider, serviceHost);
|
||||
serviceHost.ServiceProvider = serviceProvider;
|
||||
|
||||
|
||||
@@ -3661,6 +3661,518 @@ namespace Microsoft.SqlTools.ServiceLayer
|
||||
}
|
||||
}
|
||||
|
||||
public static string UserCancelledSelectStep
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.UserCancelledSelectStep);
|
||||
}
|
||||
}
|
||||
|
||||
public static string RequestPostedToTargetServers
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.RequestPostedToTargetServers);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Executing
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Executing);
|
||||
}
|
||||
}
|
||||
|
||||
public static string BetweenRetries
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.BetweenRetries);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Suspended
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Suspended);
|
||||
}
|
||||
}
|
||||
|
||||
public static string PerformingCompletionAction
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.PerformingCompletionAction);
|
||||
}
|
||||
}
|
||||
|
||||
public static string WaitingForStepToFinish
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.WaitingForStepToFinish);
|
||||
}
|
||||
}
|
||||
|
||||
public static string WaitingForWorkerThread
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.WaitingForWorkerThread);
|
||||
}
|
||||
}
|
||||
|
||||
public static string AllDatabases
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.AllDatabases);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity001
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity001);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity002
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity002);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity003
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity003);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity004
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity004);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity005
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity005);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity006
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity006);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity007
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity007);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity008
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity008);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity009
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity009);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity010
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity010);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity011
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity011);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity012
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity012);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity013
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity013);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity014
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity014);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity015
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity015);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity016
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity016);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity017
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity017);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity018
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity018);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity019
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity019);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity020
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity020);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity021
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity021);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity022
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity022);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity023
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity023);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity024
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity024);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Severity025
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Severity025);
|
||||
}
|
||||
}
|
||||
|
||||
public static string PagerScheduleMonFri
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.PagerScheduleMonFri);
|
||||
}
|
||||
}
|
||||
|
||||
public static string PagerScheduleSatSun
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.PagerScheduleSatSun);
|
||||
}
|
||||
}
|
||||
|
||||
public static string PagerScheduleWarning
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.PagerScheduleWarning);
|
||||
}
|
||||
}
|
||||
|
||||
public static string General
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.General);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Notifications
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Notifications);
|
||||
}
|
||||
}
|
||||
|
||||
public static string History
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.History);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Day
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Day);
|
||||
}
|
||||
}
|
||||
|
||||
public static string StartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.StartTime);
|
||||
}
|
||||
}
|
||||
|
||||
public static string EndTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.EndTime);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ColumnIndexIsInvalid
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.ColumnIndexIsInvalid);
|
||||
}
|
||||
}
|
||||
|
||||
public static string RowIndexIsInvalid
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.RowIndexIsInvalid);
|
||||
}
|
||||
}
|
||||
|
||||
public static string NewOperatorProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.NewOperatorProperties);
|
||||
}
|
||||
}
|
||||
|
||||
public static string FailedToCreateInitializeAgentOperatorDialog
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.FailedToCreateInitializeAgentOperatorDialog);
|
||||
}
|
||||
}
|
||||
|
||||
public static string JobServerIsNotAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.JobServerIsNotAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
public static string CannotCreateInitializeGeneralPage
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.CannotCreateInitializeGeneralPage);
|
||||
}
|
||||
}
|
||||
|
||||
public static string CannotCreateInitializeNotificationsPage
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.CannotCreateInitializeNotificationsPage);
|
||||
}
|
||||
}
|
||||
|
||||
public static string CannotCreateInitializeHistoryPage
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.CannotCreateInitializeHistoryPage);
|
||||
}
|
||||
}
|
||||
|
||||
public static string CannotResetOperator
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.CannotResetOperator);
|
||||
}
|
||||
}
|
||||
|
||||
public static string AlertList
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.AlertList);
|
||||
}
|
||||
}
|
||||
|
||||
public static string JobList
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.JobList);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Email
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Email);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Pager
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Pager);
|
||||
}
|
||||
}
|
||||
|
||||
public static string AlertName
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.AlertName);
|
||||
}
|
||||
}
|
||||
|
||||
public static string JobName
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.JobName);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Always
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Always);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Never
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.Never);
|
||||
}
|
||||
}
|
||||
|
||||
public static string OnFailure
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.OnFailure);
|
||||
}
|
||||
}
|
||||
|
||||
public static string OnSuccess
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.OnSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
public static string CannotModifyAlerts
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.CannotModifyAlerts);
|
||||
}
|
||||
}
|
||||
|
||||
public static string CannotCreateScriptForModifyAlerts
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.CannotCreateScriptForModifyAlerts);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ConnectionServiceListDbErrorNotConnected(string uri)
|
||||
{
|
||||
return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri);
|
||||
@@ -3751,6 +4263,151 @@ namespace Microsoft.SqlTools.ServiceLayer
|
||||
return Keys.GetString(Keys.EditDataIncorrectTable, tableName);
|
||||
}
|
||||
|
||||
public static string EnableAlertsTitle(String serverName)
|
||||
{
|
||||
return Keys.GetString(Keys.EnableAlertsTitle, serverName);
|
||||
}
|
||||
|
||||
public static string EnableAlertDescription(String alertName)
|
||||
{
|
||||
return Keys.GetString(Keys.EnableAlertDescription, alertName);
|
||||
}
|
||||
|
||||
public static string EnablingAlert(String alertName)
|
||||
{
|
||||
return Keys.GetString(Keys.EnablingAlert, alertName);
|
||||
}
|
||||
|
||||
public static string EnabledAlert(String alertName)
|
||||
{
|
||||
return Keys.GetString(Keys.EnabledAlert, alertName);
|
||||
}
|
||||
|
||||
public static string DisableAlertsTitle(String serverName)
|
||||
{
|
||||
return Keys.GetString(Keys.DisableAlertsTitle, serverName);
|
||||
}
|
||||
|
||||
public static string DisableAlertDescription(String alertName)
|
||||
{
|
||||
return Keys.GetString(Keys.DisableAlertDescription, alertName);
|
||||
}
|
||||
|
||||
public static string DisablingAlert(String alertName)
|
||||
{
|
||||
return Keys.GetString(Keys.DisablingAlert, alertName);
|
||||
}
|
||||
|
||||
public static string DisabledAlert(String alertName)
|
||||
{
|
||||
return Keys.GetString(Keys.DisabledAlert, alertName);
|
||||
}
|
||||
|
||||
public static string EnableJobsTitle(String serverName)
|
||||
{
|
||||
return Keys.GetString(Keys.EnableJobsTitle, serverName);
|
||||
}
|
||||
|
||||
public static string EnableJobDescription(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.EnableJobDescription, jobName);
|
||||
}
|
||||
|
||||
public static string EnablingJob(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.EnablingJob, jobName);
|
||||
}
|
||||
|
||||
public static string EnabledJob(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.EnabledJob, jobName);
|
||||
}
|
||||
|
||||
public static string DisableJobsTitle(String serverName)
|
||||
{
|
||||
return Keys.GetString(Keys.DisableJobsTitle, serverName);
|
||||
}
|
||||
|
||||
public static string DisableJobDescription(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.DisableJobDescription, jobName);
|
||||
}
|
||||
|
||||
public static string DisablingJob(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.DisablingJob, jobName);
|
||||
}
|
||||
|
||||
public static string DisabledJob(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.DisabledJob, jobName);
|
||||
}
|
||||
|
||||
public static string StartJobsTitle(String serverName)
|
||||
{
|
||||
return Keys.GetString(Keys.StartJobsTitle, serverName);
|
||||
}
|
||||
|
||||
public static string StartJobDescription(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.StartJobDescription, jobName);
|
||||
}
|
||||
|
||||
public static string GettingStartStep(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.GettingStartStep, jobName);
|
||||
}
|
||||
|
||||
public static string StartingJob(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.StartingJob, jobName);
|
||||
}
|
||||
|
||||
public static string StartJobWithStep(String jobName, String stepName)
|
||||
{
|
||||
return Keys.GetString(Keys.StartJobWithStep, jobName, stepName);
|
||||
}
|
||||
|
||||
public static string ExecuteJob(string jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.ExecuteJob, jobName);
|
||||
}
|
||||
|
||||
public static string JobFailed(string jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.JobFailed, jobName);
|
||||
}
|
||||
|
||||
public static string StopJobsTitle(String serverName)
|
||||
{
|
||||
return Keys.GetString(Keys.StopJobsTitle, serverName);
|
||||
}
|
||||
|
||||
public static string StopJobDescription(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.StopJobDescription, jobName);
|
||||
}
|
||||
|
||||
public static string StoppingJob(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.StoppingJob, jobName);
|
||||
}
|
||||
|
||||
public static string StoppedJob(String jobName)
|
||||
{
|
||||
return Keys.GetString(Keys.StoppedJob, jobName);
|
||||
}
|
||||
|
||||
public static string UnknownSeverity(int severity)
|
||||
{
|
||||
return Keys.GetString(Keys.UnknownSeverity, severity);
|
||||
}
|
||||
|
||||
public static string OperatorProperties(string operatorName)
|
||||
{
|
||||
return Keys.GetString(Keys.OperatorProperties, operatorName);
|
||||
}
|
||||
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Keys
|
||||
{
|
||||
@@ -5175,6 +5832,285 @@ namespace Microsoft.SqlTools.ServiceLayer
|
||||
public const string ProfilerConnectionNotFound = "ProfilerConnectionNotFound";
|
||||
|
||||
|
||||
public const string EnableAlertsTitle = "EnableAlertsTitle";
|
||||
|
||||
|
||||
public const string EnableAlertDescription = "EnableAlertDescription";
|
||||
|
||||
|
||||
public const string EnablingAlert = "EnablingAlert";
|
||||
|
||||
|
||||
public const string EnabledAlert = "EnabledAlert";
|
||||
|
||||
|
||||
public const string DisableAlertsTitle = "DisableAlertsTitle";
|
||||
|
||||
|
||||
public const string DisableAlertDescription = "DisableAlertDescription";
|
||||
|
||||
|
||||
public const string DisablingAlert = "DisablingAlert";
|
||||
|
||||
|
||||
public const string DisabledAlert = "DisabledAlert";
|
||||
|
||||
|
||||
public const string EnableJobsTitle = "EnableJobsTitle";
|
||||
|
||||
|
||||
public const string EnableJobDescription = "EnableJobDescription";
|
||||
|
||||
|
||||
public const string EnablingJob = "EnablingJob";
|
||||
|
||||
|
||||
public const string EnabledJob = "EnabledJob";
|
||||
|
||||
|
||||
public const string DisableJobsTitle = "DisableJobsTitle";
|
||||
|
||||
|
||||
public const string DisableJobDescription = "DisableJobDescription";
|
||||
|
||||
|
||||
public const string DisablingJob = "DisablingJob";
|
||||
|
||||
|
||||
public const string DisabledJob = "DisabledJob";
|
||||
|
||||
|
||||
public const string StartJobsTitle = "StartJobsTitle";
|
||||
|
||||
|
||||
public const string StartJobDescription = "StartJobDescription";
|
||||
|
||||
|
||||
public const string GettingStartStep = "GettingStartStep";
|
||||
|
||||
|
||||
public const string UserCancelledSelectStep = "UserCancelledSelectStep";
|
||||
|
||||
|
||||
public const string StartingJob = "StartingJob";
|
||||
|
||||
|
||||
public const string StartJobWithStep = "StartJobWithStep";
|
||||
|
||||
|
||||
public const string RequestPostedToTargetServers = "RequestPostedToTargetServers";
|
||||
|
||||
|
||||
public const string ExecuteJob = "ExecuteJob";
|
||||
|
||||
|
||||
public const string JobFailed = "JobFailed";
|
||||
|
||||
|
||||
public const string Executing = "Executing";
|
||||
|
||||
|
||||
public const string BetweenRetries = "BetweenRetries";
|
||||
|
||||
|
||||
public const string Suspended = "Suspended";
|
||||
|
||||
|
||||
public const string PerformingCompletionAction = "PerformingCompletionAction";
|
||||
|
||||
|
||||
public const string WaitingForStepToFinish = "WaitingForStepToFinish";
|
||||
|
||||
|
||||
public const string WaitingForWorkerThread = "WaitingForWorkerThread";
|
||||
|
||||
|
||||
public const string StopJobsTitle = "StopJobsTitle";
|
||||
|
||||
|
||||
public const string StopJobDescription = "StopJobDescription";
|
||||
|
||||
|
||||
public const string StoppingJob = "StoppingJob";
|
||||
|
||||
|
||||
public const string StoppedJob = "StoppedJob";
|
||||
|
||||
|
||||
public const string AllDatabases = "AllDatabases";
|
||||
|
||||
|
||||
public const string UnknownSeverity = "UnknownSeverity";
|
||||
|
||||
|
||||
public const string Severity001 = "Severity001";
|
||||
|
||||
|
||||
public const string Severity002 = "Severity002";
|
||||
|
||||
|
||||
public const string Severity003 = "Severity003";
|
||||
|
||||
|
||||
public const string Severity004 = "Severity004";
|
||||
|
||||
|
||||
public const string Severity005 = "Severity005";
|
||||
|
||||
|
||||
public const string Severity006 = "Severity006";
|
||||
|
||||
|
||||
public const string Severity007 = "Severity007";
|
||||
|
||||
|
||||
public const string Severity008 = "Severity008";
|
||||
|
||||
|
||||
public const string Severity009 = "Severity009";
|
||||
|
||||
|
||||
public const string Severity010 = "Severity010";
|
||||
|
||||
|
||||
public const string Severity011 = "Severity011";
|
||||
|
||||
|
||||
public const string Severity012 = "Severity012";
|
||||
|
||||
|
||||
public const string Severity013 = "Severity013";
|
||||
|
||||
|
||||
public const string Severity014 = "Severity014";
|
||||
|
||||
|
||||
public const string Severity015 = "Severity015";
|
||||
|
||||
|
||||
public const string Severity016 = "Severity016";
|
||||
|
||||
|
||||
public const string Severity017 = "Severity017";
|
||||
|
||||
|
||||
public const string Severity018 = "Severity018";
|
||||
|
||||
|
||||
public const string Severity019 = "Severity019";
|
||||
|
||||
|
||||
public const string Severity020 = "Severity020";
|
||||
|
||||
|
||||
public const string Severity021 = "Severity021";
|
||||
|
||||
|
||||
public const string Severity022 = "Severity022";
|
||||
|
||||
|
||||
public const string Severity023 = "Severity023";
|
||||
|
||||
|
||||
public const string Severity024 = "Severity024";
|
||||
|
||||
|
||||
public const string Severity025 = "Severity025";
|
||||
|
||||
|
||||
public const string PagerScheduleMonFri = "PagerScheduleMonFri";
|
||||
|
||||
|
||||
public const string PagerScheduleSatSun = "PagerScheduleSatSun";
|
||||
|
||||
|
||||
public const string PagerScheduleWarning = "PagerScheduleWarning";
|
||||
|
||||
|
||||
public const string General = "General";
|
||||
|
||||
|
||||
public const string Notifications = "Notifications";
|
||||
|
||||
|
||||
public const string History = "History";
|
||||
|
||||
|
||||
public const string Day = "Day";
|
||||
|
||||
|
||||
public const string StartTime = "StartTime";
|
||||
|
||||
|
||||
public const string EndTime = "EndTime";
|
||||
|
||||
|
||||
public const string ColumnIndexIsInvalid = "ColumnIndexIsInvalid";
|
||||
|
||||
|
||||
public const string RowIndexIsInvalid = "RowIndexIsInvalid";
|
||||
|
||||
|
||||
public const string NewOperatorProperties = "NewOperatorProperties";
|
||||
|
||||
|
||||
public const string OperatorProperties = "OperatorProperties";
|
||||
|
||||
|
||||
public const string FailedToCreateInitializeAgentOperatorDialog = "FailedToCreateInitializeAgentOperatorDialog";
|
||||
|
||||
|
||||
public const string JobServerIsNotAvailable = "JobServerIsNotAvailable";
|
||||
|
||||
|
||||
public const string CannotCreateInitializeGeneralPage = "CannotCreateInitializeGeneralPage";
|
||||
|
||||
|
||||
public const string CannotCreateInitializeNotificationsPage = "CannotCreateInitializeNotificationsPage";
|
||||
|
||||
|
||||
public const string CannotCreateInitializeHistoryPage = "CannotCreateInitializeHistoryPage";
|
||||
|
||||
|
||||
public const string CannotResetOperator = "CannotResetOperator";
|
||||
|
||||
|
||||
public const string AlertList = "AlertList";
|
||||
|
||||
|
||||
public const string JobList = "JobList";
|
||||
|
||||
|
||||
public const string Email = "Email";
|
||||
|
||||
|
||||
public const string Pager = "Pager";
|
||||
|
||||
|
||||
public const string AlertName = "AlertName";
|
||||
|
||||
|
||||
public const string JobName = "JobName";
|
||||
|
||||
|
||||
public const string Always = "Always";
|
||||
|
||||
|
||||
public const string Never = "Never";
|
||||
|
||||
|
||||
public const string OnFailure = "OnFailure";
|
||||
|
||||
|
||||
public const string OnSuccess = "OnSuccess";
|
||||
|
||||
|
||||
public const string CannotModifyAlerts = "CannotModifyAlerts";
|
||||
|
||||
|
||||
public const string CannotCreateScriptForModifyAlerts = "CannotCreateScriptForModifyAlerts";
|
||||
|
||||
|
||||
private Keys()
|
||||
{ }
|
||||
|
||||
|
||||
@@ -2023,4 +2023,405 @@
|
||||
<value>Connection not found</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="EnableAlertsTitle" xml:space="preserve">
|
||||
<value>Enable Alerts - {0}</value>
|
||||
<comment>.
|
||||
Parameters: 0 - serverName (String) </comment>
|
||||
</data>
|
||||
<data name="EnableAlertDescription" xml:space="preserve">
|
||||
<value>Enable Alert '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - alertName (String) </comment>
|
||||
</data>
|
||||
<data name="EnablingAlert" xml:space="preserve">
|
||||
<value>Enabling Alert '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - alertName (String) </comment>
|
||||
</data>
|
||||
<data name="EnabledAlert" xml:space="preserve">
|
||||
<value>Enabled Alert '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - alertName (String) </comment>
|
||||
</data>
|
||||
<data name="DisableAlertsTitle" xml:space="preserve">
|
||||
<value>Disable Alerts - {0}</value>
|
||||
<comment>.
|
||||
Parameters: 0 - serverName (String) </comment>
|
||||
</data>
|
||||
<data name="DisableAlertDescription" xml:space="preserve">
|
||||
<value>Disable Alert '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - alertName (String) </comment>
|
||||
</data>
|
||||
<data name="DisablingAlert" xml:space="preserve">
|
||||
<value>Disabling Alert '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - alertName (String) </comment>
|
||||
</data>
|
||||
<data name="DisabledAlert" xml:space="preserve">
|
||||
<value>Disabled Alert '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - alertName (String) </comment>
|
||||
</data>
|
||||
<data name="EnableJobsTitle" xml:space="preserve">
|
||||
<value>Enable Jobs - {0}</value>
|
||||
<comment>.
|
||||
Parameters: 0 - serverName (String) </comment>
|
||||
</data>
|
||||
<data name="EnableJobDescription" xml:space="preserve">
|
||||
<value>Enable Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="EnablingJob" xml:space="preserve">
|
||||
<value>Enabling Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="EnabledJob" xml:space="preserve">
|
||||
<value>Enabled Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="DisableJobsTitle" xml:space="preserve">
|
||||
<value>Disable Jobs - {0}</value>
|
||||
<comment>.
|
||||
Parameters: 0 - serverName (String) </comment>
|
||||
</data>
|
||||
<data name="DisableJobDescription" xml:space="preserve">
|
||||
<value>Disable Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="DisablingJob" xml:space="preserve">
|
||||
<value>Disabling Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="DisabledJob" xml:space="preserve">
|
||||
<value>Disabled Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="StartJobsTitle" xml:space="preserve">
|
||||
<value>Start Jobs - {0}</value>
|
||||
<comment>.
|
||||
Parameters: 0 - serverName (String) </comment>
|
||||
</data>
|
||||
<data name="StartJobDescription" xml:space="preserve">
|
||||
<value>Start Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="GettingStartStep" xml:space="preserve">
|
||||
<value>Job '{0}' has more than one step. Getting step to start</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="UserCancelledSelectStep" xml:space="preserve">
|
||||
<value>User canceled select step. Job will not be started</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="StartingJob" xml:space="preserve">
|
||||
<value>Starting Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="StartJobWithStep" xml:space="preserve">
|
||||
<value>Start Job '{0}' with step '{1}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String), 1 - stepName (String) </comment>
|
||||
</data>
|
||||
<data name="RequestPostedToTargetServers" xml:space="preserve">
|
||||
<value>Posted remote job execution request</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="ExecuteJob" xml:space="preserve">
|
||||
<value>Execute job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (string) </comment>
|
||||
</data>
|
||||
<data name="JobFailed" xml:space="preserve">
|
||||
<value>Execution of job '{0}' failed. See the history log for details.</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (string) </comment>
|
||||
</data>
|
||||
<data name="Executing" xml:space="preserve">
|
||||
<value>Executing</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="BetweenRetries" xml:space="preserve">
|
||||
<value>Between retries</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Suspended" xml:space="preserve">
|
||||
<value>Suspended</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="PerformingCompletionAction" xml:space="preserve">
|
||||
<value>Performing completion action</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="WaitingForStepToFinish" xml:space="preserve">
|
||||
<value>Waiting for step to finish</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="WaitingForWorkerThread" xml:space="preserve">
|
||||
<value>Waiting for worker thread</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="StopJobsTitle" xml:space="preserve">
|
||||
<value>Stop Jobs - {0}</value>
|
||||
<comment>.
|
||||
Parameters: 0 - serverName (String) </comment>
|
||||
</data>
|
||||
<data name="StopJobDescription" xml:space="preserve">
|
||||
<value>Stop Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="StoppingJob" xml:space="preserve">
|
||||
<value>Stopping Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="StoppedJob" xml:space="preserve">
|
||||
<value>Stopped Job '{0}'</value>
|
||||
<comment>.
|
||||
Parameters: 0 - jobName (String) </comment>
|
||||
</data>
|
||||
<data name="AllDatabases" xml:space="preserve">
|
||||
<value><all databases></value>
|
||||
<comment> First item in database name drop down list</comment>
|
||||
</data>
|
||||
<data name="UnknownSeverity" xml:space="preserve">
|
||||
<value>Unknown severity: {0}</value>
|
||||
<comment> Exception thrown when agent alert has unknown severity level.
|
||||
Parameters: 0 - severity (int) </comment>
|
||||
</data>
|
||||
<data name="Severity001" xml:space="preserve">
|
||||
<value>001 - Miscellaneous System Information</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity002" xml:space="preserve">
|
||||
<value>002 - Reserved</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity003" xml:space="preserve">
|
||||
<value>003 - Reserved</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity004" xml:space="preserve">
|
||||
<value>004 - Reserved</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity005" xml:space="preserve">
|
||||
<value>005 - Reserved</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity006" xml:space="preserve">
|
||||
<value>006 - Reserved</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity007" xml:space="preserve">
|
||||
<value>007 - Notification: Status Information</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity008" xml:space="preserve">
|
||||
<value>008 - Notification: User Intervention Required</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity009" xml:space="preserve">
|
||||
<value>009 - User Defined</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity010" xml:space="preserve">
|
||||
<value>010 - Information</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity011" xml:space="preserve">
|
||||
<value>011 - Specified Database Object Not Found</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity012" xml:space="preserve">
|
||||
<value>012 - Unused</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity013" xml:space="preserve">
|
||||
<value>013 - User Transaction Syntax Error</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity014" xml:space="preserve">
|
||||
<value>014 - Insufficient Permission</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity015" xml:space="preserve">
|
||||
<value>015 - Syntax Error in SQL Statements</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity016" xml:space="preserve">
|
||||
<value>016 - Miscellaneous User Error</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity017" xml:space="preserve">
|
||||
<value>017 - Insufficient Resources</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity018" xml:space="preserve">
|
||||
<value>018 - Nonfatal Internal Error</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity019" xml:space="preserve">
|
||||
<value>019 - Fatal Error in Resource</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity020" xml:space="preserve">
|
||||
<value>020 - Fatal Error in Current Process</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity021" xml:space="preserve">
|
||||
<value>021 - Fatal Error in Database Processes</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity022" xml:space="preserve">
|
||||
<value>022 - Fatal Error: Table Integrity Suspect</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity023" xml:space="preserve">
|
||||
<value>023 - Fatal Error: Database Integrity Suspect</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity024" xml:space="preserve">
|
||||
<value>024 - Fatal Error: Hardware Error</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="Severity025" xml:space="preserve">
|
||||
<value>025 - Fatal Error</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="PagerScheduleMonFri" xml:space="preserve">
|
||||
<value>Pager schedule end time is earlier than start time on Mon-Fri. Do you want to continue?</value>
|
||||
<comment> Message box that displayed if start time is more than end time on Mon-Fri</comment>
|
||||
</data>
|
||||
<data name="PagerScheduleSatSun" xml:space="preserve">
|
||||
<value>Pager schedule end time is earlier than start time on Sat-Sun. Do you want to continue?</value>
|
||||
<comment> Message box that displayed if start time is more than end time on Sat-Sun</comment>
|
||||
</data>
|
||||
<data name="PagerScheduleWarning" xml:space="preserve">
|
||||
<value>Pager schedule warning</value>
|
||||
<comment> Message box caption</comment>
|
||||
</data>
|
||||
<data name="General" xml:space="preserve">
|
||||
<value>General</value>
|
||||
<comment> Tree node name</comment>
|
||||
</data>
|
||||
<data name="Notifications" xml:space="preserve">
|
||||
<value>Notifications</value>
|
||||
<comment> Tree node name</comment>
|
||||
</data>
|
||||
<data name="History" xml:space="preserve">
|
||||
<value>History</value>
|
||||
<comment> Tree node name</comment>
|
||||
</data>
|
||||
<data name="Day" xml:space="preserve">
|
||||
<value>Day</value>
|
||||
<comment> Pager schedule grid column name</comment>
|
||||
</data>
|
||||
<data name="StartTime" xml:space="preserve">
|
||||
<value>Start Time</value>
|
||||
<comment> Pager schedule grid column name</comment>
|
||||
</data>
|
||||
<data name="EndTime" xml:space="preserve">
|
||||
<value>End Time</value>
|
||||
<comment> Pager schedule grid column name</comment>
|
||||
</data>
|
||||
<data name="ColumnIndexIsInvalid" xml:space="preserve">
|
||||
<value>Column index is invalid.</value>
|
||||
<comment> Exception thrown when column index is invalid</comment>
|
||||
</data>
|
||||
<data name="RowIndexIsInvalid" xml:space="preserve">
|
||||
<value>Row index is invalid.</value>
|
||||
<comment> Exception thrown when row index is invalid</comment>
|
||||
</data>
|
||||
<data name="NewOperatorProperties" xml:space="preserve">
|
||||
<value>New Operator</value>
|
||||
<comment> Name of the operator dialog in create new operator mode</comment>
|
||||
</data>
|
||||
<data name="OperatorProperties" xml:space="preserve">
|
||||
<value>{0} Properties</value>
|
||||
<comment> Name of the operator dialog in modify operator mode.
|
||||
Parameters: 0 - operatorName (string) </comment>
|
||||
</data>
|
||||
<data name="FailedToCreateInitializeAgentOperatorDialog" xml:space="preserve">
|
||||
<value>Unable to create/initialize Agent Operator dialog.</value>
|
||||
<comment> Exception thrown when dialog cannot be created/intialized.</comment>
|
||||
</data>
|
||||
<data name="JobServerIsNotAvailable" xml:space="preserve">
|
||||
<value>Job server is not available.</value>
|
||||
<comment> Exception thrown when job server is not available</comment>
|
||||
</data>
|
||||
<data name="CannotCreateInitializeGeneralPage" xml:space="preserve">
|
||||
<value>Cannot create/initialize General page.</value>
|
||||
<comment> Exception thrown when we cannot create/initialize agent operators general page</comment>
|
||||
</data>
|
||||
<data name="CannotCreateInitializeNotificationsPage" xml:space="preserve">
|
||||
<value>Cannot create/initialize Notifications page.</value>
|
||||
<comment> Exception thrown when we cannot create/initialize agent operators notifications page</comment>
|
||||
</data>
|
||||
<data name="CannotCreateInitializeHistoryPage" xml:space="preserve">
|
||||
<value>Cannot create/initialize History page.</value>
|
||||
<comment> Exception thrown when we cannot create/initialize agent operators history page</comment>
|
||||
</data>
|
||||
<data name="CannotResetOperator" xml:space="preserve">
|
||||
<value>Cannot reset operator.</value>
|
||||
<comment> Exception throw when dialog cannot refresh operator</comment>
|
||||
</data>
|
||||
<data name="AlertList" xml:space="preserve">
|
||||
<value>Alert list:</value>
|
||||
<comment> Name of label on notifications page</comment>
|
||||
</data>
|
||||
<data name="JobList" xml:space="preserve">
|
||||
<value>Job list:</value>
|
||||
<comment> Name of label on notifications page</comment>
|
||||
</data>
|
||||
<data name="Email" xml:space="preserve">
|
||||
<value>E-mail</value>
|
||||
<comment> Name of column on notifications page</comment>
|
||||
</data>
|
||||
<data name="Pager" xml:space="preserve">
|
||||
<value>Pager</value>
|
||||
<comment> Name of column on notifications page</comment>
|
||||
</data>
|
||||
<data name="AlertName" xml:space="preserve">
|
||||
<value>Alert name</value>
|
||||
<comment> Name of column on notifications page</comment>
|
||||
</data>
|
||||
<data name="JobName" xml:space="preserve">
|
||||
<value>Job name</value>
|
||||
<comment> Name of column on notifications page</comment>
|
||||
</data>
|
||||
<data name="Always" xml:space="preserve">
|
||||
<value>Always</value>
|
||||
<comment> Completion Action</comment>
|
||||
</data>
|
||||
<data name="Never" xml:space="preserve">
|
||||
<value>Never</value>
|
||||
<comment> Completion Action</comment>
|
||||
</data>
|
||||
<data name="OnFailure" xml:space="preserve">
|
||||
<value>On failure</value>
|
||||
<comment> Completion Action</comment>
|
||||
</data>
|
||||
<data name="OnSuccess" xml:space="preserve">
|
||||
<value>On success</value>
|
||||
<comment> Completion Action</comment>
|
||||
</data>
|
||||
<data name="CannotModifyAlerts" xml:space="preserve">
|
||||
<value>Cannot modify alerts.</value>
|
||||
<comment> Exception thrown when we cannot modify alerts</comment>
|
||||
</data>
|
||||
<data name="CannotCreateScriptForModifyAlerts" xml:space="preserve">
|
||||
<value>Cannot create script for modify alerts.</value>
|
||||
<comment> Exception thrown when we cannot create script that modify alerts</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -887,3 +887,158 @@ InvalidPathError = Cannot access the specified path on the server: {0}
|
||||
############################################################################
|
||||
# Profiler
|
||||
ProfilerConnectionNotFound = Connection not found
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#############################################################################
|
||||
# SQL Agent
|
||||
EnableAlertsTitle(String serverName) = Enable Alerts - {0}
|
||||
EnableAlertDescription(String alertName) = Enable Alert '{0}'
|
||||
EnablingAlert(String alertName) = Enabling Alert '{0}'
|
||||
EnabledAlert(String alertName) = Enabled Alert '{0}'
|
||||
|
||||
DisableAlertsTitle(String serverName) = Disable Alerts - {0}
|
||||
DisableAlertDescription(String alertName) = Disable Alert '{0}'
|
||||
DisablingAlert(String alertName) = Disabling Alert '{0}'
|
||||
DisabledAlert(String alertName) = Disabled Alert '{0}'
|
||||
|
||||
EnableJobsTitle(String serverName) = Enable Jobs - {0}
|
||||
EnableJobDescription(String jobName) = Enable Job '{0}'
|
||||
EnablingJob(String jobName) = Enabling Job '{0}'
|
||||
EnabledJob(String jobName) = Enabled Job '{0}'
|
||||
|
||||
DisableJobsTitle(String serverName) = Disable Jobs - {0}
|
||||
DisableJobDescription(String jobName) = Disable Job '{0}'
|
||||
DisablingJob(String jobName) = Disabling Job '{0}'
|
||||
DisabledJob(String jobName) = Disabled Job '{0}'
|
||||
|
||||
StartJobsTitle(String serverName) = Start Jobs - {0}
|
||||
StartJobDescription(String jobName) = Start Job '{0}'
|
||||
GettingStartStep(String jobName) = Job '{0}' has more than one step. Getting step to start
|
||||
UserCancelledSelectStep = User canceled select step. Job will not be started
|
||||
StartingJob(String jobName) = Starting Job '{0}'
|
||||
StartJobWithStep(String jobName, String stepName) = Start Job '{0}' with step '{1}'
|
||||
RequestPostedToTargetServers = Posted remote job execution request
|
||||
|
||||
ExecuteJob(string jobName) = Execute job '{0}'
|
||||
JobFailed(string jobName) = Execution of job '{0}' failed. See the history log for details.
|
||||
Executing = Executing
|
||||
BetweenRetries = Between retries
|
||||
Suspended = Suspended
|
||||
PerformingCompletionAction = Performing completion action
|
||||
WaitingForStepToFinish = Waiting for step to finish
|
||||
WaitingForWorkerThread = Waiting for worker thread
|
||||
|
||||
StopJobsTitle(String serverName) = Stop Jobs - {0}
|
||||
StopJobDescription(String jobName) = Stop Job '{0}'
|
||||
StoppingJob(String jobName) = Stopping Job '{0}'
|
||||
StoppedJob(String jobName) = Stopped Job '{0}'
|
||||
|
||||
; First item in database name drop down list
|
||||
AllDatabases = <all databases>
|
||||
; Exception thrown when agent alert has unknown severity level
|
||||
UnknownSeverity(int severity) = Unknown severity: {0}
|
||||
|
||||
#severity types
|
||||
Severity001 = 001 - Miscellaneous System Information
|
||||
Severity002 = 002 - Reserved
|
||||
Severity003 = 003 - Reserved
|
||||
Severity004 = 004 - Reserved
|
||||
Severity005 = 005 - Reserved
|
||||
Severity006 = 006 - Reserved
|
||||
Severity007 = 007 - Notification: Status Information
|
||||
Severity008 = 008 - Notification: User Intervention Required
|
||||
Severity009 = 009 - User Defined
|
||||
Severity010 = 010 - Information
|
||||
Severity011 = 011 - Specified Database Object Not Found
|
||||
Severity012 = 012 - Unused
|
||||
Severity013 = 013 - User Transaction Syntax Error
|
||||
Severity014 = 014 - Insufficient Permission
|
||||
Severity015 = 015 - Syntax Error in SQL Statements
|
||||
Severity016 = 016 - Miscellaneous User Error
|
||||
Severity017 = 017 - Insufficient Resources
|
||||
Severity018 = 018 - Nonfatal Internal Error
|
||||
Severity019 = 019 - Fatal Error in Resource
|
||||
Severity020 = 020 - Fatal Error in Current Process
|
||||
Severity021 = 021 - Fatal Error in Database Processes
|
||||
Severity022 = 022 - Fatal Error: Table Integrity Suspect
|
||||
Severity023 = 023 - Fatal Error: Database Integrity Suspect
|
||||
Severity024 = 024 - Fatal Error: Hardware Error
|
||||
Severity025 = 025 - Fatal Error
|
||||
|
||||
; Message box that displayed if start time is more than end time on Mon-Fri
|
||||
PagerScheduleMonFri = Pager schedule end time is earlier than start time on Mon-Fri. Do you want to continue?
|
||||
; Message box that displayed if start time is more than end time on Sat-Sun
|
||||
PagerScheduleSatSun = Pager schedule end time is earlier than start time on Sat-Sun. Do you want to continue?
|
||||
; Message box caption
|
||||
PagerScheduleWarning = Pager schedule warning
|
||||
|
||||
; Tree node name
|
||||
General = General
|
||||
; Tree node name
|
||||
Notifications = Notifications
|
||||
; Tree node name
|
||||
History = History
|
||||
; Pager schedule grid column name
|
||||
Day = Day
|
||||
; Pager schedule grid column name
|
||||
StartTime = Start Time
|
||||
; Pager schedule grid column name
|
||||
EndTime = End Time
|
||||
; Exception thrown when column index is invalid
|
||||
ColumnIndexIsInvalid = Column index is invalid.
|
||||
; Exception thrown when row index is invalid
|
||||
RowIndexIsInvalid = Row index is invalid.
|
||||
; Name of the operator dialog in create new operator mode
|
||||
NewOperatorProperties = New Operator
|
||||
; Name of the operator dialog in modify operator mode
|
||||
OperatorProperties(string operatorName) = {0} Properties
|
||||
; Exception thrown when dialog cannot be created/intialized.
|
||||
FailedToCreateInitializeAgentOperatorDialog = Unable to create/initialize Agent Operator dialog.
|
||||
; Exception thrown when job server is not available
|
||||
JobServerIsNotAvailable = Job server is not available.
|
||||
; Exception thrown when we cannot create/initialize agent operators general page
|
||||
CannotCreateInitializeGeneralPage = Cannot create/initialize General page.
|
||||
; Exception thrown when we cannot create/initialize agent operators notifications page
|
||||
CannotCreateInitializeNotificationsPage = Cannot create/initialize Notifications page.
|
||||
; Exception thrown when we cannot create/initialize agent operators history page
|
||||
CannotCreateInitializeHistoryPage = Cannot create/initialize History page.
|
||||
; Exception throw when dialog cannot refresh operator
|
||||
CannotResetOperator = Cannot reset operator.
|
||||
|
||||
|
||||
#
|
||||
; Name of label on notifications page
|
||||
AlertList = Alert list:
|
||||
; Name of label on notifications page
|
||||
JobList = Job list:
|
||||
; Name of column on notifications page
|
||||
Email = E-mail
|
||||
; Name of column on notifications page
|
||||
Pager = Pager
|
||||
; Name of column on notifications page
|
||||
AlertName = Alert name
|
||||
; Name of column on notifications page
|
||||
JobName = Job name
|
||||
; Completion Action
|
||||
Always = Always
|
||||
; Completion Action
|
||||
Never = Never
|
||||
; Completion Action
|
||||
OnFailure = On failure
|
||||
; Completion Action
|
||||
OnSuccess = On success
|
||||
; Exception thrown when we cannot modify alerts
|
||||
CannotModifyAlerts = Cannot modify alerts.
|
||||
; Exception thrown when we cannot create script that modify alerts
|
||||
CannotCreateScriptForModifyAlerts = Cannot create script for modify alerts.
|
||||
|
||||
@@ -2379,6 +2379,500 @@
|
||||
<note>.
|
||||
Parameters: 0 - tableName (string) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="EnableAlertsTitle">
|
||||
<source>Enable Alerts - {0}</source>
|
||||
<target state="new">Enable Alerts - {0}</target>
|
||||
<note>.
|
||||
Parameters: 0 - serverName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="EnableAlertDescription">
|
||||
<source>Enable Alert '{0}'</source>
|
||||
<target state="new">Enable Alert '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - alertName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="EnablingAlert">
|
||||
<source>Enabling Alert '{0}'</source>
|
||||
<target state="new">Enabling Alert '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - alertName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="EnabledAlert">
|
||||
<source>Enabled Alert '{0}'</source>
|
||||
<target state="new">Enabled Alert '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - alertName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DisableAlertsTitle">
|
||||
<source>Disable Alerts - {0}</source>
|
||||
<target state="new">Disable Alerts - {0}</target>
|
||||
<note>.
|
||||
Parameters: 0 - serverName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DisableAlertDescription">
|
||||
<source>Disable Alert '{0}'</source>
|
||||
<target state="new">Disable Alert '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - alertName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DisablingAlert">
|
||||
<source>Disabling Alert '{0}'</source>
|
||||
<target state="new">Disabling Alert '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - alertName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DisabledAlert">
|
||||
<source>Disabled Alert '{0}'</source>
|
||||
<target state="new">Disabled Alert '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - alertName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="EnableJobsTitle">
|
||||
<source>Enable Jobs - {0}</source>
|
||||
<target state="new">Enable Jobs - {0}</target>
|
||||
<note>.
|
||||
Parameters: 0 - serverName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="EnableJobDescription">
|
||||
<source>Enable Job '{0}'</source>
|
||||
<target state="new">Enable Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="EnablingJob">
|
||||
<source>Enabling Job '{0}'</source>
|
||||
<target state="new">Enabling Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="EnabledJob">
|
||||
<source>Enabled Job '{0}'</source>
|
||||
<target state="new">Enabled Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DisableJobsTitle">
|
||||
<source>Disable Jobs - {0}</source>
|
||||
<target state="new">Disable Jobs - {0}</target>
|
||||
<note>.
|
||||
Parameters: 0 - serverName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DisableJobDescription">
|
||||
<source>Disable Job '{0}'</source>
|
||||
<target state="new">Disable Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DisablingJob">
|
||||
<source>Disabling Job '{0}'</source>
|
||||
<target state="new">Disabling Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DisabledJob">
|
||||
<source>Disabled Job '{0}'</source>
|
||||
<target state="new">Disabled Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StartJobsTitle">
|
||||
<source>Start Jobs - {0}</source>
|
||||
<target state="new">Start Jobs - {0}</target>
|
||||
<note>.
|
||||
Parameters: 0 - serverName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StartJobDescription">
|
||||
<source>Start Job '{0}'</source>
|
||||
<target state="new">Start Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GettingStartStep">
|
||||
<source>Job '{0}' has more than one step. Getting step to start</source>
|
||||
<target state="new">Job '{0}' has more than one step. Getting step to start</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="UserCancelledSelectStep">
|
||||
<source>User canceled select step. Job will not be started</source>
|
||||
<target state="new">User canceled select step. Job will not be started</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingJob">
|
||||
<source>Starting Job '{0}'</source>
|
||||
<target state="new">Starting Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StartJobWithStep">
|
||||
<source>Start Job '{0}' with step '{1}'</source>
|
||||
<target state="new">Start Job '{0}' with step '{1}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String), 1 - stepName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="RequestPostedToTargetServers">
|
||||
<source>Posted remote job execution request</source>
|
||||
<target state="new">Posted remote job execution request</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ExecuteJob">
|
||||
<source>Execute job '{0}'</source>
|
||||
<target state="new">Execute job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (string) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="JobFailed">
|
||||
<source>Execution of job '{0}' failed. See the history log for details.</source>
|
||||
<target state="new">Execution of job '{0}' failed. See the history log for details.</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (string) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Executing">
|
||||
<source>Executing</source>
|
||||
<target state="new">Executing</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="BetweenRetries">
|
||||
<source>Between retries</source>
|
||||
<target state="new">Between retries</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Suspended">
|
||||
<source>Suspended</source>
|
||||
<target state="new">Suspended</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PerformingCompletionAction">
|
||||
<source>Performing completion action</source>
|
||||
<target state="new">Performing completion action</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="WaitingForStepToFinish">
|
||||
<source>Waiting for step to finish</source>
|
||||
<target state="new">Waiting for step to finish</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="WaitingForWorkerThread">
|
||||
<source>Waiting for worker thread</source>
|
||||
<target state="new">Waiting for worker thread</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StopJobsTitle">
|
||||
<source>Stop Jobs - {0}</source>
|
||||
<target state="new">Stop Jobs - {0}</target>
|
||||
<note>.
|
||||
Parameters: 0 - serverName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StopJobDescription">
|
||||
<source>Stop Job '{0}'</source>
|
||||
<target state="new">Stop Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StoppingJob">
|
||||
<source>Stopping Job '{0}'</source>
|
||||
<target state="new">Stopping Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StoppedJob">
|
||||
<source>Stopped Job '{0}'</source>
|
||||
<target state="new">Stopped Job '{0}'</target>
|
||||
<note>.
|
||||
Parameters: 0 - jobName (String) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="AllDatabases">
|
||||
<source><all databases></source>
|
||||
<target state="new"><all databases></target>
|
||||
<note> First item in database name drop down list</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="UnknownSeverity">
|
||||
<source>Unknown severity: {0}</source>
|
||||
<target state="new">Unknown severity: {0}</target>
|
||||
<note> Exception thrown when agent alert has unknown severity level.
|
||||
Parameters: 0 - severity (int) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity001">
|
||||
<source>001 - Miscellaneous System Information</source>
|
||||
<target state="new">001 - Miscellaneous System Information</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity002">
|
||||
<source>002 - Reserved</source>
|
||||
<target state="new">002 - Reserved</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity003">
|
||||
<source>003 - Reserved</source>
|
||||
<target state="new">003 - Reserved</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity004">
|
||||
<source>004 - Reserved</source>
|
||||
<target state="new">004 - Reserved</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity005">
|
||||
<source>005 - Reserved</source>
|
||||
<target state="new">005 - Reserved</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity006">
|
||||
<source>006 - Reserved</source>
|
||||
<target state="new">006 - Reserved</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity007">
|
||||
<source>007 - Notification: Status Information</source>
|
||||
<target state="new">007 - Notification: Status Information</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity008">
|
||||
<source>008 - Notification: User Intervention Required</source>
|
||||
<target state="new">008 - Notification: User Intervention Required</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity009">
|
||||
<source>009 - User Defined</source>
|
||||
<target state="new">009 - User Defined</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity010">
|
||||
<source>010 - Information</source>
|
||||
<target state="new">010 - Information</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity011">
|
||||
<source>011 - Specified Database Object Not Found</source>
|
||||
<target state="new">011 - Specified Database Object Not Found</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity012">
|
||||
<source>012 - Unused</source>
|
||||
<target state="new">012 - Unused</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity013">
|
||||
<source>013 - User Transaction Syntax Error</source>
|
||||
<target state="new">013 - User Transaction Syntax Error</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity014">
|
||||
<source>014 - Insufficient Permission</source>
|
||||
<target state="new">014 - Insufficient Permission</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity015">
|
||||
<source>015 - Syntax Error in SQL Statements</source>
|
||||
<target state="new">015 - Syntax Error in SQL Statements</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity016">
|
||||
<source>016 - Miscellaneous User Error</source>
|
||||
<target state="new">016 - Miscellaneous User Error</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity017">
|
||||
<source>017 - Insufficient Resources</source>
|
||||
<target state="new">017 - Insufficient Resources</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity018">
|
||||
<source>018 - Nonfatal Internal Error</source>
|
||||
<target state="new">018 - Nonfatal Internal Error</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity019">
|
||||
<source>019 - Fatal Error in Resource</source>
|
||||
<target state="new">019 - Fatal Error in Resource</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity020">
|
||||
<source>020 - Fatal Error in Current Process</source>
|
||||
<target state="new">020 - Fatal Error in Current Process</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity021">
|
||||
<source>021 - Fatal Error in Database Processes</source>
|
||||
<target state="new">021 - Fatal Error in Database Processes</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity022">
|
||||
<source>022 - Fatal Error: Table Integrity Suspect</source>
|
||||
<target state="new">022 - Fatal Error: Table Integrity Suspect</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity023">
|
||||
<source>023 - Fatal Error: Database Integrity Suspect</source>
|
||||
<target state="new">023 - Fatal Error: Database Integrity Suspect</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity024">
|
||||
<source>024 - Fatal Error: Hardware Error</source>
|
||||
<target state="new">024 - Fatal Error: Hardware Error</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Severity025">
|
||||
<source>025 - Fatal Error</source>
|
||||
<target state="new">025 - Fatal Error</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PagerScheduleMonFri">
|
||||
<source>Pager schedule end time is earlier than start time on Mon-Fri. Do you want to continue?</source>
|
||||
<target state="new">Pager schedule end time is earlier than start time on Mon-Fri. Do you want to continue?</target>
|
||||
<note> Message box that displayed if start time is more than end time on Mon-Fri</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PagerScheduleSatSun">
|
||||
<source>Pager schedule end time is earlier than start time on Sat-Sun. Do you want to continue?</source>
|
||||
<target state="new">Pager schedule end time is earlier than start time on Sat-Sun. Do you want to continue?</target>
|
||||
<note> Message box that displayed if start time is more than end time on Sat-Sun</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PagerScheduleWarning">
|
||||
<source>Pager schedule warning</source>
|
||||
<target state="new">Pager schedule warning</target>
|
||||
<note> Message box caption</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="General">
|
||||
<source>General</source>
|
||||
<target state="new">General</target>
|
||||
<note> Tree node name</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Notifications">
|
||||
<source>Notifications</source>
|
||||
<target state="new">Notifications</target>
|
||||
<note> Tree node name</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="History">
|
||||
<source>History</source>
|
||||
<target state="new">History</target>
|
||||
<note> Tree node name</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Day">
|
||||
<source>Day</source>
|
||||
<target state="new">Day</target>
|
||||
<note> Pager schedule grid column name</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StartTime">
|
||||
<source>Start Time</source>
|
||||
<target state="new">Start Time</target>
|
||||
<note> Pager schedule grid column name</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="EndTime">
|
||||
<source>End Time</source>
|
||||
<target state="new">End Time</target>
|
||||
<note> Pager schedule grid column name</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ColumnIndexIsInvalid">
|
||||
<source>Column index is invalid.</source>
|
||||
<target state="new">Column index is invalid.</target>
|
||||
<note> Exception thrown when column index is invalid</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="RowIndexIsInvalid">
|
||||
<source>Row index is invalid.</source>
|
||||
<target state="new">Row index is invalid.</target>
|
||||
<note> Exception thrown when row index is invalid</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="NewOperatorProperties">
|
||||
<source>New Operator</source>
|
||||
<target state="new">New Operator</target>
|
||||
<note> Name of the operator dialog in create new operator mode</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="OperatorProperties">
|
||||
<source>{0} Properties</source>
|
||||
<target state="new">{0} Properties</target>
|
||||
<note> Name of the operator dialog in modify operator mode.
|
||||
Parameters: 0 - operatorName (string) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="FailedToCreateInitializeAgentOperatorDialog">
|
||||
<source>Unable to create/initialize Agent Operator dialog.</source>
|
||||
<target state="new">Unable to create/initialize Agent Operator dialog.</target>
|
||||
<note> Exception thrown when dialog cannot be created/intialized.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="JobServerIsNotAvailable">
|
||||
<source>Job server is not available.</source>
|
||||
<target state="new">Job server is not available.</target>
|
||||
<note> Exception thrown when job server is not available</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotCreateInitializeGeneralPage">
|
||||
<source>Cannot create/initialize General page.</source>
|
||||
<target state="new">Cannot create/initialize General page.</target>
|
||||
<note> Exception thrown when we cannot create/initialize agent operators general page</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotCreateInitializeNotificationsPage">
|
||||
<source>Cannot create/initialize Notifications page.</source>
|
||||
<target state="new">Cannot create/initialize Notifications page.</target>
|
||||
<note> Exception thrown when we cannot create/initialize agent operators notifications page</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotCreateInitializeHistoryPage">
|
||||
<source>Cannot create/initialize History page.</source>
|
||||
<target state="new">Cannot create/initialize History page.</target>
|
||||
<note> Exception thrown when we cannot create/initialize agent operators history page</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotResetOperator">
|
||||
<source>Cannot reset operator.</source>
|
||||
<target state="new">Cannot reset operator.</target>
|
||||
<note> Exception throw when dialog cannot refresh operator</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="AlertList">
|
||||
<source>Alert list:</source>
|
||||
<target state="new">Alert list:</target>
|
||||
<note> Name of label on notifications page</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="JobList">
|
||||
<source>Job list:</source>
|
||||
<target state="new">Job list:</target>
|
||||
<note> Name of label on notifications page</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Email">
|
||||
<source>E-mail</source>
|
||||
<target state="new">E-mail</target>
|
||||
<note> Name of column on notifications page</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Pager">
|
||||
<source>Pager</source>
|
||||
<target state="new">Pager</target>
|
||||
<note> Name of column on notifications page</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="AlertName">
|
||||
<source>Alert name</source>
|
||||
<target state="new">Alert name</target>
|
||||
<note> Name of column on notifications page</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="JobName">
|
||||
<source>Job name</source>
|
||||
<target state="new">Job name</target>
|
||||
<note> Name of column on notifications page</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Always">
|
||||
<source>Always</source>
|
||||
<target state="new">Always</target>
|
||||
<note> Completion Action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Never">
|
||||
<source>Never</source>
|
||||
<target state="new">Never</target>
|
||||
<note> Completion Action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="OnFailure">
|
||||
<source>On failure</source>
|
||||
<target state="new">On failure</target>
|
||||
<note> Completion Action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="OnSuccess">
|
||||
<source>On success</source>
|
||||
<target state="new">On success</target>
|
||||
<note> Completion Action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotModifyAlerts">
|
||||
<source>Cannot modify alerts.</source>
|
||||
<target state="new">Cannot modify alerts.</target>
|
||||
<note> Exception thrown when we cannot modify alerts</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotCreateScriptForModifyAlerts">
|
||||
<source>Cannot create script for modify alerts.</source>
|
||||
<target state="new">Cannot create script for modify alerts.</target>
|
||||
<note> Exception thrown when we cannot create script that modify alerts</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// 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 Microsoft.SqlTools.ServiceLayer.Agent;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// a class for storing various credential properties
|
||||
/// </summary>
|
||||
public class CredentialInfo
|
||||
{
|
||||
public string Identity { get; set; }
|
||||
public int Id { get; }
|
||||
public DateTime DateLastModified { get; }
|
||||
public DateTime CreateDate { get; }
|
||||
public string ProviderName { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Create Credential parameters
|
||||
/// </summary>
|
||||
public class CreateCredentialParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public CredentialInfo Credential { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create Credential result
|
||||
/// </summary>
|
||||
public class CreateCredentialResult
|
||||
{
|
||||
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create Credential request type
|
||||
/// </summary>
|
||||
public class CreateCredentialRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<CreateCredentialParams, CreateCredentialResult> Type =
|
||||
RequestType<CreateCredentialParams, CreateCredentialResult>.Create("security/createcredential");
|
||||
}
|
||||
}
|
||||
114
src/Microsoft.SqlTools.ServiceLayer/Security/Credential.cs
Normal file
114
src/Microsoft.SqlTools.ServiceLayer/Security/Credential.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
//
|
||||
// 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;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Xml;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.Diagnostics;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
{
|
||||
internal class Credential : ManagementActionBase
|
||||
{
|
||||
|
||||
// #region Trace support
|
||||
// private const string componentName = "Credential";
|
||||
|
||||
// public string ComponentName
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return componentName;
|
||||
// }
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
#region Constants
|
||||
private const int MAX_SQL_SYS_NAME_LENGTH = 128; // max sql sys name length
|
||||
private const string PASSWORD_MASK_STRING = "**********";
|
||||
#endregion
|
||||
|
||||
#region Variables
|
||||
private CredentialData credentialData = null;
|
||||
#endregion
|
||||
|
||||
#region Constructors / Dispose
|
||||
/// <summary>
|
||||
/// required when loading from Object Explorer context
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public Credential(CDataContainer context)
|
||||
{
|
||||
this.DataContainer = context;
|
||||
this.credentialData = new CredentialData(context);
|
||||
this.credentialData.Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
protected override void Dispose( bool disposing )
|
||||
{
|
||||
base.Dispose( disposing );
|
||||
if (disposing == true)
|
||||
{
|
||||
if (this.credentialData != null)
|
||||
{
|
||||
this.credentialData.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Overrides SqlManagementUserControl
|
||||
/// <summary>
|
||||
/// called on background thread by the framework to execute the action
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
public void OnRunNow(object sender)
|
||||
{
|
||||
this.credentialData.SendDataToServer();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// update logic layer based on content of user interface
|
||||
/// </summary>
|
||||
private void UpdateLogicLayer()
|
||||
{
|
||||
|
||||
this.credentialData.CredentialName = "this.textBoxCredentialName.Text";
|
||||
this.credentialData.CredentialIdentity = "this.textBoxIdentity.Text";
|
||||
|
||||
|
||||
this.credentialData.SecurePassword = AdminService.BuildSecureStringFromPassword("password");
|
||||
this.credentialData.SecurePasswordConfirm = AdminService.BuildSecureStringFromPassword("password");
|
||||
|
||||
if (this.ServerConnection.ServerVersion.Major >= 10)
|
||||
{
|
||||
// need to update only during create time
|
||||
this.credentialData.IsEncryptionByProvider = true; //this.checkBoxUseProvider.Checked;
|
||||
if (this.credentialData.IsEncryptionByProvider)
|
||||
{
|
||||
this.credentialData.ProviderName = "this.comboBoxProviderName.SelectedItem.ToString()";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.credentialData.ProviderName = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
256
src/Microsoft.SqlTools.ServiceLayer/Security/CredentialData.cs
Normal file
256
src/Microsoft.SqlTools.ServiceLayer/Security/CredentialData.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
|
||||
//
|
||||
// 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.SqlClient;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Diagnostics;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
{
|
||||
internal class CredentialException : Exception
|
||||
{
|
||||
public CredentialException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal class CredentialData : IDisposable
|
||||
{
|
||||
#region Properties
|
||||
private string credentialName = string.Empty;
|
||||
public string CredentialName
|
||||
{
|
||||
get { return credentialName; }
|
||||
set { credentialName = value; }
|
||||
}
|
||||
|
||||
private string credentialIdentity = string.Empty;
|
||||
public string CredentialIdentity
|
||||
{
|
||||
get { return credentialIdentity; }
|
||||
set { credentialIdentity = value; }
|
||||
}
|
||||
|
||||
private SecureString securePassword;
|
||||
public SecureString SecurePassword
|
||||
{
|
||||
get { return securePassword; }
|
||||
set
|
||||
{
|
||||
securePassword = value;
|
||||
PasswordWasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
private SecureString securePasswordConfirm;
|
||||
public SecureString SecurePasswordConfirm
|
||||
{
|
||||
get { return securePasswordConfirm; }
|
||||
set
|
||||
{
|
||||
securePasswordConfirm = value;
|
||||
PasswordWasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool isPropertiesMode = false;
|
||||
public bool IsPropertiesMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return isPropertiesMode;
|
||||
}
|
||||
}
|
||||
|
||||
private bool passwordWasChanged = false;
|
||||
public bool PasswordWasChanged
|
||||
{
|
||||
get { return passwordWasChanged; }
|
||||
set { passwordWasChanged = value; }
|
||||
}
|
||||
|
||||
private bool isEncryptionByProvider = false;
|
||||
public bool IsEncryptionByProvider
|
||||
{
|
||||
get { return isEncryptionByProvider; }
|
||||
set { isEncryptionByProvider = value; }
|
||||
}
|
||||
|
||||
private string providerName = string.Empty;
|
||||
public string ProviderName
|
||||
{
|
||||
get { return providerName; }
|
||||
set { providerName = value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const string ENUMERATOR_FIELD_IDENTITY = "Identity";
|
||||
private const string ENUMERATOR_FIELD_PROVIDER_NAME = "ProviderName";
|
||||
|
||||
#region Constructor
|
||||
private CDataContainer context = null;
|
||||
private CDataContainer Context { get { return context; } set { context = value; } }
|
||||
public CredentialData(CDataContainer ctxt)
|
||||
{
|
||||
this.Context = ctxt;
|
||||
LoadDataFromXmlContext();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Implementation: LoadDataFromXmlContext(), LoadDataFromServer(), SendDataToServer()
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
LoadDataFromXmlContext();
|
||||
LoadDataFromServer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LoadDataFromXmlContext
|
||||
///
|
||||
/// loads context information from xml - e.g. name of object
|
||||
/// </summary>
|
||||
private void LoadDataFromXmlContext()
|
||||
{
|
||||
this.CredentialName = this.Context.GetDocumentPropertyString("credential");
|
||||
this.isPropertiesMode = (this.CredentialName != null) && (this.CredentialName.Length > 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LoadDataFromServer
|
||||
///
|
||||
/// talks with enumerator an retrieves info that is not available in the xml context but on server
|
||||
/// </summary>
|
||||
private void LoadDataFromServer()
|
||||
{
|
||||
if (this.IsPropertiesMode == true)
|
||||
{
|
||||
bool isKatmaiAndNotMatrix = (this.context.Server.Version.Major >= 10);
|
||||
|
||||
Urn urn = new Urn("Server/Credential[@Name='" + Urn.EscapeString(this.CredentialName) + "']");
|
||||
string [] fields;
|
||||
if (isKatmaiAndNotMatrix)
|
||||
{
|
||||
fields = new string[] { ENUMERATOR_FIELD_IDENTITY, ENUMERATOR_FIELD_PROVIDER_NAME };
|
||||
}
|
||||
else
|
||||
{
|
||||
fields = new string[] { ENUMERATOR_FIELD_IDENTITY };
|
||||
}
|
||||
Request r = new Request(urn, fields);
|
||||
System.Data.DataTable dataTable = Enumerator.GetData(this.Context.ConnectionInfo, r);
|
||||
|
||||
if (dataTable.Rows.Count == 0)
|
||||
{
|
||||
throw new Exception("SRError.CredentialNoLongerExists");
|
||||
}
|
||||
|
||||
System.Data.DataRow dataRow = dataTable.Rows[0];
|
||||
this.CredentialIdentity = Convert.ToString(dataRow[ENUMERATOR_FIELD_IDENTITY], System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
if (isKatmaiAndNotMatrix)
|
||||
{
|
||||
this.providerName = Convert.ToString(dataRow[ENUMERATOR_FIELD_PROVIDER_NAME], System.Globalization.CultureInfo.InvariantCulture);
|
||||
this.isEncryptionByProvider = !string.IsNullOrEmpty(providerName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.CredentialName = string.Empty;
|
||||
this.CredentialIdentity = string.Empty;
|
||||
this.providerName = string.Empty;
|
||||
this.isEncryptionByProvider = false;
|
||||
}
|
||||
|
||||
this.SecurePassword = new SecureString();
|
||||
this.SecurePasswordConfirm = new SecureString();
|
||||
|
||||
this.PasswordWasChanged = false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SendDataToServer
|
||||
///
|
||||
/// here we talk with server via smo and do the actual data changing
|
||||
/// </summary>
|
||||
public void SendDataToServer()
|
||||
{
|
||||
if (this.IsPropertiesMode == true)
|
||||
{
|
||||
SendToServerAlterCredential();
|
||||
}
|
||||
else
|
||||
{
|
||||
SendToServerCreateCredential();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// create credential - create mode
|
||||
/// </summary>
|
||||
private void SendToServerCreateCredential()
|
||||
{
|
||||
Microsoft.SqlServer.Management.Smo.Credential smoCredential = new Microsoft.SqlServer.Management.Smo.Credential (
|
||||
this.Context.Server,
|
||||
this.CredentialName);
|
||||
if (this.isEncryptionByProvider)
|
||||
{
|
||||
smoCredential.MappedClassType = MappedClassType.CryptographicProvider;
|
||||
smoCredential.ProviderName = this.providerName;
|
||||
}
|
||||
smoCredential.Create(this.CredentialIdentity, this.SecurePassword.ToString());
|
||||
GC.Collect(); // this.SecurePassword.ToString() just created an immutable string that lives in memory
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// alter credential - properties mode
|
||||
/// </summary>
|
||||
private void SendToServerAlterCredential()
|
||||
{
|
||||
Microsoft.SqlServer.Management.Smo.Credential smoCredential = this.Context.Server.Credentials[this.CredentialName];
|
||||
|
||||
if (smoCredential != null)
|
||||
{
|
||||
if (this.PasswordWasChanged == false)
|
||||
{
|
||||
if (smoCredential.Identity != this.CredentialIdentity)
|
||||
{
|
||||
smoCredential.Alter(this.CredentialIdentity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
smoCredential.Alter(this.CredentialIdentity, this.SecurePassword.ToString());
|
||||
GC.Collect(); // this.SecurePassword.ToString() just created an immutable string that lives in memory
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("SRError.CredentialNoLongerExists");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.SecurePassword.Dispose();
|
||||
this.SecurePasswordConfirm.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
116
src/Microsoft.SqlTools.ServiceLayer/Security/SecurityService.cs
Normal file
116
src/Microsoft.SqlTools.ServiceLayer/Security/SecurityService.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
//
|
||||
// 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.Threading.Tasks;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
||||
using Microsoft.SqlTools.ServiceLayer.Security.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Main class for Security Service functionality
|
||||
/// </summary>
|
||||
public sealed class SecurityService : IDisposable
|
||||
{
|
||||
private bool disposed;
|
||||
|
||||
private ConnectionService connectionService = null;
|
||||
|
||||
private static readonly Lazy<SecurityService> instance = new Lazy<SecurityService>(() => new SecurityService());
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new SecurityService instance with default parameters
|
||||
/// </summary>
|
||||
public SecurityService()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the singleton instance object
|
||||
/// </summary>
|
||||
public static SecurityService Instance
|
||||
{
|
||||
get { return instance.Value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal for testing purposes only
|
||||
/// </summary>
|
||||
internal ConnectionService ConnectionServiceInstance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (connectionService == null)
|
||||
{
|
||||
connectionService = ConnectionService.Instance;
|
||||
}
|
||||
return connectionService;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
connectionService = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Service host object for sending/receiving requests/events.
|
||||
/// Internal for testing purposes.
|
||||
/// </summary>
|
||||
internal IProtocolEndpoint ServiceHost
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Security Service instance
|
||||
/// </summary>
|
||||
public void InitializeService(ServiceHost serviceHost)
|
||||
{
|
||||
this.ServiceHost = serviceHost;
|
||||
this.ServiceHost.SetRequestHandler(CreateCredentialRequest.Type, HandleCreateCredentialRequest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle request to create a credential
|
||||
/// </summary>
|
||||
internal async Task HandleCreateCredentialRequest(CreateCredentialParams parameters, RequestContext<CreateCredentialResult> requestContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = new CreateCredentialResult();
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri,
|
||||
out connInfo);
|
||||
|
||||
CDataContainer dataContainer = AdminService.CreateDataContainer(connInfo, databaseExists: true);
|
||||
Credential credential = new Credential(dataContainer);
|
||||
|
||||
await requestContext.SendResult(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the service
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/Microsoft.SqlTools.ServiceLayer/Utility/ReturnResult.cs
Normal file
15
src/Microsoft.SqlTools.ServiceLayer/Utility/ReturnResult.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
{
|
||||
public class ReturnResult
|
||||
{
|
||||
public bool Succeeded { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// 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.SqlClient;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.XEvent;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Profiler;
|
||||
using Microsoft.SqlTools.ServiceLayer.Profiler.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Agent
|
||||
{
|
||||
public class AgentAlertTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Verify default agent/alerts handlers
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task TestHandleAgentAlertsRequest()
|
||||
{
|
||||
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||
{
|
||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||
|
||||
var requestParams = new AgentAlertsParams()
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri
|
||||
};
|
||||
|
||||
var requestContext = new Mock<RequestContext<AgentAlertsResult>>();
|
||||
|
||||
AgentService service = new AgentService();
|
||||
await service.HandleAgentAlertsRequest(requestParams, requestContext.Object);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify the default "create agent alert" request handler with valid parameters
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task TestHandleCreateAgentAlertsRequest()
|
||||
{
|
||||
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||
{
|
||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||
|
||||
var requestParams = new CreateAgentAlertParams
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
Alert = new AgentAlertInfo()
|
||||
{
|
||||
JobName = "Test Job Name"
|
||||
}
|
||||
};
|
||||
|
||||
var requestContext = new Mock<RequestContext<CreateAgentAlertResult>>();
|
||||
|
||||
AgentService service = new AgentService();
|
||||
await service.HandleCreateAgentAlertRequest(requestParams, requestContext.Object);
|
||||
|
||||
// var agentAlerts = await AgentTestUtils.GetAgentAlerts(connectionResult.ConnectionInfo.OwnerUri);
|
||||
// if (agentAlerts != null && agentAlerts.Length > 0)
|
||||
// {
|
||||
// foreach (var agentAlert in agentAlerts)
|
||||
// {
|
||||
// if (agentAlert.JobName.Equals(alert.JobName))
|
||||
// {
|
||||
// await service.HandleDeleteAgentAlertRequest(new DeleteAgentAlertParams()
|
||||
// {
|
||||
// OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
// Alert = alert
|
||||
// }, deleteContext.Object);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify the default "update agent alert" request handler with valid parameters
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task TestHandleUpdateAgentAlertsRequest()
|
||||
{
|
||||
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||
{
|
||||
var createContext = new Mock<RequestContext<CreateAgentAlertResult>>();
|
||||
var updateContext = new Mock<RequestContext<UpdateAgentAlertResult>>();
|
||||
var deleteContext = new Mock<RequestContext<DeleteAgentAlertResult>>();
|
||||
|
||||
var service = new AgentService();
|
||||
var alert = new AgentAlertInfo()
|
||||
{
|
||||
JobName = "test_update_job",
|
||||
AlertType = AlertType.SqlServerEvent,
|
||||
Severity = 1
|
||||
};
|
||||
|
||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||
await service.HandleDeleteAgentAlertRequest(new DeleteAgentAlertParams()
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
Alert = alert
|
||||
}, deleteContext.Object);
|
||||
|
||||
await service.HandleCreateAgentAlertRequest(new CreateAgentAlertParams
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
Alert = alert
|
||||
}, createContext.Object);
|
||||
|
||||
await service.HandleUpdateAgentAlertRequest(new UpdateAgentAlertParams()
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
Alert = alert
|
||||
}, updateContext.Object);
|
||||
|
||||
await service.HandleDeleteAgentAlertRequest(new DeleteAgentAlertParams()
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
Alert = alert
|
||||
}, deleteContext.Object);
|
||||
|
||||
createContext.VerifyAll();
|
||||
updateContext.VerifyAll();
|
||||
deleteContext.VerifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Agent
|
||||
{
|
||||
public class AgentOperatorTests
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Verify the default "update agent alert" request handler with valid parameters
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task TestHandleUpdateAgentOperatorRequest()
|
||||
{
|
||||
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||
{
|
||||
var createContext = new Mock<RequestContext<CreateAgentOperatorResult>>();
|
||||
|
||||
var service = new AgentService();
|
||||
var operatorInfo = new AgentOperatorInfo()
|
||||
{
|
||||
Id = 10,
|
||||
Name = "Joe DBA",
|
||||
EmailAddress = "test@aol.com"
|
||||
};
|
||||
|
||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||
|
||||
await service.HandleCreateAgentOperatorRequest(new CreateAgentOperatorParams
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
Operator = operatorInfo
|
||||
}, createContext.Object);
|
||||
|
||||
createContext.VerifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Agent
|
||||
{
|
||||
public class AgentProxyTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Verify the default "update agent alert" request handler with valid parameters
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task TestHandleUpdateAgentProxyRequest()
|
||||
{
|
||||
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||
{
|
||||
var createContext = new Mock<RequestContext<CreateAgentProxyResult>>();
|
||||
var updateContext = new Mock<RequestContext<UpdateAgentProxyResult>>();
|
||||
var deleteContext = new Mock<RequestContext<DeleteAgentProxyResult>>();
|
||||
|
||||
var service = new AgentService();
|
||||
var proxy = new AgentProxyInfo()
|
||||
{
|
||||
Id = 10,
|
||||
AccountName = "Test Proxy 2",
|
||||
CredentialName = "User",
|
||||
Description = "",
|
||||
IsEnabled = true
|
||||
};
|
||||
|
||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||
await service.HandleDeleteAgentProxyRequest(new DeleteAgentProxyParams()
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
Proxy = proxy
|
||||
}, deleteContext.Object);
|
||||
|
||||
deleteContext.VerifyAll();
|
||||
|
||||
await service.HandleCreateAgentProxyRequest(new CreateAgentProxyParams
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
Proxy = proxy
|
||||
}, createContext.Object);
|
||||
|
||||
createContext.VerifyAll();
|
||||
|
||||
string originalProxyName = proxy.AccountName;
|
||||
proxy.AccountName = proxy.AccountName + " Updated";
|
||||
await service.HandleUpdateAgentProxyRequest(new UpdateAgentProxyParams()
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
OriginalProxyName = originalProxyName,
|
||||
Proxy = proxy
|
||||
}, updateContext.Object);
|
||||
|
||||
updateContext.VerifyAll();
|
||||
|
||||
await service.HandleDeleteAgentProxyRequest(new DeleteAgentProxyParams()
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
Proxy = proxy
|
||||
}, deleteContext.Object);
|
||||
|
||||
deleteContext.VerifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Agent
|
||||
AgentService service = new AgentService();
|
||||
await service.HandleAgentJobsRequest(requestParams, requestContext.Object);
|
||||
requestContext.VerifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent;
|
||||
using Microsoft.SqlTools.ServiceLayer.Agent.Contracts;
|
||||
using Moq;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Agent
|
||||
{
|
||||
public static class AgentTestUtils
|
||||
{
|
||||
internal static async Task<AgentAlertInfo[]> GetAgentAlerts(string connectionUri)
|
||||
{
|
||||
var requestParams = new AgentAlertsParams()
|
||||
{
|
||||
OwnerUri = connectionUri
|
||||
};
|
||||
|
||||
var requestContext = new Mock<RequestContext<AgentAlertsResult>>();
|
||||
|
||||
AgentAlertInfo[] agentAlerts = null;
|
||||
requestContext.Setup(x => x.SendResult(It.IsAny<AgentAlertsResult>()))
|
||||
.Callback<AgentAlertsResult>(r => agentAlerts = r.Alerts);
|
||||
|
||||
AgentService service = new AgentService();
|
||||
await service.HandleAgentAlertsRequest(requestParams, requestContext.Object);
|
||||
return agentAlerts;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Security;
|
||||
using Microsoft.SqlTools.ServiceLayer.Security.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Moq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using static Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility.LiveConnectionHelper;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests for the security service component
|
||||
/// </summary>
|
||||
public class SecuritygServiceTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Verify the script object request
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task TestHandleCreateCredentialRequest()
|
||||
{
|
||||
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||
{
|
||||
var createContext = new Mock<RequestContext<CreateCredentialResult>>();
|
||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||
|
||||
var service = new SecurityService();
|
||||
var credential = new CredentialInfo()
|
||||
{
|
||||
};
|
||||
|
||||
await service.HandleCreateCredentialRequest(new CreateCredentialParams
|
||||
{
|
||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||
Credential = credential
|
||||
}, createContext.Object);
|
||||
|
||||
createContext.VerifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user