From cf3105e5bedfe764a7af5dd0d91e2bc3c82a3d64 Mon Sep 17 00:00:00 2001 From: Ivan Anselmi Date: Tue, 30 Nov 2021 09:28:48 +0100 Subject: [PATCH] MSSQL: Change regex to validate Provider connection string (#40248) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Change the regex to allow to specified other connection attribute for MSSQL connection like ApplicationIntent property * Docs update * docs update * some tests added * formatting * Change the regex to allow to specified other connection attribute for MSSQL connection like ApplicationIntent property * Docs update * docs update * some tests added * formatting * docs and formatting Co-authored-by: Zoltán Bedi --- docs/sources/datasources/mssql.md | 26 +++++----- pkg/tsdb/mssql/mssql.go | 2 +- pkg/tsdb/mssql/mssql_test.go | 80 +++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 14 deletions(-) diff --git a/docs/sources/datasources/mssql.md b/docs/sources/datasources/mssql.md index c17da7d81ce..89b04ec23ac 100644 --- a/docs/sources/datasources/mssql.md +++ b/docs/sources/datasources/mssql.md @@ -14,19 +14,19 @@ Grafana ships with a built-in Microsoft SQL Server (MS SQL) data source plugin t To access data source settings, hover your mouse over the **Configuration** (gear) icon, then click **Data Sources**, and then click the data source. -| Name | Description | -| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| `Name` | The data source name. This is how you refer to the data source in panels and queries. | -| `Default` | Default data source means that it will be pre-selected for new panels. | -| `Host` | The IP address/hostname and optional port of your MS SQL instance. If the port is omitted, the driver default will be used (0). | -| `Database` | Name of your MS SQL database. | -| `Authentication` | Authentication mode. Either using SQL Server Authentication or Windows Authentication (single sign on for Windows users). | -| `User` | Database user's login/username | -| `Password` | Database user's password | -| `Encrypt` | This option determines whether or to which extent a secure SSL TCP/IP connection will be negotiated with the server, default `false`. | -| `Max open` | The maximum number of open connections to the database, default `unlimited`. | -| `Max idle` | The maximum number of connections in the idle connection pool, default `2`. | -| `Max lifetime` | The maximum amount of time in seconds a connection may be reused, default `14400`/4 hours. | +| Name | Description | +| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Name` | The data source name. This is how you refer to the data source in panels and queries. | +| `Default` | Default data source means that it will be pre-selected for new panels. | +| `Host` | The IP address/hostname and optional port of your MS SQL instance. If you omit the port, then the driver default is used (0). You can specify multiple connection properties such as ApplicationIntent using ';' character to separate each property. | +| `Database` | Name of your MS SQL database. | +| `Authentication` | Authentication mode. Either using SQL Server Authentication or Windows Authentication (single sign on for Windows users). | +| `User` | Database user's login/username | +| `Password` | Database user's password | +| `Encrypt` | This option determines whether or to which extent a secure SSL TCP/IP connection will be negotiated with the server, default `false`. | +| `Max open` | The maximum number of open connections to the database, default `unlimited`. | +| `Max idle` | The maximum number of connections in the idle connection pool, default `2`. | +| `Max lifetime` | The maximum amount of time in seconds a connection may be reused, default `14400`/4 hours. | ### Min time interval diff --git a/pkg/tsdb/mssql/mssql.go b/pkg/tsdb/mssql/mssql.go index e2929611e40..654daf14559 100644 --- a/pkg/tsdb/mssql/mssql.go +++ b/pkg/tsdb/mssql/mssql.go @@ -114,7 +114,7 @@ func ParseURL(u string) (*url.URL, error) { logger.Debug("Parsing MSSQL URL", "url", u) // Recognize ODBC connection strings like host\instance:1234 - reODBC := regexp.MustCompile(`^[^\\:]+(?:\\[^:]+)?(?::\d+)?$`) + reODBC := regexp.MustCompile(`^[^\\:]+(?:\\[^:]+)?(?::\d+)?(?:;.+)?$`) var host string switch { case reODBC.MatchString(u): diff --git a/pkg/tsdb/mssql/mssql_test.go b/pkg/tsdb/mssql/mssql_test.go index 31ac7602d11..2be8574d11e 100644 --- a/pkg/tsdb/mssql/mssql_test.go +++ b/pkg/tsdb/mssql/mssql_test.go @@ -1331,6 +1331,86 @@ func TestGenerateConnectionString(t *testing.T) { }, expConnStr: "server=localhost;database=database;user id=user;password=;", }, + { + desc: "With instance name", + dataSource: sqleng.DataSourceInfo{ + URL: "localhost\\instance", + Database: "database", + User: "user", + JsonData: sqleng.JsonData{}, + }, + expConnStr: "server=localhost\\instance;database=database;user id=user;password=;", + }, + { + desc: "With instance name and port", + dataSource: sqleng.DataSourceInfo{ + URL: "localhost\\instance:333", + Database: "database", + User: "user", + JsonData: sqleng.JsonData{}, + }, + expConnStr: "server=localhost\\instance;database=database;user id=user;password=;port=333;", + }, + { + desc: "With instance name and ApplicationIntent", + dataSource: sqleng.DataSourceInfo{ + URL: "localhost\\instance;ApplicationIntent=ReadOnly", + Database: "database", + User: "user", + JsonData: sqleng.JsonData{}, + }, + expConnStr: "server=localhost\\instance;ApplicationIntent=ReadOnly;database=database;user id=user;password=;", + }, + { + desc: "With ApplicationIntent instance name and port", + dataSource: sqleng.DataSourceInfo{ + URL: "localhost\\instance:333;ApplicationIntent=ReadOnly", + Database: "database", + User: "user", + JsonData: sqleng.JsonData{}, + }, + expConnStr: "server=localhost\\instance;database=database;user id=user;password=;port=333;ApplicationIntent=ReadOnly;", + }, + { + desc: "With instance name", + dataSource: sqleng.DataSourceInfo{ + URL: "localhost\\instance", + Database: "database", + User: "user", + JsonData: sqleng.JsonData{}, + }, + expConnStr: "server=localhost\\instance;database=database;user id=user;password=;", + }, + { + desc: "With instance name and port", + dataSource: sqleng.DataSourceInfo{ + URL: "localhost\\instance:333", + Database: "database", + User: "user", + JsonData: sqleng.JsonData{}, + }, + expConnStr: "server=localhost\\instance;database=database;user id=user;password=;port=333;", + }, + { + desc: "With instance name and ApplicationIntent", + dataSource: sqleng.DataSourceInfo{ + URL: "localhost\\instance;ApplicationIntent=ReadOnly", + Database: "database", + User: "user", + JsonData: sqleng.JsonData{}, + }, + expConnStr: "server=localhost\\instance;ApplicationIntent=ReadOnly;database=database;user id=user;password=;", + }, + { + desc: "With ApplicationIntent instance name and port", + dataSource: sqleng.DataSourceInfo{ + URL: "localhost\\instance:333;ApplicationIntent=ReadOnly", + Database: "database", + User: "user", + JsonData: sqleng.JsonData{}, + }, + expConnStr: "server=localhost\\instance;database=database;user id=user;password=;port=333;ApplicationIntent=ReadOnly;", + }, { desc: "Defaults", dataSource: sqleng.DataSourceInfo{