mz_debug/
utils.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
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 in the LICENSE file at the
6// root of this repository, or online at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15use anyhow::Context as AnyhowContext;
16
17use std::fs::{File, create_dir_all, remove_dir_all};
18use std::io::{BufWriter, copy};
19use std::path::PathBuf;
20use std::str::FromStr;
21
22use chrono::{DateTime, Utc};
23use kube::{Api, Client};
24use mz_cloud_resources::crd::materialize::v1alpha1::Materialize;
25use mz_server_core::listeners::AuthenticatorKind;
26use zip::ZipWriter;
27use zip::write::SimpleFileOptions;
28
29use crate::{AuthMode, PasswordAuthCredentials};
30
31/// Formats the base path for the output of the debug tool.
32pub fn format_base_path(date_time: DateTime<Utc>) -> PathBuf {
33    PathBuf::from(format!("mz_debug_{}", date_time.format("%Y-%m-%dT%H:%MZ")))
34}
35
36pub fn validate_pg_connection_string(connection_string: &str) -> Result<String, String> {
37    tokio_postgres::Config::from_str(connection_string)
38        .map(|_| connection_string.to_string())
39        .map_err(|e| format!("Invalid PostgreSQL connection string: {}", e))
40}
41
42pub fn create_tracing_log_file(dir: PathBuf) -> Result<File, std::io::Error> {
43    let log_file = dir.join("tracing.log");
44    if log_file.exists() {
45        remove_dir_all(&log_file)?;
46    }
47    create_dir_all(&dir)?;
48    let file = File::create(&log_file);
49    file
50}
51
52/// Zips a folder
53pub fn zip_debug_folder(zip_file_name: PathBuf, folder_path: &PathBuf) -> std::io::Result<()> {
54    // Delete the zip file if it already exists
55    if zip_file_name.exists() {
56        std::fs::remove_file(&zip_file_name)?;
57    }
58    let zip_file = File::create(&zip_file_name)?;
59    let mut zip_writer = ZipWriter::new(BufWriter::new(zip_file));
60
61    for entry in walkdir::WalkDir::new(folder_path) {
62        let entry = entry?;
63        let path = entry.path();
64
65        if path.is_file() {
66            zip_writer.start_file(path.to_string_lossy(), SimpleFileOptions::default())?;
67            let mut file = File::open(path)?;
68            copy(&mut file, &mut zip_writer)?;
69        }
70    }
71
72    zip_writer.finish()?;
73    Ok(())
74}
75
76pub async fn get_k8s_auth_mode(
77    mz_username: Option<String>,
78    mz_password: Option<String>,
79    k8s_client: &Client,
80    k8s_namespace: &String,
81    mz_instance_name: &String,
82) -> Result<AuthMode, anyhow::Error> {
83    let materialize_api = Api::<Materialize>::namespaced(k8s_client.clone(), k8s_namespace);
84
85    let materialize_cr = materialize_api
86        .get(mz_instance_name)
87        .await
88        .with_context(|| {
89            format!(
90                "Could not find Materialize CR with name: {}",
91                mz_instance_name
92            )
93        })?;
94
95    let authenticator_kind = materialize_cr.spec.authenticator_kind;
96
97    match authenticator_kind {
98        AuthenticatorKind::None => Ok(AuthMode::None),
99        AuthenticatorKind::Password => {
100            if let (Some(mz_username), Some(mz_password)) = (&mz_username, &mz_password) {
101                Ok(AuthMode::Password(PasswordAuthCredentials {
102                    username: mz_username.clone(),
103                    password: mz_password.clone(),
104                }))
105            } else {
106                Err(anyhow::anyhow!(
107                    "mz_username and mz_password are required for password authentication"
108                ))
109            }
110        }
111        _ => Err(anyhow::anyhow!(
112            "Unsupported authenticator kind: {:?}",
113            authenticator_kind
114        )),
115    }
116}