support named instances and other props via jdbc uri syntax #48 [#158388528] (#49)

This commit is contained in:
Tim Hess 2019-04-01 12:05:23 -05:00 коммит произвёл GitHub
Родитель 921677f66a
Коммит 9885d34e58
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 125 добавлений и 19 удалений

Просмотреть файл

@ -13,6 +13,7 @@
// limitations under the License.
using Steeltoe.CloudFoundry.Connector.Services;
using System;
using System.Net;
namespace Steeltoe.CloudFoundry.Connector.SqlServer
@ -36,7 +37,35 @@ namespace Steeltoe.CloudFoundry.Connector.SqlServer
{
configuration.Port = si.Port;
configuration.Server = si.Host;
configuration.Database = si.Path.Replace("databaseName=", string.Empty);
if (!string.IsNullOrEmpty(si.Path))
{
configuration.Database = si.Path;
}
if (si.Query != null)
{
foreach (var piece in si.Query.Split('&'))
{
var kvp = piece.Split('=');
if (kvp[0].EndsWith("database", StringComparison.InvariantCultureIgnoreCase) || kvp[0].EndsWith("databaseName", StringComparison.InvariantCultureIgnoreCase))
{
configuration.Database = kvp[1];
}
else if (kvp[0].EndsWith("instancename", StringComparison.InvariantCultureIgnoreCase))
{
configuration.InstanceName = kvp[1];
}
else if (kvp[0].StartsWith("hostnameincertificate", StringComparison.InvariantCultureIgnoreCase))
{
// adding this key could result in "System.ArgumentException : Keyword not supported: 'hostnameincertificate'" later
}
else
{
configuration.Options.Add(kvp[0], kvp[1]);
}
}
}
if (configuration.UrlEncodedCredentials)
{
configuration.Username = WebUtility.UrlDecode(si.UserName);

Просмотреть файл

@ -14,6 +14,8 @@
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Steeltoe.CloudFoundry.Connector.SqlServer
@ -59,6 +61,11 @@ namespace Steeltoe.CloudFoundry.Connector.SqlServer
public string Server { get; set; } = Default_Server;
public string InstanceName { get; set; }
/// <summary>
/// Gets or sets the port SQL Server is listening on. To exclude from connection string, use a value less than 0
/// </summary>
public int Port { get; set; } = Default_Port;
public string Username { get; set; }
@ -83,6 +90,8 @@ namespace Steeltoe.CloudFoundry.Connector.SqlServer
/// <remarks>Default value is 15</remarks>
public int? Timeout { get; set; }
internal Dictionary<string, string> Options { get; set; } = new Dictionary<string, string>();
public override string ToString()
{
if (!string.IsNullOrEmpty(ConnectionString) && !cloudFoundryConfigFound)
@ -91,14 +100,41 @@ namespace Steeltoe.CloudFoundry.Connector.SqlServer
}
StringBuilder sb = new StringBuilder();
AddKeyValue(sb, "Data Source", $"{Server},{Port}");
AddDataSource(sb);
AddKeyValue(sb, "Initial Catalog", Database);
AddKeyValue(sb, "User Id", Username);
AddKeyValue(sb, "Password", Password);
AddKeyValue(sb, "Integrated Security", IntegratedSecurity);
AddKeyValue(sb, nameof(Timeout), Timeout);
if (Options != null && Options.Any())
{
foreach (var o in Options)
{
AddKeyValue(sb, o.Key, o.Value);
}
}
return sb.ToString();
}
private void AddDataSource(StringBuilder sb)
{
sb.Append("Data Source");
sb.Append(Default_Separator);
sb.Append(Server);
if (InstanceName != null)
{
sb.Append($"\\{InstanceName}");
}
if (Port > 0)
{
sb.Append($",{Port}");
}
sb.Append(Default_Terminator);
}
}
}

Просмотреть файл

@ -19,16 +19,12 @@ namespace Steeltoe.CloudFoundry.Connector.Services
public static readonly string[] SQLSERVER_SCHEME = { "sqlserver", "jdbc:sqlserver", "mssql" };
public SqlServerServiceInfo(string id, string url)
: base(id, url.Replace("jdbc:", string.Empty).Replace(';', '/'))
: base(id, url)
{
}
public SqlServerServiceInfo(string id, string url, string username, string password)
: base(
id,
url != null ? url.Replace("jdbc:", string.Empty) : string.Empty,
username,
password)
: base(id, url, username, password)
{
}
}

Просмотреть файл

@ -63,11 +63,6 @@ namespace Steeltoe.CloudFoundry.Connector.Services
}
else
{
if (url.Contains(";databaseName="))
{
url = url.Replace(";databaseName", "/databaseName");
}
return new SqlServerServiceInfo(id, url, username, password);
}
}

Просмотреть файл

@ -40,8 +40,6 @@ namespace Steeltoe.CloudFoundry.Connector.Services
public UriInfo(string uristring, bool urlEncodedCredentials = false)
{
this.UriString = uristring;
Uri uri = MakeUri(uristring);
if (uri != null)
{
@ -68,12 +66,12 @@ namespace Steeltoe.CloudFoundry.Connector.Services
Password = userinfo[1];
}
}
this.UriString = uristring;
}
public UriInfo(string uristring, string username, string password)
{
this.UriString = uristring;
Uri uri = MakeUri(uristring);
if (uri != null)
{
@ -90,6 +88,7 @@ namespace Steeltoe.CloudFoundry.Connector.Services
this.UserName = username;
this.Password = password;
this.UriString = uristring;
}
public string Scheme { get; internal protected set; }
@ -158,6 +157,11 @@ namespace Steeltoe.CloudFoundry.Connector.Services
{
try
{
if (uriString.StartsWith("jdbc") || uriString.Contains(";"))
{
ConvertJdbcToUri(ref uriString);
}
return new Uri(uriString);
}
catch (Exception)
@ -166,7 +170,7 @@ namespace Steeltoe.CloudFoundry.Connector.Services
if (uriString.Contains(","))
{
// Slide past the protocol
var splitUri = UriString.Split('/');
var splitUri = uriString.Split('/');
// get the host list (and maybe credentials)
// -- pre-emptively set it as the Host property rather than a local variable
@ -187,6 +191,35 @@ namespace Steeltoe.CloudFoundry.Connector.Services
}
}
protected internal void ConvertJdbcToUri(ref string uriString)
{
uriString = uriString.Replace("jdbc:", string.Empty).Replace(";", "&");
if (!uriString.Contains("?"))
{
var firstAmp = uriString.IndexOf("&");
// If there is an equals sign before any ampersands, it is likely a key was included for the db name.
// Make the database name part of the path rather than query string if possible
var firstEquals = uriString.IndexOf("=");
if (firstEquals > 0 && (firstEquals < firstAmp || firstAmp == -1))
{
var dbnameindex = uriString.IndexOf("databasename=", StringComparison.InvariantCultureIgnoreCase);
if (dbnameindex > 0)
{
uriString = uriString.Remove(dbnameindex, 13);
// recalculate the location of the first '&'
firstAmp = uriString.IndexOf("&");
}
}
if (firstAmp > 0)
{
uriString = uriString.Substring(0, firstAmp) + questionMark[0] + uriString.Substring(firstAmp + 1, uriString.Length - firstAmp - 1);
}
}
}
protected internal string GetPath(string pathAndQuery)
{
if (string.IsNullOrEmpty(pathAndQuery))

Просмотреть файл

@ -116,5 +116,22 @@ namespace Steeltoe.CloudFoundry.Connector.SqlServer.Test
Assert.Contains("User Id=Dd6O1BPXUHdrmzbP;", opts);
Assert.Contains("Password=7E1LxXnlH2hhlPVt;", opts);
}
[Fact]
public void Configure_With_ServiceInfo_NamedInstance_Overrides_Config()
{
SqlServerProviderConfigurer configurer = new SqlServerProviderConfigurer();
// override provided by environment
SqlServerServiceInfo si = new SqlServerServiceInfo("MyId", "jdbc:sqlserver://servername/databaseName=de5aa3a747c134b3d8780f8cc80be519e;instanceName=someInstance;integratedSecurity=true");
// apply override
var opts = configurer.Configure(si, config);
// resulting options should contain values parsed from environment
Assert.Contains("Data Source=servername\\someInstance", opts);
Assert.Contains("Initial Catalog=de5aa3a747c134b3d8780f8cc80be519e;", opts);
Assert.Contains("integratedSecurity=true;", opts);
}
}
}

Просмотреть файл

@ -30,7 +30,7 @@ namespace Steeltoe.CloudFoundry.Connector.Services.Test
Assert.Equal(1433, r1.Port);
Assert.Equal("7E1LxXnlH2hhlPVt", r1.Password);
Assert.Equal("Dd6O1BPXUHdrmzbP", r1.UserName);
Assert.Equal("databaseName=de5aa3a747c134b3d8780f8cc80be519e", r1.Path);
Assert.Equal("de5aa3a747c134b3d8780f8cc80be519e", r1.Path);
}
}
}