feat: add tiered Oracle agent profiles
This commit is contained in:
1 parent
f13c46b903
commit
c334550252
11 files changed
+152
-38
No files matched your search
@@ -91,6 +91,7 @@
|
||||
"skipTcpProbe": true,
|
||||
"defaultPort": 1521,
|
||||
"driverProfiles": [
|
||||
{ "profile": "oracle-legacy", "label": "Oracle Legacy", "agentKey": "oracle-legacy" },
|
||||
{ "profile": "oracle-10g", "label": "Oracle 10g", "agentKey": "oracle-10g" }
|
||||
]
|
||||
},
|
||||
|
||||
@@ -17,8 +17,10 @@ pub struct AgentDriverProfile {
|
||||
pub store_visible: bool,
|
||||
}
|
||||
|
||||
const ORACLE_PROFILES: &[AgentDriverProfile] =
|
||||
&[AgentDriverProfile { profile: "oracle-10g", key: "oracle-10g", label: "Oracle 10g", store_visible: true }];
|
||||
const ORACLE_PROFILES: &[AgentDriverProfile] = &[
|
||||
AgentDriverProfile { profile: "oracle-legacy", key: "oracle-legacy", label: "Oracle Legacy", store_visible: true },
|
||||
AgentDriverProfile { profile: "oracle-10g", key: "oracle-10g", label: "Oracle 10g", store_visible: true },
|
||||
];
|
||||
|
||||
const AGENT_CATALOG: &[AgentCatalogEntry] = &[
|
||||
AgentCatalogEntry {
|
||||
|
||||
@@ -110,14 +110,22 @@ fn postgres_like_agent_jdbc_connection_string(
|
||||
}
|
||||
|
||||
pub fn should_retry_oracle_with_10g_driver(config: &ConnectionConfig, err: &str) -> bool {
|
||||
!oracle_auth_fallback_profiles(config, err).is_empty()
|
||||
}
|
||||
|
||||
pub fn oracle_auth_fallback_profiles(config: &ConnectionConfig, err: &str) -> Vec<&'static str> {
|
||||
if config.db_type != DatabaseType::Oracle {
|
||||
return false;
|
||||
}
|
||||
if config.driver_profile.as_deref() == Some("oracle-10g") {
|
||||
return false;
|
||||
return Vec::new();
|
||||
}
|
||||
let normalized = err.to_lowercase();
|
||||
normalized.contains("ora-28040") || normalized.contains("no matching authentication protocol")
|
||||
if !normalized.contains("ora-28040") && !normalized.contains("no matching authentication protocol") {
|
||||
return Vec::new();
|
||||
}
|
||||
match config.driver_profile.as_deref() {
|
||||
Some("oracle-10g") => Vec::new(),
|
||||
Some("oracle-legacy") => vec!["oracle-10g"],
|
||||
_ => vec!["oracle-legacy", "oracle-10g"],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn oracle_alternate_connect_config(config: &ConnectionConfig, err: &str) -> Option<ConnectionConfig> {
|
||||
@@ -295,6 +303,26 @@ mod tests {
|
||||
assert!(oracle_alternate_connect_config(&cfg, "ORA-12541: TNS:no listener").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oracle_auth_errors_use_legacy_then_10g_fallbacks() {
|
||||
let mut cfg = config(DatabaseType::Oracle, Some("ORCL"));
|
||||
cfg.driver_profile = Some("oracle".to_string());
|
||||
|
||||
assert_eq!(
|
||||
oracle_auth_fallback_profiles(&cfg, "ORA-28040: No matching authentication protocol"),
|
||||
vec!["oracle-legacy", "oracle-10g"]
|
||||
);
|
||||
|
||||
cfg.driver_profile = Some("oracle-legacy".to_string());
|
||||
assert_eq!(
|
||||
oracle_auth_fallback_profiles(&cfg, "ORA-28040: No matching authentication protocol"),
|
||||
vec!["oracle-10g"]
|
||||
);
|
||||
|
||||
cfg.driver_profile = Some("oracle-10g".to_string());
|
||||
assert!(oracle_auth_fallback_profiles(&cfg, "ORA-28040: No matching authentication protocol").is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oracle_custom_connection_string_skips_alternate_descriptor_retry() {
|
||||
let mut cfg = config(DatabaseType::Oracle, Some("ORCL"));
|
||||
|
||||
@@ -152,7 +152,12 @@ mod tests {
|
||||
let manager = test_manager("profile-key");
|
||||
|
||||
assert_eq!(AgentManager::db_type_to_agent_key(&DatabaseType::Oracle, Some("oracle-10g")), Some("oracle-10g"));
|
||||
assert_eq!(
|
||||
AgentManager::db_type_to_agent_key(&DatabaseType::Oracle, Some("oracle-legacy")),
|
||||
Some("oracle-legacy")
|
||||
);
|
||||
assert_eq!(AgentManager::db_type_to_agent_key(&DatabaseType::Oracle, None), Some("oracle"));
|
||||
manager.stop_daemon_by_key("oracle-legacy").await;
|
||||
manager.stop_daemon_by_key("oracle-10g").await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use mysql_async::Row as MysqlRow;
|
||||
|
||||
use crate::agent_connection::{
|
||||
agent_connect_params, mongo_legacy_error_with_auth_hint, oracle_alternate_connect_config,
|
||||
should_retry_oracle_with_10g_driver,
|
||||
oracle_auth_fallback_profiles, should_retry_oracle_with_10g_driver,
|
||||
};
|
||||
use crate::database_capabilities;
|
||||
use crate::db;
|
||||
@@ -333,19 +333,39 @@ impl AppState {
|
||||
})?;
|
||||
} else if should_retry_oracle_with_10g_driver(&db_config, &err) {
|
||||
log::warn!(
|
||||
"Oracle connect failed with profile {:?}: {}. Retrying with oracle-10g profile.",
|
||||
"Oracle connect failed with profile {:?}: {}. Retrying with legacy Oracle profiles.",
|
||||
db_config.driver_profile,
|
||||
err
|
||||
);
|
||||
let mut fallback_client =
|
||||
self.agent_manager.spawn(&db_config.db_type, Some("oracle-10g")).await?;
|
||||
fallback_client
|
||||
.call_method::<serde_json::Value>(AgentMethod::Connect, connect_params)
|
||||
.await
|
||||
.map_err(|fallback_err| {
|
||||
format!("{err}\n\nFallback with oracle-10g driver failed: {fallback_err}")
|
||||
})?;
|
||||
client = fallback_client;
|
||||
let mut fallback_errors = Vec::new();
|
||||
let mut connected_client = None;
|
||||
for profile in oracle_auth_fallback_profiles(&db_config, &err) {
|
||||
match self.agent_manager.spawn(&db_config.db_type, Some(profile)).await {
|
||||
Ok(mut fallback_client) => {
|
||||
match fallback_client
|
||||
.call_method::<serde_json::Value>(AgentMethod::Connect, connect_params.clone())
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
connected_client = Some(fallback_client);
|
||||
break;
|
||||
}
|
||||
Err(fallback_err) => {
|
||||
fallback_errors.push(format!("{profile}: {fallback_err}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(fallback_err) => {
|
||||
fallback_errors.push(format!("{profile}: {fallback_err}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
client = connected_client.ok_or_else(|| {
|
||||
format!(
|
||||
"{err}\n\nFallback with legacy Oracle drivers failed: {}",
|
||||
fallback_errors.join("\n")
|
||||
)
|
||||
})?;
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
@@ -1090,6 +1110,10 @@ mod tests {
|
||||
|
||||
config.driver_profile = Some("oracle-10g".to_string());
|
||||
assert!(!should_retry_oracle_with_10g_driver(&config, "Agent RPC error (-1): ORA-12541: TNS:no listener"));
|
||||
assert!(!should_retry_oracle_with_10g_driver(
|
||||
&config,
|
||||
"Agent RPC error (-1): ORA-28040: No matching authentication protocol"
|
||||
));
|
||||
|
||||
config.driver_profile = Some("oracle".to_string());
|
||||
assert!(!should_retry_oracle_with_10g_driver(
|
||||
|
||||
@@ -61,6 +61,7 @@ fn maps_agent_database_types_to_driver_keys() {
|
||||
assert_eq!(agent_key(&DatabaseType::Gbase, None), Some("gbase"));
|
||||
assert_eq!(agent_key(&DatabaseType::Access, None), Some("access"));
|
||||
assert_eq!(agent_key(&DatabaseType::Oracle, None), Some("oracle"));
|
||||
assert_eq!(agent_key(&DatabaseType::Oracle, Some("oracle-legacy")), Some("oracle-legacy"));
|
||||
assert_eq!(agent_key(&DatabaseType::Oracle, Some("oracle-10g")), Some("oracle-10g"));
|
||||
assert_eq!(agent_key(&DatabaseType::Postgres, None), None);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user