diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionInfo.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionInfo.cs
index 78fe4154..b9e26081 100644
--- a/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionInfo.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionInfo.cs
@@ -161,6 +161,11 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
public void UpdateAzureToken(string token)
{
ConnectionDetails.AzureAccountToken = token;
+
+ foreach (var connection in _connectionTypeToConnectionMap.Values)
+ {
+ connection.UpdateAzureToken(token);
+ }
}
}
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionService.cs
index 22877353..42044a69 100644
--- a/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionService.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionService.cs
@@ -6,7 +6,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -268,23 +267,22 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
return completeParams;
}
- internal void RefreshAzureToken(string ownerUri)
+ internal string RefreshAzureToken(string ownerUri)
{
- ConnectionInfo existingConnection = OwnerToConnectionMap[ownerUri];
-
+ TryFindConnection(ownerUri, out ConnectionInfo connection);
+
var requestMessage = new RequestSecurityTokenParams
{
- AccountId = existingConnection.ConnectionDetails.GetOptionValue("azureAccount", string.Empty),
- Authority = existingConnection.ConnectionDetails.GetOptionValue("azureTenantId", string.Empty),
+ AccountId = connection.ConnectionDetails.GetOptionValue("azureAccount", string.Empty),
+ Authority = connection.ConnectionDetails.GetOptionValue("azureTenantId", string.Empty),
Provider = "Azure",
Resource = "SQL"
};
var response = Instance.ServiceHost.SendRequest(SecurityTokenRequest.Type, requestMessage, true).Result;
- existingConnection.UpdateAzureToken(response.Token);
-
- existingConnection.TryGetConnection(ConnectionType.Query, out var reliableDataSourceConnection);
- reliableDataSourceConnection.GetUnderlyingConnection().UpdateAzureToken(response.Token);
+ connection.UpdateAzureToken(response.Token);
+
+ return response.Token;
}
private void TryCloseConnectionTemporaryConnection(ConnectParams connectionParams, ConnectionInfo connectionInfo)
@@ -452,7 +450,7 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
string connectionString = BuildConnectionString(connectionInfo.ConnectionDetails);
// create a sql connection instance
- connection = connectionInfo.Factory.CreateDataSourceConnection(connectionString, connectionInfo.ConnectionDetails.AzureAccountToken);
+ connection = connectionInfo.Factory.CreateDataSourceConnection(connectionString, connectionInfo.ConnectionDetails.AzureAccountToken, connectionInfo.OwnerUri);
connectionInfo.AddConnection(connectionParams.Type, connection);
// Add a cancellation token source so that the connection OpenAsync() can be cancelled
@@ -786,9 +784,10 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
{
throw new Exception(SR.ConnectionServiceListDbErrorNotConnected(owner));
}
- ConnectionDetails connectionDetails = info.ConnectionDetails.Clone();
- IDataSource dataSource = OpenDataSourceConnection(info);
+ info.TryGetConnection(ConnectionType.Default, out ReliableDataSourceConnection connection);
+ IDataSource dataSource = connection.GetUnderlyingConnection();
+
DataSourceObjectMetadata objectMetadata = MetadataFactory.CreateClusterMetadata(info.ConnectionDetails.ServerName);
ListDatabasesResponse response = new ListDatabasesResponse();
@@ -813,7 +812,6 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
ServiceHost = serviceHost;
_dataSourceConnectionFactory = dataSourceConnectionFactory;
_dataSourceFactory = dataSourceFactory;
-
connectedQueues.AddOrUpdate("Default", connectedBindingQueue, (key, old) => connectedBindingQueue);
LockedDatabaseManager.ConnectionService = this;
@@ -1262,7 +1260,7 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
string connectionString = BuildConnectionString(info.ConnectionDetails);
// create a sql connection instance
- ReliableDataSourceConnection connection = info.Factory.CreateDataSourceConnection(connectionString, info.ConnectionDetails.AzureAccountToken);
+ ReliableDataSourceConnection connection = info.Factory.CreateDataSourceConnection(connectionString, info.ConnectionDetails.AzureAccountToken, ownerUri);
connection.Open();
info.AddConnection(key, connection);
}
@@ -1358,35 +1356,6 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
}
}
- ///
- /// Create and open a new SqlConnection from a ConnectionInfo object
- /// Note: we need to audit all uses of this method to determine why we're
- /// bypassing normal ConnectionService connection management
- ///
- /// The connection info to connect with
- /// A plaintext string that will be included in the application name for the connection
- /// A SqlConnection created with the given connection info
- private IDataSource OpenDataSourceConnection(ConnectionInfo connInfo, string featureName = null)
- {
- try
- {
- // generate connection string
- string connectionString = BuildConnectionString(connInfo.ConnectionDetails);
-
- // TODOKusto: Pass in type of DataSource needed to make this generic. Hard coded to Kusto right now.
- return _dataSourceFactory.Create(DataSourceType.Kusto, connectionString, connInfo.ConnectionDetails.AzureAccountToken);
- }
- catch (Exception ex)
- {
- string error = string.Format(CultureInfo.InvariantCulture,
- "Failed opening a DataSource of type {0}: error:{1} inner:{2} stacktrace:{3}",
- DataSourceType.Kusto, ex.Message, ex.InnerException != null ? ex.InnerException.Message : string.Empty, ex.StackTrace);
- Logger.Write(TraceEventType.Error, error);
- }
-
- return null;
- }
-
public static void EnsureConnectionIsOpen(ReliableDataSourceConnection conn, bool forceReopen = false)
{
// verify that the connection is open
diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/DataSourceConnectionFactory.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/DataSourceConnectionFactory.cs
index 567a70ce..b18e7228 100644
--- a/src/Microsoft.Kusto.ServiceLayer/Connection/DataSourceConnectionFactory.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/Connection/DataSourceConnectionFactory.cs
@@ -28,11 +28,11 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
///
/// Creates a new SqlConnection object
///
- public ReliableDataSourceConnection CreateDataSourceConnection(string connectionString, string azureAccountToken)
+ public ReliableDataSourceConnection CreateDataSourceConnection(string connectionString, string azureAccountToken, string ownerUri)
{
RetryPolicy connectionRetryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy();
RetryPolicy commandRetryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy();
- return new ReliableDataSourceConnection(connectionString, connectionRetryPolicy, commandRetryPolicy, azureAccountToken, _dataSourceFactory);
+ return new ReliableDataSourceConnection(connectionString, connectionRetryPolicy, commandRetryPolicy, azureAccountToken, _dataSourceFactory, ownerUri);
}
}
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/IDataSourceConnectionFactory.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/IDataSourceConnectionFactory.cs
index fbfd45b1..102779fa 100644
--- a/src/Microsoft.Kusto.ServiceLayer/Connection/IDataSourceConnectionFactory.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/Connection/IDataSourceConnectionFactory.cs
@@ -3,9 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-using System.Data.Common;
-
-namespace Microsoft.Kusto.ServiceLayer.Connection
+ namespace Microsoft.Kusto.ServiceLayer.Connection
{
///
/// Interface for the SQL Connection factory
@@ -15,6 +13,6 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
///
/// Create a new SQL Connection object
///
- ReliableDataSourceConnection CreateDataSourceConnection(string connectionString, string azureAccountToken);
+ ReliableDataSourceConnection CreateDataSourceConnection(string connectionString, string azureAccountToken, string ownerUri);
}
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs
index 6bd35bf7..adb9bcf6 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs
@@ -89,8 +89,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public abstract string GenerateExecuteFunctionScript(string functionName);
- public abstract void UpdateAzureToken(string azureToken);
-
///
public DataSourceType DataSourceType { get; protected set; }
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs
index 6ca18479..f6064b78 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs
@@ -13,7 +13,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
[Export(typeof(IDataSourceFactory))]
public class DataSourceFactory : IDataSourceFactory
{
- public IDataSource Create(DataSourceType dataSourceType, string connectionString, string azureAccountToken)
+ public IDataSource Create(DataSourceType dataSourceType, string connectionString, string azureAccountToken, string ownerUri)
{
ValidationUtils.IsArgumentNotNullOrWhiteSpace(connectionString, nameof(connectionString));
ValidationUtils.IsArgumentNotNullOrWhiteSpace(azureAccountToken, nameof(azureAccountToken));
@@ -22,7 +22,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
{
case DataSourceType.Kusto:
{
- var kustoClient = new KustoClient(connectionString, azureAccountToken);
+ var kustoClient = new KustoClient(connectionString, azureAccountToken, ownerUri);
return new KustoDataSource(kustoClient);
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Exceptions/DataSourceUnauthorizedException.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Exceptions/DataSourceUnauthorizedException.cs
deleted file mode 100644
index 51ef3fa2..00000000
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/Exceptions/DataSourceUnauthorizedException.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace Microsoft.Kusto.ServiceLayer.DataSource.Exceptions
-{
- public class DataSourceUnauthorizedException : Exception
- {
- public DataSourceUnauthorizedException(Exception ex) : base (ex.Message, ex)
- {
- }
- }
-}
\ No newline at end of file
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs
index 1979f430..7429016f 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs
@@ -111,11 +111,5 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
///
///
string GenerateExecuteFunctionScript(string functionName);
-
- ///
- /// Updates Azure Token
- ///
- ///
- void UpdateAzureToken(string azureToken);
}
}
\ No newline at end of file
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSourceFactory.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSourceFactory.cs
index 0b5b70a1..670239ac 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSourceFactory.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSourceFactory.cs
@@ -2,6 +2,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
{
public interface IDataSourceFactory
{
- IDataSource Create(DataSourceType dataSourceType, string connectionString, string azureAccountToken);
+ IDataSource Create(DataSourceType dataSourceType, string connectionString, string azureAccountToken, string ownerUri);
}
}
\ No newline at end of file
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/IKustoClient.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/IKustoClient.cs
index 861f6cf2..6f3fc22e 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/IKustoClient.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/IKustoClient.cs
@@ -17,9 +17,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
string DatabaseName { get; }
- void UpdateAzureToken(string azureAccountToken);
-
- IDataReader ExecuteQuery(string query, CancellationToken cancellationToken, string databaseName = null);
+ IDataReader ExecuteQuery(string query, CancellationToken cancellationToken, string databaseName = null, int retryCount = 1);
///
/// Executes a query or command against a kusto cluster and returns a sequence of result row instances.
@@ -37,7 +35,8 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
/// Executes a Kusto control command.
///
/// The command.
- void ExecuteControlCommand(string command);
+ ///
+ void ExecuteControlCommand(string command, int retryCount = 1);
void UpdateDatabase(string databaseName);
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs
index 9fa4b246..b72158fa 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs
@@ -14,14 +14,16 @@ using Kusto.Data.Net.Client;
using Kusto.Language;
using Kusto.Language.Editor;
using Microsoft.Data.SqlClient;
+using Microsoft.Kusto.ServiceLayer.Connection;
using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
-using Microsoft.Kusto.ServiceLayer.DataSource.Exceptions;
using Microsoft.Kusto.ServiceLayer.Utility;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
public class KustoClient : IKustoClient
{
+ private readonly string _ownerUri;
+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private ICslAdminProvider _kustoAdminProvider;
@@ -36,8 +38,9 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public string ClusterName { get; }
public string DatabaseName { get; private set; }
- public KustoClient(string connectionString, string azureAccountToken)
+ public KustoClient(string connectionString, string azureAccountToken, string ownerUri)
{
+ _ownerUri = ownerUri;
ClusterName = GetClusterName(connectionString);
var databaseName = new SqlConnectionStringBuilder(connectionString).InitialCatalog;
Initialize(ClusterName, databaseName, azureAccountToken);
@@ -75,8 +78,9 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
_kustoAdminProvider = KustoClientFactory.CreateCslAdminProvider(stringBuilder);
}
- public void UpdateAzureToken(string azureAccountToken)
+ private void RefreshAzureToken()
{
+ string azureAccountToken = ConnectionService.Instance.RefreshAzureToken(_ownerUri);
_kustoQueryProvider.Dispose();
_kustoAdminProvider.Dispose();
Initialize(ClusterName, DatabaseName, azureAccountToken);
@@ -162,7 +166,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
}
}
- public IDataReader ExecuteQuery(string query, CancellationToken cancellationToken, string databaseName = null)
+ public IDataReader ExecuteQuery(string query, CancellationToken cancellationToken, string databaseName = null, int retryCount = 1)
{
ValidationUtils.IsArgumentNotNullOrWhiteSpace(query, nameof(query));
@@ -175,29 +179,33 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
var script = CodeScript.From(query, GlobalState.Default);
IDataReader[] origReaders = new IDataReader[script.Blocks.Count];
-
- Parallel.ForEach(script.Blocks, (codeBlock, state, index) =>
+ try
{
- var minimalQuery = codeBlock.Service.GetMinimalText(MinimalTextKind.RemoveLeadingWhitespaceAndComments);
-
- try
+ Parallel.ForEach(script.Blocks, (codeBlock, state, index) =>
{
+ var minimalQuery =
+ codeBlock.Service.GetMinimalText(MinimalTextKind.RemoveLeadingWhitespaceAndComments);
IDataReader origReader = _kustoQueryProvider.ExecuteQuery(
KustoQueryUtils.IsClusterLevelQuery(minimalQuery) ? "" : databaseName,
minimalQuery,
clientRequestProperties);
-
+
origReaders[index] = origReader;
- }
- catch (KustoRequestException exception) when (exception.FailureCode == 401) // Unauthorized
- {
- throw new DataSourceUnauthorizedException(exception);
- }
- });
-
- return new KustoResultsReader(origReaders);
+ });
+
+ return new KustoResultsReader(origReaders);
+ }
+ catch (AggregateException exception)
+ when (retryCount > 0 &&
+ exception.InnerException is KustoRequestException innerException
+ && innerException.FailureCode == 401) // Unauthorized
+ {
+ RefreshAzureToken();
+ retryCount--;
+ return ExecuteQuery(query, cancellationToken, databaseName, retryCount);
+ }
}
-
+
///
/// Executes a query or command against a kusto cluster and returns a sequence of result row instances.
///
@@ -211,10 +219,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
var tableReader = results[WellKnownDataSet.PrimaryResult].Single().TableData.CreateDataReader();
return new ObjectReader(tableReader);
}
- catch (DataSourceUnauthorizedException)
- {
- throw;
- }
catch (Exception) when (!throwOnError)
{
return null;
@@ -243,12 +247,22 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
/// Executes a Kusto control command.
///
/// The command.
- public void ExecuteControlCommand(string command)
+ ///
+ public void ExecuteControlCommand(string command, int retryCount = 1)
{
ValidationUtils.IsArgumentNotNullOrWhiteSpace(command, nameof(command));
- using (var adminOutput = _kustoAdminProvider.ExecuteControlCommand(command, null))
+ try
{
+ using (var adminOutput = _kustoAdminProvider.ExecuteControlCommand(command, null))
+ {
+ }
+ }
+ catch (KustoRequestException exception) when (retryCount > 0 && exception.FailureCode == 401) // Unauthorized
+ {
+ RefreshAzureToken();
+ retryCount--;
+ ExecuteControlCommand(command, retryCount);
}
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs
index a958121a..6366b3f8 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs
@@ -796,10 +796,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
return string.IsNullOrWhiteSpace(objectName) ? databaseName : $"{databaseName}.{objectName}";
}
- public override void UpdateAzureToken(string azureToken)
- {
- _kustoClient.UpdateAzureToken(azureToken);
- }
#endregion
}
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/ReliableDataSourceConnection.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/ReliableDataSourceConnection.cs
index b0c30c0c..a59955b1 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/ReliableDataSourceConnection.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/ReliableDataSourceConnection.cs
@@ -42,8 +42,9 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
private readonly Guid _azureSessionId = Guid.NewGuid();
private readonly string _connectionString;
- private readonly string _azureAccountToken;
+ private string _azureAccountToken;
private readonly IDataSourceFactory _dataSourceFactory;
+ private readonly string _ownerUri;
///
/// Initializes a new instance of the ReliableKustoClient class with a given connection string
@@ -55,13 +56,15 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
/// The retry policy defining whether to retry a request if a command fails to be executed.
///
///
+ ///
public ReliableDataSourceConnection(string connectionString, RetryPolicy connectionRetryPolicy,
- RetryPolicy commandRetryPolicy, string azureAccountToken, IDataSourceFactory dataSourceFactory)
+ RetryPolicy commandRetryPolicy, string azureAccountToken, IDataSourceFactory dataSourceFactory, string ownerUri)
{
_connectionString = connectionString;
_azureAccountToken = azureAccountToken;
_dataSourceFactory = dataSourceFactory;
- _dataSource = dataSourceFactory.Create(DataSourceType.Kusto, connectionString, azureAccountToken);
+ _ownerUri = ownerUri;
+ _dataSource = dataSourceFactory.Create(DataSourceType.Kusto, connectionString, azureAccountToken, ownerUri);
_connectionRetryPolicy = connectionRetryPolicy ?? RetryPolicyFactory.CreateNoRetryPolicy();
_commandRetryPolicy = commandRetryPolicy ?? RetryPolicyFactory.CreateNoRetryPolicy();
@@ -190,7 +193,7 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
{
_connectionRetryPolicy.ExecuteAction(() =>
{
- _dataSource = _dataSourceFactory.Create(DataSourceType.Kusto, _connectionString, _azureAccountToken);
+ _dataSource = _dataSourceFactory.Create(DataSourceType.Kusto, _connectionString, _azureAccountToken, _ownerUri);
});
}
}
@@ -247,6 +250,11 @@ namespace Microsoft.Kusto.ServiceLayer.Connection
{
get { return _dataSource.DatabaseName; }
}
+
+ public void UpdateAzureToken(string token)
+ {
+ _azureAccountToken = token;
+ }
}
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs b/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs
index b9221b0c..165c8a16 100644
--- a/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs
@@ -12,7 +12,6 @@ using Microsoft.Kusto.ServiceLayer.Admin;
using Microsoft.Kusto.ServiceLayer.Metadata;
using Microsoft.Kusto.ServiceLayer.Connection;
using Microsoft.Kusto.ServiceLayer.DataSource;
-using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
using Microsoft.Kusto.ServiceLayer.LanguageServices;
using Microsoft.Kusto.ServiceLayer.QueryExecution;
using Microsoft.Kusto.ServiceLayer.Scripting;
@@ -91,7 +90,7 @@ namespace Microsoft.Kusto.ServiceLayer
QueryExecutionService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(QueryExecutionService.Instance);
- ScriptingService.Instance.InitializeService(serviceHost, scripter, dataSourceFactory);
+ ScriptingService.Instance.InitializeService(serviceHost, scripter, ConnectionService.Instance);
serviceProvider.RegisterSingleService(ScriptingService.Instance);
AdminService.Instance.InitializeService(serviceHost, ConnectionService.Instance);
diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingQueue.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingQueue.cs
index b0d0cfbc..5ea86e18 100644
--- a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingQueue.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingQueue.cs
@@ -98,7 +98,7 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
bindingContext.BindingLock.Reset();
string connectionString = ConnectionService.BuildConnectionString(connInfo.ConnectionDetails);
- bindingContext.DataSource = _dataSourceFactory.Create(DataSourceType.Kusto, connectionString, connInfo.ConnectionDetails.AzureAccountToken);
+ bindingContext.DataSource = _dataSourceFactory.Create(DataSourceType.Kusto, connectionString, connInfo.ConnectionDetails.AzureAccountToken, connInfo.OwnerUri);
bindingContext.BindingTimeout = DefaultBindingTimeout;
bindingContext.IsConnected = true;
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Batch.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Batch.cs
index f3557cf8..9950a28d 100644
--- a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Batch.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Batch.cs
@@ -15,7 +15,6 @@ using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts;
using Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage;
using Microsoft.SqlTools.Utility;
using System.Globalization;
-using Microsoft.Kusto.ServiceLayer.DataSource.Exceptions;
namespace Microsoft.Kusto.ServiceLayer.QueryExecution
{
@@ -66,8 +65,6 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
///
private readonly bool getFullColumnSchema;
- private int _retryCount;
-
#endregion
internal Batch(string batchText, SelectionData selection, int ordinalId,
@@ -88,7 +85,6 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
this.outputFileFactory = outputFileFactory;
specialAction = new SpecialAction();
BatchExecutionCount = executionCount > 0 ? executionCount : 1;
- _retryCount = 1;
this.getFullColumnSchema = getFullColumnSchema;
}
@@ -252,7 +248,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
public async Task Execute(ReliableDataSourceConnection conn, CancellationToken cancellationToken)
{
// Sanity check to make sure we haven't already run this batch
- if (HasExecuted && _retryCount < 0)
+ if (HasExecuted)
{
throw new InvalidOperationException("Batch has already executed.");
}
@@ -267,12 +263,6 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
{
await DoExecute(conn, cancellationToken);
}
- catch (DataSourceUnauthorizedException)
- {
- // Rerun the query once if unauthorized
- _retryCount--;
- throw;
- }
catch (TaskCanceledException)
{
// Cancellation isn't considered an error condition
diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Query.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Query.cs
index aaa2eadc..7ef881d0 100644
--- a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Query.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Query.cs
@@ -16,7 +16,6 @@ using Microsoft.SqlTools.Utility;
using Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode;
using System.Collections.Generic;
using System.Diagnostics;
-using Microsoft.Kusto.ServiceLayer.DataSource.Exceptions;
using Microsoft.Kusto.ServiceLayer.Utility;
namespace Microsoft.Kusto.ServiceLayer.QueryExecution
@@ -391,11 +390,6 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
await QueryCompleted(this);
}
}
- catch (DataSourceUnauthorizedException)
- {
- ConnectionService.Instance.RefreshAzureToken(editorConnection.OwnerUri);
- await ExecuteInternal();
- }
catch (Exception e)
{
HasErrored = true;
diff --git a/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptAsScriptingOperation.cs b/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptAsScriptingOperation.cs
index 3b54e1a1..d05689ba 100644
--- a/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptAsScriptingOperation.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptAsScriptingOperation.cs
@@ -24,20 +24,15 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
{
private readonly IScripter _scripter;
private static readonly Dictionary scriptCompatibilityMap = LoadScriptCompatibilityMap();
+ private string _serverName;
+ private string _databaseName;
- public ScriptAsScriptingOperation(ScriptingParams parameters, string azureAccountToken, IScripter scripter, IDataSourceFactory dataSourceFactory) : base(parameters, dataSourceFactory)
+ public ScriptAsScriptingOperation(ScriptingParams parameters, IScripter scripter, IDataSource datasource) :
+ base(parameters, datasource)
{
- DataSource = _dataSourceFactory.Create(DataSourceType.Kusto, this.Parameters.ConnectionString,
- azureAccountToken);
_scripter = scripter;
}
- internal IDataSource DataSource { get; set; }
-
- private string serverName;
- private string databaseName;
- private bool disconnectAtDispose = false;
-
public override void Execute()
{
try
@@ -49,7 +44,7 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
this.CancellationToken.ThrowIfCancellationRequested();
string resultScript = string.Empty;
- UrnCollection urns = CreateUrns(DataSource);
+ UrnCollection urns = CreateUrns(_dataSource);
ScriptingOptions options = new ScriptingOptions();
SetScriptBehavior(options);
ScriptAsOptions scriptAsOptions = new ScriptAsOptions(this.Parameters.ScriptOptions);
@@ -65,12 +60,12 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
switch (this.Parameters.Operation)
{
case ScriptingOperationType.Select:
- resultScript = GenerateScriptSelect(DataSource, urns);
+ resultScript = GenerateScriptSelect(_dataSource, urns);
break;
case ScriptingOperationType.Alter:
case ScriptingOperationType.Execute:
- resultScript = GenerateScriptForFunction(DataSource);
+ resultScript = GenerateScriptForFunction(_dataSource);
break;
}
@@ -118,13 +113,6 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
});
}
}
- finally
- {
- if (disconnectAtDispose && DataSource != null)
- {
- DataSource.Dispose();
- }
- }
}
private string GenerateScriptSelect(IDataSource dataSource, UrnCollection urns)
@@ -168,8 +156,8 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
{
IEnumerable selectedObjects = new List(this.Parameters.ScriptingObjects);
- serverName = dataSource.ClusterName;
- databaseName = new SqlConnectionStringBuilder(this.Parameters.ConnectionString).InitialCatalog;
+ _serverName = dataSource.ClusterName;
+ _databaseName = new SqlConnectionStringBuilder(this.Parameters.ConnectionString).InitialCatalog;
UrnCollection urnCollection = new UrnCollection();
foreach (var scriptingObject in selectedObjects)
{
@@ -178,7 +166,7 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
// TODO: get the default schema
scriptingObject.Schema = "dbo";
}
- urnCollection.Add(scriptingObject.ToUrn(serverName, databaseName));
+ urnCollection.Add(scriptingObject.ToUrn(_serverName, _databaseName));
}
return urnCollection;
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingScriptOperation.cs b/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingScriptOperation.cs
index 8b8b3aa3..78816351 100644
--- a/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingScriptOperation.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingScriptOperation.cs
@@ -20,18 +20,15 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
///
public sealed class ScriptingScriptOperation : SmoScriptingOperation
{
-
private int scriptedObjectCount = 0;
private int totalScriptedObjectCount = 0;
private int eventSequenceNumber = 1;
- private string azureAccessToken;
-
- public ScriptingScriptOperation(ScriptingParams parameters, string azureAccessToken, IDataSourceFactory dataSourceFactory) : base(parameters, dataSourceFactory)
+ public ScriptingScriptOperation(ScriptingParams parameters, IDataSource dataSource) : base(parameters, dataSource)
{
- this.azureAccessToken = azureAccessToken;
+
}
public override void Execute()
@@ -204,7 +201,7 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
selectedObjects.Count(),
string.Join(", ", selectedObjects)));
- string server = GetServerNameFromLiveInstance(this.Parameters.ConnectionString, this.azureAccessToken);
+ string server = GetServerNameFromLiveInstance();
string database = new SqlConnectionStringBuilder(this.Parameters.ConnectionString).InitialCatalog;
foreach (ScriptingObject scriptingObject in selectedObjects)
diff --git a/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingService.cs b/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingService.cs
index deffcc2e..2f73e4fc 100644
--- a/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingService.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingService.cs
@@ -10,7 +10,6 @@ using System.Threading.Tasks;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.Kusto.ServiceLayer.Connection;
-using Microsoft.Kusto.ServiceLayer.DataSource;
using Microsoft.Kusto.ServiceLayer.Scripting.Contracts;
using Microsoft.SqlTools.Utility;
using Microsoft.Kusto.ServiceLayer.Utility;
@@ -22,13 +21,11 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
///
public sealed class ScriptingService : IDisposable
{
- private const int ScriptingOperationTimeout = 60000;
-
private static readonly Lazy LazyInstance = new Lazy(() => new ScriptingService());
public static ScriptingService Instance => LazyInstance.Value;
- private static ConnectionService connectionService;
+ private static ConnectionService _connectionService;
private readonly Lazy> operations =
new Lazy>(() => new ConcurrentDictionary());
@@ -36,26 +33,6 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
private bool disposed;
private IScripter _scripter;
- private IDataSourceFactory _dataSourceFactory;
-
- ///
- /// Internal for testing purposes only
- ///
- internal static ConnectionService ConnectionServiceInstance
- {
- get
- {
- if (connectionService == null)
- {
- connectionService = ConnectionService.Instance;
- }
- return connectionService;
- }
- set
- {
- connectionService = value;
- }
- }
///
/// The collection of active operations
@@ -66,11 +43,13 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
/// Initializes the Scripting Service instance
///
///
- ///
- public void InitializeService(ServiceHost serviceHost, IScripter scripter, IDataSourceFactory dataSourceFactory)
+ ///
+ ///
+ public void InitializeService(ServiceHost serviceHost, IScripter scripter, ConnectionService connectionService)
{
_scripter = scripter;
- _dataSourceFactory = dataSourceFactory;
+ _connectionService = connectionService;
+
serviceHost.SetRequestHandler(ScriptingRequest.Type, this.HandleScriptExecuteRequest);
serviceHost.SetRequestHandler(ScriptingCancelRequest.Type, this.HandleScriptCancelRequest);
serviceHost.SetRequestHandler(ScriptingListObjectsRequest.Type, this.HandleListObjectsRequest);
@@ -108,22 +87,18 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
///
public async Task HandleScriptExecuteRequest(ScriptingParams parameters, RequestContext requestContext)
{
- SmoScriptingOperation operation = null;
-
try
{
// if a connection string wasn't provided as a parameter then
// use the owner uri property to lookup its associated ConnectionInfo
// and then build a connection string out of that
- ConnectionInfo connInfo = null;
- string accessToken = null;
if (parameters.ConnectionString == null)
{
- ScriptingService.ConnectionServiceInstance.TryFindConnection(parameters.OwnerUri, out connInfo);
+ ConnectionInfo connInfo;
+ _connectionService.TryFindConnection(parameters.OwnerUri, out connInfo);
if (connInfo != null)
{
parameters.ConnectionString = ConnectionService.BuildConnectionString(connInfo.ConnectionDetails);
- accessToken = connInfo.ConnectionDetails.AzureAccountToken;
}
else
{
@@ -131,13 +106,16 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
}
}
+ SmoScriptingOperation operation;
+ var datasource = _connectionService.GetOrOpenConnection(parameters.OwnerUri, ConnectionType.Default)
+ .Result.GetUnderlyingConnection();
if (!ShouldCreateScriptAsOperation(parameters))
{
- operation = new ScriptingScriptOperation(parameters, accessToken, _dataSourceFactory);
+ operation = new ScriptingScriptOperation(parameters, datasource);
}
else
{
- operation = new ScriptAsScriptingOperation(parameters, accessToken, _scripter, _dataSourceFactory);
+ operation = new ScriptAsScriptingOperation(parameters, _scripter, datasource);
}
operation.PlanNotification += (sender, e) => requestContext.SendEvent(ScriptingPlanNotificationEvent.Type, e).Wait();
diff --git a/src/Microsoft.Kusto.ServiceLayer/Scripting/SmoScriptingOperation.cs b/src/Microsoft.Kusto.ServiceLayer/Scripting/SmoScriptingOperation.cs
index 33108281..bbaf99f8 100644
--- a/src/Microsoft.Kusto.ServiceLayer/Scripting/SmoScriptingOperation.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/Scripting/SmoScriptingOperation.cs
@@ -20,14 +20,13 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
///
public abstract class SmoScriptingOperation : ScriptingOperation
{
- protected readonly IDataSourceFactory _dataSourceFactory;
+ protected readonly IDataSource _dataSource;
private bool _disposed;
- protected SmoScriptingOperation(ScriptingParams parameters, IDataSourceFactory dataSourceFactory)
+ protected SmoScriptingOperation(ScriptingParams parameters, IDataSource datasource)
{
- _dataSourceFactory = dataSourceFactory;
+ _dataSource = datasource;
Validate.IsNotNull("parameters", parameters);
-
this.Parameters = parameters;
}
@@ -73,17 +72,10 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
parameters.OperationId = this.OperationId;
}
- protected string GetServerNameFromLiveInstance(string connectionString, string azureAccessToken)
+ protected string GetServerNameFromLiveInstance()
{
- string serverName = string.Empty;
-
- using(var dataSource = _dataSourceFactory.Create(DataSourceType.Kusto, connectionString, azureAccessToken))
- {
- serverName = dataSource.ClusterName;
- }
-
- Logger.Write(TraceEventType.Verbose, string.Format("Resolved server name '{0}'", serverName));
- return serverName;
+ Logger.Write(TraceEventType.Verbose, string.Format("Resolved server name '{0}'", _dataSource.ClusterName));
+ return _dataSource.ClusterName;
}
protected void ValidateScriptDatabaseParams()
diff --git a/test/Microsoft.Kusto.ServiceLayer.UnitTests/Connection/ConnectionInfoTests.cs b/test/Microsoft.Kusto.ServiceLayer.UnitTests/Connection/ConnectionInfoTests.cs
index a1405c49..259ff89e 100644
--- a/test/Microsoft.Kusto.ServiceLayer.UnitTests/Connection/ConnectionInfoTests.cs
+++ b/test/Microsoft.Kusto.ServiceLayer.UnitTests/Connection/ConnectionInfoTests.cs
@@ -36,7 +36,7 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.Connection
var dataSourceFactoryMock = new Mock();
var reliableDataSource = new ReliableDataSourceConnection("", RetryPolicyFactory.NoRetryPolicy,
- RetryPolicyFactory.NoRetryPolicy, "", dataSourceFactoryMock.Object);
+ RetryPolicyFactory.NoRetryPolicy, "", dataSourceFactoryMock.Object, "");
connectionInfo.AddConnection("ConnectionType", reliableDataSource);
connectionInfo.TryGetConnection("ConnectionType", out var connection);
@@ -60,7 +60,7 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.Connection
var dataSourceFactoryMock = new Mock();
var reliableDataSource = new ReliableDataSourceConnection("", RetryPolicyFactory.NoRetryPolicy,
- RetryPolicyFactory.NoRetryPolicy, "", dataSourceFactoryMock.Object);
+ RetryPolicyFactory.NoRetryPolicy, "", dataSourceFactoryMock.Object, "");
connectionInfo.AddConnection("ConnectionType", reliableDataSource);
connectionInfo.RemoveConnection("ConnectionType");
@@ -77,7 +77,7 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.Connection
var dataSourceFactoryMock = new Mock();
var reliableDataSource = new ReliableDataSourceConnection("", RetryPolicyFactory.NoRetryPolicy,
- RetryPolicyFactory.NoRetryPolicy, "", dataSourceFactoryMock.Object);
+ RetryPolicyFactory.NoRetryPolicy, "", dataSourceFactoryMock.Object, "");
connectionInfo.AddConnection("ConnectionType", reliableDataSource);
connectionInfo.RemoveAllConnections();
diff --git a/test/Microsoft.Kusto.ServiceLayer.UnitTests/Connection/DataSourceConnectionFactoryTests.cs b/test/Microsoft.Kusto.ServiceLayer.UnitTests/Connection/DataSourceConnectionFactoryTests.cs
index 64ebab23..ec8db3e4 100644
--- a/test/Microsoft.Kusto.ServiceLayer.UnitTests/Connection/DataSourceConnectionFactoryTests.cs
+++ b/test/Microsoft.Kusto.ServiceLayer.UnitTests/Connection/DataSourceConnectionFactoryTests.cs
@@ -12,7 +12,7 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.Connection
{
var dataSourceFactoryMock = new Mock();
var connectionFactory = new DataSourceConnectionFactory(dataSourceFactoryMock.Object);
- var connection = connectionFactory.CreateDataSourceConnection("", "");
+ var connection = connectionFactory.CreateDataSourceConnection("", "", "");
Assert.IsNotNull(connection);
}
diff --git a/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceFactoryTests.cs b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceFactoryTests.cs
index 91db92bb..a488b3de 100644
--- a/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceFactoryTests.cs
+++ b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceFactoryTests.cs
@@ -19,7 +19,7 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.DataSource
{
var dataSourceFactory = new DataSourceFactory();
Assert.Throws(exceptionType,
- () => dataSourceFactory.Create(DataSourceType.None, connectionString, azureAccountToken));
+ () => dataSourceFactory.Create(DataSourceType.None, connectionString, azureAccountToken, ""));
}
[Test]
diff --git a/test/Microsoft.Kusto.ServiceLayer.UnitTests/LanguageServices/ConnectedBindingQueueTests.cs b/test/Microsoft.Kusto.ServiceLayer.UnitTests/LanguageServices/ConnectedBindingQueueTests.cs
index c484699e..f32485b3 100644
--- a/test/Microsoft.Kusto.ServiceLayer.UnitTests/LanguageServices/ConnectedBindingQueueTests.cs
+++ b/test/Microsoft.Kusto.ServiceLayer.UnitTests/LanguageServices/ConnectedBindingQueueTests.cs
@@ -97,7 +97,7 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.LanguageServices
var dataSourceFactory = new Mock();
var dataSourceMock = new Mock();
dataSourceFactory
- .Setup(x => x.Create(It.IsAny(), It.IsAny(), It.IsAny()))
+ .Setup(x => x.Create(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Returns(dataSourceMock.Object);
var connectedBindingQueue =