meta_srv/utils/
etcd.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_meta::kv_backend::etcd::create_etcd_tls_options;
16use common_telemetry::warn;
17use etcd_client::{Client, ConnectOptions};
18use servers::tls::{TlsMode, TlsOption};
19use snafu::ResultExt;
20
21use crate::error::{self, BuildTlsOptionsSnafu, Result};
22use crate::metasrv::BackendClientOptions;
23
24/// Creates an etcd client with TLS configuration.
25pub async fn create_etcd_client_with_tls(
26    store_addrs: &[String],
27    client_options: &BackendClientOptions,
28    tls_config: Option<&TlsOption>,
29) -> Result<Client> {
30    let etcd_endpoints = store_addrs
31        .iter()
32        .map(|x| x.trim())
33        .filter(|x| !x.is_empty())
34        .collect::<Vec<_>>();
35
36    let mut connect_options = ConnectOptions::new()
37        .with_keep_alive_while_idle(true)
38        .with_keep_alive(
39            client_options.keep_alive_interval,
40            client_options.keep_alive_timeout,
41        );
42
43    let all_endpoints_use_https = etcd_endpoints.iter().all(|e| e.starts_with("https"));
44    if let Some(tls_config) = tls_config
45        && let Some(tls_options) =
46            create_etcd_tls_options(&convert_tls_option(all_endpoints_use_https, tls_config))
47                .context(BuildTlsOptionsSnafu)?
48    {
49        connect_options = connect_options.with_tls(tls_options);
50    }
51
52    Client::connect(&etcd_endpoints, Some(connect_options))
53        .await
54        .context(error::ConnectEtcdSnafu)
55}
56
57fn convert_tls_option(
58    all_endpoints_use_https: bool,
59    tls_option: &TlsOption,
60) -> common_meta::kv_backend::etcd::TlsOption {
61    let mode = match tls_option.mode {
62        TlsMode::Disable => common_meta::kv_backend::etcd::TlsMode::Disable,
63        TlsMode::Prefer => {
64            if all_endpoints_use_https {
65                common_meta::kv_backend::etcd::TlsMode::Require
66            } else {
67                warn!(
68                    "All endpoints use HTTP, TLS prefer mode is not supported, using disable mode"
69                );
70                common_meta::kv_backend::etcd::TlsMode::Disable
71            }
72        }
73        _ => common_meta::kv_backend::etcd::TlsMode::Require,
74    };
75    common_meta::kv_backend::etcd::TlsOption {
76        mode,
77        cert_path: tls_option.cert_path.clone(),
78        key_path: tls_option.key_path.clone(),
79        ca_cert_path: tls_option.ca_cert_path.clone(),
80    }
81}