1use std::sync::Arc;
16
17use clap::Parser;
18use common_error::ext::BoxedError;
19use common_meta::kv_backend::KvBackendRef;
20use common_meta::kv_backend::chroot::ChrootKvBackend;
21use common_meta::kv_backend::etcd::EtcdStore;
22use meta_srv::metasrv::{BackendClientOptions, BackendImpl};
23use meta_srv::utils::etcd::create_etcd_client_with_tls;
24use servers::tls::{TlsMode, TlsOption};
25
26use crate::error::EmptyStoreAddrsSnafu;
27
28#[derive(Debug, Default, Parser)]
29pub struct StoreConfig {
30 #[clap(long, alias = "store-addr", value_delimiter = ',', num_args = 1..)]
41 pub store_addrs: Vec<String>,
42
43 #[clap(long, default_value = "128")]
45 pub max_txn_ops: usize,
46
47 #[clap(long, value_enum, default_value = "etcd-store")]
49 pub backend: BackendImpl,
50
51 #[clap(long, default_value = "")]
53 pub store_key_prefix: String,
54
55 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
57 #[clap(long, default_value = common_meta::kv_backend::DEFAULT_META_TABLE_NAME)]
58 pub meta_table_name: String,
59
60 #[cfg(feature = "pg_kvbackend")]
62 #[clap(long)]
63 pub meta_schema_name: Option<String>,
64
65 #[cfg(feature = "pg_kvbackend")]
67 #[clap(long, default_value_t = true)]
68 pub auto_create_schema: bool,
69
70 #[clap(long = "backend-tls-mode", value_enum, default_value = "disable")]
72 pub backend_tls_mode: TlsMode,
73
74 #[clap(long = "backend-tls-cert-path", default_value = "")]
76 pub backend_tls_cert_path: String,
77
78 #[clap(long = "backend-tls-key-path", default_value = "")]
80 pub backend_tls_key_path: String,
81
82 #[clap(long = "backend-tls-ca-cert-path", default_value = "")]
84 pub backend_tls_ca_cert_path: String,
85
86 #[clap(long = "backend-tls-watch")]
88 pub backend_tls_watch: bool,
89}
90
91impl StoreConfig {
92 pub fn tls_config(&self) -> Option<TlsOption> {
93 if self.backend_tls_mode != TlsMode::Disable {
94 Some(TlsOption {
95 mode: self.backend_tls_mode.clone(),
96 cert_path: self.backend_tls_cert_path.clone(),
97 key_path: self.backend_tls_key_path.clone(),
98 ca_cert_path: self.backend_tls_ca_cert_path.clone(),
99 watch: self.backend_tls_watch,
100 })
101 } else {
102 None
103 }
104 }
105
106 pub async fn build(&self) -> Result<KvBackendRef, BoxedError> {
108 let max_txn_ops = self.max_txn_ops;
109 let store_addrs = &self.store_addrs;
110 if store_addrs.is_empty() {
111 EmptyStoreAddrsSnafu.fail().map_err(BoxedError::new)
112 } else {
113 common_telemetry::info!(
114 "Building kvbackend with store addrs: {:?}, backend: {:?}",
115 store_addrs,
116 self.backend
117 );
118 let kvbackend = match self.backend {
119 BackendImpl::EtcdStore => {
120 let tls_config = self.tls_config();
121 let etcd_client = create_etcd_client_with_tls(
122 store_addrs,
123 &BackendClientOptions::default(),
124 tls_config.as_ref(),
125 )
126 .await
127 .map_err(BoxedError::new)?;
128 Ok(EtcdStore::with_etcd_client(etcd_client, max_txn_ops))
129 }
130 #[cfg(feature = "pg_kvbackend")]
131 BackendImpl::PostgresStore => {
132 let table_name = &self.meta_table_name;
133 let tls_config = self.tls_config();
134 let pool = meta_srv::utils::postgres::create_postgres_pool(
135 store_addrs,
136 None,
137 tls_config,
138 )
139 .await
140 .map_err(BoxedError::new)?;
141 let schema_name = self.meta_schema_name.as_deref();
142 Ok(common_meta::kv_backend::rds::PgStore::with_pg_pool(
143 pool,
144 schema_name,
145 table_name,
146 max_txn_ops,
147 self.auto_create_schema,
148 )
149 .await
150 .map_err(BoxedError::new)?)
151 }
152 #[cfg(feature = "mysql_kvbackend")]
153 BackendImpl::MysqlStore => {
154 let table_name = &self.meta_table_name;
155 let tls_config = self.tls_config();
156 let pool =
157 meta_srv::utils::mysql::create_mysql_pool(store_addrs, tls_config.as_ref())
158 .await
159 .map_err(BoxedError::new)?;
160 Ok(common_meta::kv_backend::rds::MySqlStore::with_mysql_pool(
161 pool,
162 table_name,
163 max_txn_ops,
164 )
165 .await
166 .map_err(BoxedError::new)?)
167 }
168 #[cfg(not(test))]
169 BackendImpl::MemoryStore => {
170 use crate::error::UnsupportedMemoryBackendSnafu;
171
172 UnsupportedMemoryBackendSnafu
173 .fail()
174 .map_err(BoxedError::new)
175 }
176 #[cfg(test)]
177 BackendImpl::MemoryStore => {
178 use common_meta::kv_backend::memory::MemoryKvBackend;
179
180 Ok(Arc::new(MemoryKvBackend::default()) as _)
181 }
182 };
183 if self.store_key_prefix.is_empty() {
184 kvbackend
185 } else {
186 let chroot_kvbackend =
187 ChrootKvBackend::new(self.store_key_prefix.as_bytes().to_vec(), kvbackend?);
188 Ok(Arc::new(chroot_kvbackend))
189 }
190 }
191 }
192}