Skip to content

Commit 213ff98

Browse files
committed
mk-sql: use cluster name with odbc
When a SQL Server instance belongs to a Windows Server Failover Cluster (WSFC), ODBC connections must use the cluster's Virtual Network Name (VNN) as the SERVER parameter instead of the physical hostname. Send downstream cluster_name through `create_odbc_client` and `make_connection_string` so that the VNN takes priority over hostname when present. Affects both SqlInstance::connect (established instances) and get_custom_instance_builder. CMK-32976 Change-Id: Ie907123939966f36a4a274bf462fd5c5bd55ccd6
1 parent ebd595d commit 213ff98

3 files changed

Lines changed: 46 additions & 8 deletions

File tree

packages/mk-sql/src/ms_sql/instance.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,13 @@ impl SqlInstance {
481481
if self.tcp {
482482
create_tcp_client(endpoint, database, self.port()).await
483483
} else {
484-
create_odbc_client(endpoint.conn(), &self.name, database).await
484+
create_odbc_client(
485+
endpoint.conn(),
486+
self.cluster_name.as_ref(),
487+
&self.name,
488+
database,
489+
)
490+
.await
485491
}
486492
}
487493

@@ -1383,21 +1389,24 @@ pub async fn create_tcp_client(
13831389

13841390
pub async fn create_odbc_client(
13851391
connection: &Connection,
1392+
cluster_name: Option<&ClusterName>,
13861393
instance_name: &InstanceName,
13871394
database: Option<String>,
13881395
) -> Result<UniClient> {
13891396
let hostname = connection.hostname();
13901397
#[cfg(unix)]
13911398
anyhow::bail!(
1392-
"ODBC Not supported `{}` `{}` db:`{:?}`",
1399+
"ODBC Not supported `{}` `{}` cluster:`{:?}` db:`{:?}`",
13931400
hostname,
13941401
instance_name,
1402+
cluster_name,
13951403
database
13961404
);
13971405
#[cfg(windows)]
13981406
{
13991407
let connection_string = odbc::make_connection_string(
14001408
Some(&hostname),
1409+
cluster_name,
14011410
instance_name,
14021411
database.as_deref(),
14031412
None,
@@ -2197,8 +2206,11 @@ async fn get_custom_instance_builder(
21972206
let auth = endpoint.auth();
21982207
let conn = endpoint.conn();
21992208
if is_local_endpoint(auth, conn) && !is_use_tcp(instance_name, auth, conn) {
2200-
if let Ok(mut client) = create_odbc_client(conn, instance_name, None).await {
2201-
log::debug!("Trying to connect to `{instance_name}` using ODBC");
2209+
log::debug!("Trying to connect to `{instance_name}` using ODBC");
2210+
if let Ok(mut client) =
2211+
create_odbc_client(conn, builder.cluster_name.as_ref(), instance_name, None).await
2212+
{
2213+
log::debug!("Connected to `{instance_name}` using ODBC");
22022214
let b = obtain_properties(&mut client, instance_name)
22032215
.await
22042216
.map(|p| to_instance_builder(builder.to_owned(), endpoint, &p));
@@ -2280,7 +2292,7 @@ async fn find_custom_instance(
22802292
.map(|p| {
22812293
// Fresh builder: this function has no access to the original customized
22822294
// builder, so customizations (cluster, alias, piggyback) are not carried
2283-
// through here.
2295+
// through here. Accepted limitation for this port-scan fallback path.
22842296
to_instance_builder(SqlInstanceBuilder::new(), endpoint, &p).port(detected_port)
22852297
})
22862298
} else {

packages/mk-sql/src/platform.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ mod tests {
268268
#[cfg(windows)]
269269
pub mod odbc {
270270
use super::Block;
271+
use crate::types::ClusterName;
271272
use anyhow::Result;
272273
use odbc_api::{
273274
buffers::{ColumnarBuffer, TextColumn, TextRowSet},
@@ -310,15 +311,22 @@ pub mod odbc {
310311
/// always SSPI = Trusted connection, but TrustServerCertificate depends
311312
pub fn make_connection_string(
312313
hostname: Option<&HostName>,
314+
cluster_name: Option<&ClusterName>,
313315
instance: &InstanceName,
314316
database: Option<&str>,
315317
driver: Option<&str>,
316318
trust_server_certificate: bool,
317319
) -> String {
320+
let server = match cluster_name {
321+
Some(c) => c.to_string(),
322+
None => hostname
323+
.map(|h| h.to_string())
324+
.unwrap_or_else(|| "(local)".to_string()),
325+
};
318326
format!(
319327
"Driver={{{}}};SERVER={}{};Database={};Integrated Security=SSPI;Trusted_Connection=yes;Encrypt=yes;TrustServerCertificate={};",
320328
driver.unwrap_or(&ODBC_DRIVER.clone()),
321-
hostname.map(|h| h.to_string()).unwrap_or("(local)".to_string()),
329+
server,
322330
if instance.to_string().to_uppercase() == *"MSSQLSERVER" {
323331
"".to_string()
324332
} else {
@@ -413,11 +421,12 @@ pub mod odbc {
413421
#[cfg(test)]
414422
mod tests {
415423
use crate::platform::odbc::{self, ODBC_DRIVER};
416-
use crate::types::{HostName, InstanceName};
424+
use crate::types::{ClusterName, HostName, InstanceName};
417425

418426
#[test]
419427
fn test_make_connection_string() {
420428
assert_eq!( odbc::make_connection_string(
429+
None,
421430
None,
422431
&InstanceName::from("SQLEXPRESS_NAME"),
423432
None,
@@ -426,15 +435,28 @@ pub mod odbc {
426435
assert_eq!(
427436
odbc::make_connection_string(
428437
Some(&HostName::from("host".to_string())),
438+
None,
429439
&InstanceName::from("Instance"),
430440
Some("db"),
431441
Some("driver"),
432442
true
433443
),
434444
"Driver={driver};SERVER=host\\Instance;Database=db;Integrated Security=SSPI;Trusted_Connection=yes;Encrypt=yes;TrustServerCertificate=yes;"
435445
);
446+
assert_eq!(
447+
odbc::make_connection_string(
448+
Some(&HostName::from("host".to_string())),
449+
Some(&ClusterName::from("cluster".to_string())),
450+
&InstanceName::from("Instance"),
451+
Some("db"),
452+
Some("driver"),
453+
true
454+
),
455+
"Driver={driver};SERVER=cluster\\Instance;Database=db;Integrated Security=SSPI;Trusted_Connection=yes;Encrypt=yes;TrustServerCertificate=yes;"
456+
);
436457
assert_eq!( odbc::make_connection_string(
437458
Some(&HostName::from("host".to_string())),
459+
None,
438460
&InstanceName::from("mssqlserver"),
439461
None,
440462
None, false),

packages/mk-sql/tests/test_ms_sql.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,7 @@ fn test_odbc() {
16231623

16241624
let s = odbc::make_connection_string(
16251625
Some(&HostName::from("127.0.0.1".to_string())),
1626+
None,
16261627
&InstanceName::from("SQLEXPRESS_NAME"),
16271628
Some("master"),
16281629
None,
@@ -1653,6 +1654,7 @@ fn test_odbc() {
16531654
#[test]
16541655
fn test_odbc_timeout() {
16551656
let s = odbc::make_connection_string(
1657+
None,
16561658
None,
16571659
&InstanceName::from("SQLEXPRESS_XX"),
16581660
Some("master"),
@@ -1689,7 +1691,9 @@ async fn test_odbc_high_level() {
16891691
)
16901692
.unwrap()
16911693
.unwrap();
1692-
create_odbc_client(&c, &instance_name, None).await.unwrap()
1694+
create_odbc_client(&c, None, &instance_name, None)
1695+
.await
1696+
.unwrap()
16931697
}
16941698

16951699
async fn get_props(name: &str, trust: bool) -> Option<SqlInstanceProperties> {

0 commit comments

Comments
 (0)