// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // #nullable disable using Microsoft.SqlServer.Management.Common; using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlTools.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Hosting; using Microsoft.SqlTools.ServiceLayer.ServerConfigurations.Contracts; using Microsoft.SqlTools.Utility; using System; using System.Collections.Generic; using System.Threading.Tasks; namespace Microsoft.SqlTools.ServiceLayer.ServerConfigurations { public class ServerConfigService { private ConnectionService connectionService = null; private static readonly Lazy instance = new Lazy(() => new ServerConfigService()); public readonly int MaxServerMemoryPropertyNumber = 1544; public readonly int MinServerMemoryPropertyNumber = 1543; /// /// Gets the singleton instance object /// public static ServerConfigService Instance { get { return instance.Value; } } /// /// Internal for testing purposes only /// internal ConnectionService ConnectionServiceInstance { get { connectionService ??= ConnectionService.Instance; return connectionService; } set { connectionService = value; } } public void InitializeService(ServiceHost serviceHost) { serviceHost.SetRequestHandler(ServerConfigViewRequest.Type, this.HandleServerConfigViewRequest, true); serviceHost.SetRequestHandler(ServerConfigUpdateRequest.Type, this.HandleServerConfigUpdateRequest, true); serviceHost.SetRequestHandler(ServerConfigListRequest.Type, this.HandleServerConfigListRequest, true); } /// /// Handles config view request /// /// Request parameters /// Request Context /// public async Task HandleServerConfigViewRequest(ServerConfigViewRequestParams parameters, RequestContext requestContext) { Logger.Verbose("HandleServerConfigViewRequest"); ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); if (connInfo == null) { await requestContext.SendError(new Exception(SR.ProfilerConnectionNotFound)); } else { var serverConnection = ConnectionService.OpenServerConnection(connInfo); ServerConfigProperty serverConfig = GetConfig(serverConnection, parameters.ConfigNumber); await requestContext.SendResult(new ServerConfigViewResponseParams { ConfigProperty = serverConfig }); } } /// /// Handles config update request /// /// Request parameters /// Request Context /// public async Task HandleServerConfigUpdateRequest(ServerConfigUpdateRequestParams parameters, RequestContext requestContext) { Logger.Verbose("HandleServerConfigUpdateRequest"); ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); ServerConfigUpdateResponseParams response = new ServerConfigUpdateResponseParams { }; if (connInfo == null) { await requestContext.SendError(new Exception(SR.ProfilerConnectionNotFound)); } else { var serverConnection = ConnectionService.OpenServerConnection(connInfo); UpdateConfig(serverConnection, parameters.ConfigNumber, parameters.ConfigValue); response.ConfigProperty = GetConfig(serverConnection, parameters.ConfigNumber); await requestContext.SendResult(response); } } /// /// Handles config list request /// /// Request parameters /// Request Context public async Task HandleServerConfigListRequest(ServerConfigListRequestParams parameters, RequestContext requestContext) { Logger.Verbose("HandleServerConfigListRequest"); ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); ServerConfigListResponseParams response = new ServerConfigListResponseParams { }; if (connInfo == null) { await requestContext.SendError(new Exception(SR.ProfilerConnectionNotFound)); } else { var serverConnection = ConnectionService.OpenServerConnection(connInfo); response.ConfigProperties = GetConfigs(serverConnection); await requestContext.SendResult(response); } } /// /// Updates external script in a given server. Throws exception if server doesn't support external script /// /// /// public void UpdateConfig(ServerConnection serverConnection, int configNumber, int configValue) { Server server = new Server(serverConnection); ConfigProperty serverConfig = GetServerSmoConfig(server, configNumber); if (serverConfig != null) { try { serverConfig.ConfigValue = configValue; server.Configuration.Alter(true); } catch (FailedOperationException ex) { throw new ServerConfigException($"Failed to update config. config number: ${configNumber}", ex); } } else { throw new ServerConfigException($"Server doesn't have config. config number: ${configNumber}"); } } /// /// Returns current value of external script config /// /// /// private ServerConfigProperty GetConfig(ServerConnection serverConnection, int configNumber) { Server server = new Server(serverConnection); ConfigProperty serverConfig = GetServerSmoConfig(server, configNumber); return serverConfig != null ? ServerConfigProperty.ToServerConfigProperty(serverConfig) : null; } private List GetConfigs(ServerConnection serverConnection) { Server server = new Server(serverConnection); List list = new List(); foreach (ConfigProperty serverConfig in server.Configuration.Properties) { list.Add(serverConfig != null ? ServerConfigProperty.ToServerConfigProperty(serverConfig) : null); } return list; } public ConfigProperty GetServerSmoConfig(Server server, int configNumber) { try { ConfigProperty serverConfig = null; foreach (ConfigProperty configProperty in server.Configuration.Properties) { if (configProperty.Number == configNumber) { serverConfig = configProperty; break; } } return serverConfig; } catch (Exception ex) { throw new ServerConfigException($"Failed to get config. config number: ${configNumber}", ex); } } } }