【发布时间】:2020-06-30 11:11:53
【问题描述】:
我有一个集成测试,它使用 SQL Server 和已恢复的数据库启动基于 Linux 的 Docker 容器。该测试运行一个简单的select count(*) 查询,并且每次在本地运行时都通过。当测试作为 Azure DevOps Pipeline 的一部分运行时,测试失败并出现以下错误:
System.Data.SqlClient.SqlException : Cannot open database "A" requested by the login. The login failed. Login failed for user 'sa'.
Stack Trace:
at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen()
当我将测试更改为查询master数据库而不是我们自己的数据库时,查询运行成功并且测试通过了。
测试的核心如下:
using (var connection = new SqlConnection(connectionString.ConnectionString))
{
await connection.OpenAsync().ConfigureAwait(false);
using (var command = new SqlCommand("select count(*) from [table];", connection))
{
var rowCount = (int)await command.ExecuteScalarAsync();
rowCount.Should().BeGreaterThan(0);
}
connection.Close();
}
此连接字符串有效:
var connectionString = new SqlConnectionStringBuilder
{
DataSource = "localhost,32808",
UserID = "sa",
Password = "P@ssword!23",
InitialCatalog = "master",
ConnectTimeout = 120,
ConnectRetryCount = 3
};
这个失败了:
var connectionString = new SqlConnectionStringBuilder
{
DataSource = "localhost,32808",
UserID = "sa",
Password = "P@ssword!23",
InitialCatalog = "A",
ConnectTimeout = 120,
ConnectRetryCount = 3
};
最初,测试因连接超时而失败。我添加了更长的超时,异常更改为这个。安全设置中没有明显的缺失:sa 是A 数据库的dbo。此外,测试使用相同的 Docker 映像在本地通过。
任何关于如何解决这个问题的想法,或者通过日志等获得额外的反馈,我们都非常感激。
SQL Server 15.0.4023.6; Ubuntu 18.04.4;完整的 Azure 构建代理规范 here;
【问题讨论】:
-
由于测试成功访问了master数据库中的用户对象,看来这些对象被部署到master而不是用户数据库A。登录失败错误表明A数据库不存在。跨度>
-
为什么这在 DevOps 构建代理的上下文中会有所不同?它与我在本地使用的 Docker 映像相同,并且具有可用的数据库。
-
另外,我可以在测试中使用
master连接字符串并成功运行这个查询:use [A]; select count(*) from ATable;所以,A数据库必须在那里并且是可查询的。 -
由于
USE A成功,当该查询运行时数据库显然就在那里。我的怀疑是在建立直接连接时还不可用。 SQL Server 错误日志中应该有一条相关消息,详细说明登录失败的原因。 -
我认为你是对的。我在测试中添加了 2 分钟的暂停,现在它通过了。容器启动代码使用到
master数据库的连接,因为它表明容器已准备就绪,但是,系统数据库和用户数据库的初始化之间显然存在很大差距。
标签: sql-server linux docker azure-devops azure-pipelines