【问题标题】:Cannot query containerised SQL Server database from Azure DevOps Pipeline integration test无法从 Azure DevOps Pipeline 集成测试查询容器化 SQL Server 数据库
【发布时间】: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 
};

最初,测试因连接超时而失败。我添加了更长的超时,异常更改为这个。安全设置中没有明显的缺失:saA 数据库的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


【解决方案1】:

事实证明,这个问题的关键在于测试代码如何检查容器中 SQL Server 实例的就绪情况。

代码尝试使用master 数据库创建与容器中运行的SQL Server 实例的连接。我不知道的是,虽然master 数据库可能已准备好并接受连接,但其他数据库可能还没有。我更改了代码以尝试使用测试要使用的实际数据库进行连接,而不是master,这似乎可行。

本地测试一定是在本地通过的,因为与 Azure DevOps 环境相比,容器在该环境中能够始终更快地完成初始化。

【讨论】:

  • 太棒了!感谢您在此处分享您的解决方案,您可以接受它作为答案,这样它可以帮助遇到相同问题的其他社区成员,我们可以归档这个帖子,谢谢。
猜你喜欢
  • 1970-01-01
  • 2021-03-10
  • 1970-01-01
  • 2019-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多