meta_srv/utils/
mysql.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use common_telemetry::info;
16use servers::tls::{TlsMode, TlsOption};
17use snafu::{OptionExt, ResultExt};
18use sqlx::mysql::{MySqlConnectOptions, MySqlPool, MySqlSslMode};
19
20use crate::error::{self, Result};
21
22async fn setup_mysql_options(
23    store_addrs: &[String],
24    tls_config: Option<&TlsOption>,
25) -> Result<MySqlConnectOptions> {
26    let mysql_url = store_addrs.first().context(error::InvalidArgumentsSnafu {
27        err_msg: "empty store addrs",
28    })?;
29    // Avoid `SET` commands in sqlx
30    let opts: MySqlConnectOptions = mysql_url
31        .parse()
32        .context(error::ParseMySqlUrlSnafu { mysql_url })?;
33    let mut opts = opts
34        .no_engine_substitution(false)
35        .pipes_as_concat(false)
36        .timezone(None)
37        .set_names(false);
38
39    let Some(tls_config) = tls_config else {
40        return Ok(opts);
41    };
42
43    match tls_config.mode {
44        TlsMode::Disable => return Ok(opts),
45        TlsMode::Prefer => {
46            opts = opts.ssl_mode(MySqlSslMode::Preferred);
47        }
48        TlsMode::Require => {
49            opts = opts.ssl_mode(MySqlSslMode::Required);
50        }
51        TlsMode::VerifyCa => {
52            opts = opts.ssl_mode(MySqlSslMode::VerifyCa);
53            opts = opts.ssl_ca(&tls_config.ca_cert_path);
54        }
55        TlsMode::VerifyFull => {
56            opts = opts.ssl_mode(MySqlSslMode::VerifyIdentity);
57            opts = opts.ssl_ca(&tls_config.ca_cert_path);
58        }
59    }
60    info!(
61        "Setting up MySQL options with TLS mode: {:?}",
62        tls_config.mode
63    );
64
65    if !tls_config.cert_path.is_empty() && !tls_config.key_path.is_empty() {
66        info!("Loading client certificate for mutual TLS");
67        opts = opts.ssl_client_cert(&tls_config.cert_path);
68        opts = opts.ssl_client_key(&tls_config.key_path);
69    }
70
71    Ok(opts)
72}
73
74/// Creates a MySQL pool.
75pub async fn create_mysql_pool(
76    store_addrs: &[String],
77    tls_config: Option<&TlsOption>,
78) -> Result<MySqlPool> {
79    let opts = setup_mysql_options(store_addrs, tls_config).await?;
80    let pool = MySqlPool::connect_with(opts)
81        .await
82        .context(error::CreateMySqlPoolSnafu)?;
83
84    Ok(pool)
85}