From 0a6fc188886ed2ba53be84c3f11d80d2758ed3a0 Mon Sep 17 00:00:00 2001 From: Alexander Galibey Date: Tue, 7 Nov 2023 16:21:02 +0400 Subject: [PATCH] feat: use installation type in cli commands --- .github/workflows/cd_dev.yaml | 4 +- .github/workflows/ci.yml | 12 +-- .github/workflows/hourly.yml | 2 +- crates/fluvio-cli/src/profile/add.rs | 18 ++-- crates/fluvio-cli/src/profile/list.rs | 18 +++- crates/fluvio-cluster/src/check/mod.rs | 2 +- crates/fluvio-cluster/src/cli/delete.rs | 49 ++++++---- crates/fluvio-cluster/src/cli/diagnostics.rs | 78 +++++++--------- crates/fluvio-cluster/src/cli/shutdown.rs | 44 ++++----- crates/fluvio-cluster/src/cli/start/local.rs | 9 +- crates/fluvio-cluster/src/cli/start/mod.rs | 34 ++++++- crates/fluvio-cluster/src/delete.rs | 11 +-- crates/fluvio-cluster/src/lib.rs | 91 +++++++++++++++++++ crates/fluvio-cluster/src/start/k8.rs | 5 + crates/fluvio-cluster/src/start/local.rs | 42 +++++---- crates/fluvio-spu/Makefile | 2 +- .../setup/environment/local.rs | 5 +- crates/fluvio/src/config/config.rs | 11 +++ tests/cli/fluvio_read_only/basic.bats | 2 +- tls/Makefile | 2 +- 20 files changed, 293 insertions(+), 148 deletions(-) diff --git a/.github/workflows/cd_dev.yaml b/.github/workflows/cd_dev.yaml index 19c8992de4..43f04fe689 100644 --- a/.github/workflows/cd_dev.yaml +++ b/.github/workflows/cd_dev.yaml @@ -141,7 +141,7 @@ jobs: - name: Run diagnostics if: ${{ !success() }} timeout-minutes: 5 - run: ~/.fluvio/bin/fluvio cluster diagnostics --k8 + run: ~/.fluvio/bin/fluvio cluster diagnostics - name: Upload diagnostics uses: actions/upload-artifact@v3 timeout-minutes: 5 @@ -236,7 +236,7 @@ jobs: - name: Run diagnostics if: ${{ !success() }} timeout-minutes: 5 - run: fluvio cluster diagnostics --k8 + run: fluvio cluster diagnostics - name: Upload diagnostics uses: actions/upload-artifact@v3 timeout-minutes: 5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe8b1d3e44..acbf325e85 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -678,7 +678,7 @@ jobs: - name: Run diagnostics if: ${{ !success() }} timeout-minutes: 5 - run: fluvio cluster diagnostics --local + run: fluvio cluster diagnostics - name: Upload diagnostics uses: actions/upload-artifact@v3 timeout-minutes: 5 @@ -840,7 +840,7 @@ jobs: - name: Run diagnostics if: ${{ !success() }} timeout-minutes: 5 - run: fluvio cluster diagnostics --k8 + run: fluvio cluster diagnostics - name: Upload diagnostics timeout-minutes: 5 if: ${{ !success() }} @@ -903,7 +903,7 @@ jobs: - name: Run diagnostics if: ${{ !success() }} timeout-minutes: 5 - run: ~/bin/fluvio cluster diagnostics --k8 + run: ~/bin/fluvio cluster diagnostics - name: Upload logs timeout-minutes: 5 if: ${{ !success() }} @@ -1075,7 +1075,7 @@ jobs: - name: Run diagnostics if: ${{ !success() }} timeout-minutes: 5 - run: fluvio cluster diagnostics --k8 + run: fluvio cluster diagnostics - name: Upload diagnostics uses: actions/upload-artifact@v3 timeout-minutes: 5 @@ -1216,12 +1216,12 @@ jobs: - name: Shutdown Fluvio cluster timeout-minutes: 10 - run: fluvio cluster shutdown --local + run: fluvio cluster shutdown - name: Run diagnostics if: ${{ !success() }} timeout-minutes: 5 - run: fluvio cluster diagnostics --local + run: fluvio cluster diagnostics - name: Upload diagnostics uses: actions/upload-artifact@v3 diff --git a/.github/workflows/hourly.yml b/.github/workflows/hourly.yml index 09d2eeb077..30537f2dc0 100644 --- a/.github/workflows/hourly.yml +++ b/.github/workflows/hourly.yml @@ -220,7 +220,7 @@ jobs: - name: Run diagnostics if: failure() timeout-minutes: 5 - run: fluvio cluster diagnostics --k8 + run: fluvio cluster diagnostics - name: Upload diagnostics uses: actions/upload-artifact@v3 timeout-minutes: 5 diff --git a/crates/fluvio-cli/src/profile/add.rs b/crates/fluvio-cli/src/profile/add.rs index ee27184ee1..51b653e91e 100644 --- a/crates/fluvio-cli/src/profile/add.rs +++ b/crates/fluvio-cli/src/profile/add.rs @@ -2,14 +2,18 @@ use clap::Parser; use anyhow::Result; use fluvio::config::{ConfigFile, TlsPolicy}; +use fluvio_cluster::InstallationType; #[derive(Debug, Parser)] pub struct ManualAddOpt { /// Name of profile to add profile_name: String, - /// address of cluster, e.g. 127.0.0.1:9003 + /// Address of cluster, e.g. 127.0.0.1:9003 cluster_address: String, + + /// Installation type of cluster, e.g. local, local-k8, k8 + installation_type: Option, } // todo: p2 add tls config, p1 is default disabled for manual add @@ -23,14 +27,10 @@ impl ManualAddOpt { &self.cluster_address, &def_tls, )?; - if config_file - .mut_config() - .set_current_profile(&self.profile_name) - { - println!("Switched to profile {}", &self.profile_name); - } else { - return Err(anyhow::anyhow!("error creating profile")); - } + let config = config_file.mut_config().current_cluster_mut()?; + self.installation_type.unwrap_or_default().save_to(config)?; + config_file.save()?; + println!("Switched to profile {}", &self.profile_name); } Err(_) => println!("no profile can be found"), } diff --git a/crates/fluvio-cli/src/profile/list.rs b/crates/fluvio-cli/src/profile/list.rs index 8e591e6dfe..ba1da68a45 100644 --- a/crates/fluvio-cli/src/profile/list.rs +++ b/crates/fluvio-cli/src/profile/list.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use fluvio_cluster::InstallationType; use serde::Serialize; use comfy_table::Row; use clap::Parser; @@ -50,7 +51,7 @@ fn format_tls(tls: &TlsPolicy) -> &'static str { impl TableOutputHandler for ListConfig<'_> { fn header(&self) -> Row { - Row::from(["", "PROFILE", "CLUSTER", "ADDRESS", "TLS"]) + Row::from(["", "PROFILE", "CLUSTER", "ADDRESS", "TLS", "INSTALLATION"]) } fn content(&self) -> Vec { @@ -65,13 +66,20 @@ impl TableOutputHandler for ListConfig<'_> { .map(|active| if active { "*" } else { "" }) .unwrap_or(""); - let (cluster, addr, tls) = self + let (cluster, addr, tls, installation_type) = self .0 .cluster(&profile.cluster) - .map(|it| (&*profile.cluster, &*it.endpoint, format_tls(&it.tls))) - .unwrap_or(("", "", "")); + .map(|it| { + ( + &*profile.cluster, + &*it.endpoint, + format_tls(&it.tls), + InstallationType::load_or_default(it).to_string(), + ) + }) + .unwrap_or(("", "", "", "".to_string())); - Row::from([active, profile_name, cluster, addr, tls]) + Row::from([active, profile_name, cluster, addr, tls, &installation_type]) }) .collect() } diff --git a/crates/fluvio-cluster/src/check/mod.rs b/crates/fluvio-cluster/src/check/mod.rs index ecf7dd37e6..cd01271060 100644 --- a/crates/fluvio-cluster/src/check/mod.rs +++ b/crates/fluvio-cluster/src/check/mod.rs @@ -81,7 +81,7 @@ pub enum ClusterCheckError { VersionError(#[from] semver::Error), /// local fluvio exists - #[error("Loocal Fluvio running")] + #[error("Local Fluvio running")] LocalClusterExists, /// Other misc diff --git a/crates/fluvio-cluster/src/cli/delete.rs b/crates/fluvio-cluster/src/cli/delete.rs index 1bd5f805d9..add8443744 100644 --- a/crates/fluvio-cluster/src/cli/delete.rs +++ b/crates/fluvio-cluster/src/cli/delete.rs @@ -1,5 +1,8 @@ use clap::Parser; +use fluvio::config::ConfigFile; +use tracing::debug; +use crate::InstallationType; use crate::delete::ClusterUninstallConfig; use crate::cli::ClusterCliError; @@ -8,17 +11,13 @@ pub struct DeleteOpt { #[arg(long, value_name = "Kubernetes namespace")] namespace: Option, - /// Remove only local spu/sc(custom) fluvio installation - #[arg(long, conflicts_with = "k8", conflicts_with = "sys")] - local: bool, - /// Remove only k8 fluvio installation - #[arg(long, conflicts_with = "local", conflicts_with = "sys")] - k8: bool, + #[arg(long = "k8", conflicts_with = "sys_only")] + k8_only: bool, - #[arg(long, conflicts_with = "k8", conflicts_with = "local")] - /// delete system chart - sys: bool, + #[arg(long = "sys", conflicts_with = "k8_only")] + /// Remove system chart only + sys_only: bool, } impl DeleteOpt { @@ -26,22 +25,36 @@ impl DeleteOpt { let mut builder = ClusterUninstallConfig::builder(); builder.hide_spinner(false); - if self.sys { + if self.sys_only { builder.uninstall_local(false); builder.uninstall_k8(false); builder.uninstall_sys(true); - } else if self.local { - builder.uninstall_local(true); - builder.uninstall_k8(false); - builder.uninstall_sys(false); - } else if self.k8 { + } else if self.k8_only { builder.uninstall_local(false); builder.uninstall_k8(true); builder.uninstall_sys(false); } else { - builder.uninstall_local(true); - builder.uninstall_k8(true); - builder.uninstall_sys(true); + let config_file = ConfigFile::load_default_or_new()?; + let installation_type = + InstallationType::load_or_default(config_file.config().current_cluster()?); + debug!(?installation_type); + match installation_type { + InstallationType::K8 => { + builder.uninstall_local(false); + builder.uninstall_k8(true); + builder.uninstall_sys(true); + } + InstallationType::LocalK8 => { + builder.uninstall_local(true); + builder.uninstall_k8(true); + builder.uninstall_sys(true); + } + InstallationType::Local | InstallationType::ReadOnly => { + builder.uninstall_local(true); + builder.uninstall_k8(false); + builder.uninstall_sys(false); + } + } } if let Some(namespace) = self.namespace { diff --git a/crates/fluvio-cluster/src/cli/diagnostics.rs b/crates/fluvio-cluster/src/cli/diagnostics.rs index c472c92eb8..5c5d431063 100644 --- a/crates/fluvio-cluster/src/cli/diagnostics.rs +++ b/crates/fluvio-cluster/src/cli/diagnostics.rs @@ -13,36 +13,21 @@ use fluvio::config::ConfigFile; use fluvio::metadata::{topic::TopicSpec, partition::PartitionSpec, spg::SpuGroupSpec, spu::SpuSpec}; use fluvio_sc_schema::objects::Metadata; +use crate::InstallationType; use crate::cli::ClusterCliError; use crate::cli::start::get_log_directory; -use crate::start::local::DEFAULT_DATA_DIR as DEFAULT_LOCAL_DIR; - -#[derive(Debug)] -enum ProfileType { - K8, - Local, - Cloud, -} +use crate::start::local::{DEFAULT_DATA_DIR as DEFAULT_LOCAL_DIR, DEFAULT_METADATA_SUB_DIR}; #[derive(Parser, Debug)] pub struct DiagnosticsOpt { #[arg(long)] quiet: bool, - - #[arg(long)] - k8: bool, - - #[arg(long)] - local: bool, - - #[arg(long)] - cloud: bool, } impl DiagnosticsOpt { pub async fn process(self) -> Result<()> { - let profile_ty = self.get_profile_ty()?; - println!("Using profile type: {profile_ty:#?}"); + let installation_ty = self.get_installation_ty()?; + println!("Using installation: {installation_ty:#?}"); let temp_dir = tempfile::Builder::new() .prefix("fluvio-diagnostics") .tempdir()?; @@ -57,21 +42,25 @@ impl DiagnosticsOpt { }; // write internal fluvio cluster internal state - match profile_ty { + match installation_ty { // Local cluster - ProfileType::Local => { - self.write_helm(temp_path)?; + InstallationType::Local | InstallationType::ReadOnly => { self.copy_local_logs(temp_path)?; + self.copy_local_metadata(temp_path)?; for spu in spu_specs { self.spu_disk_usage(None, temp_path, &spu.spec)?; } } - // Cloud cluster - ProfileType::Cloud => { - println!("Cannot collect logs from Cloud, skipping"); + // Local cluster with k8 metadata + InstallationType::LocalK8 => { + self.write_helm(temp_path)?; + self.copy_local_logs(temp_path)?; + for spu in spu_specs { + self.spu_disk_usage(None, temp_path, &spu.spec)?; + } } - // Guess Kubernetes cluster - ProfileType::K8 => { + // Kubernetes cluster + InstallationType::K8 => { let kubectl = match which("kubectl") { Ok(kubectl) => kubectl, Err(_) => { @@ -110,23 +99,11 @@ impl DiagnosticsOpt { Ok(()) } - // get type of profile - fn get_profile_ty(&self) -> Result { - if self.k8 { - Ok(ProfileType::K8) - } else if self.local { - Ok(ProfileType::Local) - } else if self.cloud { - Ok(ProfileType::Cloud) - } else { - let config = ConfigFile::load_default_or_new()?; - match config.config().current_profile_name() { - Some("local") => Ok(ProfileType::Local), - // Cloud cluster - Some(other) if other.contains("cloud") => Ok(ProfileType::Cloud), - _ => Ok(ProfileType::K8), - } - } + fn get_installation_ty(&self) -> Result { + let config = ConfigFile::load_default_or_new()?; + Ok(InstallationType::load_or_default( + config.config().current_cluster()?, + )) } fn zip_files(&self, source: &Path, output: &mut std::fs::File) -> Result<(), std::io::Error> { @@ -158,6 +135,19 @@ impl DiagnosticsOpt { Ok(()) } + fn copy_local_metadata(&self, dest_dir: &Path) -> Result<()> { + let metadata_path = DEFAULT_LOCAL_DIR + .to_owned() + .unwrap_or_default() + .join(DEFAULT_METADATA_SUB_DIR); + if metadata_path.exists() { + println!("reading local metadata from {metadata_path:?}"); + let mut metadata_file = std::fs::File::create(dest_dir.join("metadata.tar.gz"))?; + self.zip_files(&metadata_path, &mut metadata_file)?; + } + Ok(()) + } + /// get logs from k8 pod fn copy_kubernetes_logs(&self, kubectl: &Path, dest_dir: &Path) -> Result<()> { let pods = cmd!( diff --git a/crates/fluvio-cluster/src/cli/shutdown.rs b/crates/fluvio-cluster/src/cli/shutdown.rs index bed1eefd68..6bd3be809f 100644 --- a/crates/fluvio-cluster/src/cli/shutdown.rs +++ b/crates/fluvio-cluster/src/cli/shutdown.rs @@ -2,6 +2,7 @@ use std::fs::remove_file; use std::process::Command; use clap::Parser; +use fluvio::config::ConfigFile; use tracing::debug; use sysinfo::{ProcessExt, System, SystemExt}; @@ -11,17 +12,10 @@ use fluvio_command::CommandExt; use crate::render::ProgressRenderer; use crate::cli::ClusterCliError; use crate::progress::ProgressBarFactory; -use crate::{ClusterError, UninstallError}; +use crate::{ClusterError, UninstallError, InstallationType}; #[derive(Debug, Parser)] -pub struct ShutdownOpt { - /// shutdown local spu/sc - #[arg(long)] - local: bool, - - #[arg(long)] - no_k8: bool, -} +pub struct ShutdownOpt; impl ShutdownOpt { pub async fn process(self) -> Result<(), ClusterCliError> { @@ -35,19 +29,27 @@ impl ShutdownOpt { )) } }; + let config_file = ConfigFile::load_default_or_new()?; + let installation_type = + InstallationType::load_or_default(config_file.config().current_cluster()?); + debug!(?installation_type); + + match installation_type { + InstallationType::Local | InstallationType::LocalK8 | InstallationType::ReadOnly => { + Self::kill_local_processes(&installation_type, &pb).await?; + } + _ => { + pb.println("❌ Shutdown is only implemented for local clusters."); + } + }; - if self.local { - Self::kill_local_processes(&self, &pb).await?; - } else { - pb.println(concat!( - "❌ Shutdown is only implemented for local development.\n", - " Please provide '--local' to shutdown the local cluster.", - )); - } Ok(()) } - async fn kill_local_processes(&self, pb: &ProgressRenderer) -> Result<(), ClusterError> { + async fn kill_local_processes( + installation_type: &InstallationType, + pb: &ProgressRenderer, + ) -> Result<(), ClusterError> { pb.set_message("Uninstalling fluvio local components"); let kill_proc = |name: &str, command_args: Option<&[String]>| { @@ -79,8 +81,8 @@ impl ShutdownOpt { kill_proc("fluvio", Some(&["run".into()])); kill_proc("fluvio-run", None); - if !self.no_k8 { - let _ = self.remove_custom_objects("spus", true); + if let InstallationType::LocalK8 = installation_type { + let _ = Self::remove_custom_objects("spus", true); } // remove monitoring socket @@ -104,7 +106,7 @@ impl ShutdownOpt { } /// Remove objects of specified type, namespace - fn remove_custom_objects(&self, object_type: &str, force: bool) -> Result<(), UninstallError> { + fn remove_custom_objects(object_type: &str, force: bool) -> Result<(), UninstallError> { let mut cmd = Command::new("kubectl"); cmd.arg("delete"); cmd.arg(object_type); diff --git a/crates/fluvio-cluster/src/cli/start/local.rs b/crates/fluvio-cluster/src/cli/start/local.rs index c0da67cffa..03e381d38d 100644 --- a/crates/fluvio-cluster/src/cli/start/local.rs +++ b/crates/fluvio-cluster/src/cli/start/local.rs @@ -5,7 +5,6 @@ use fluvio::config::TlsPolicy; use crate::check::ClusterCheckError; use crate::cli::ClusterCliError; -use crate::start::local::LocalMode; use crate::{LocalInstaller, LocalConfig, LocalInstallError}; use super::StartOpt; @@ -41,13 +40,9 @@ pub async fn process_local( builder.skip_checks(true); } - let mode = match (opt.local, opt.local_k8, opt.read_only) { - (_, _, Some(path)) => LocalMode::ReadOnly(path), - (_, true, _) => LocalMode::LocalK8, - _ => LocalMode::Local, - }; + builder.installation_type(opt.installation_type.get()); - builder.mode(mode); + builder.read_only_config(opt.installation_type.read_only); let config = builder.build()?; let installer = LocalInstaller::from_config(config); diff --git a/crates/fluvio-cluster/src/cli/start/mod.rs b/crates/fluvio-cluster/src/cli/start/mod.rs index 996ec498f2..039b8ccbd4 100644 --- a/crates/fluvio-cluster/src/cli/start/mod.rs +++ b/crates/fluvio-cluster/src/cli/start/mod.rs @@ -1,7 +1,7 @@ use std::{fmt, str::FromStr}; use std::path::PathBuf; -use clap::Parser; +use clap::{Parser, Args}; use semver::Version; use anyhow::Result; @@ -15,6 +15,8 @@ mod tls; use tls::TlsOpt; +use crate::InstallationType; + #[cfg(target_os = "macos")] pub fn get_log_directory() -> &'static str { "/usr/local/var/log/fluvio" @@ -170,8 +172,15 @@ pub struct StartOpt { #[arg(long)] pub service_type: Option, + #[command(flatten)] + pub installation_type: IntallationTypeOpt, +} + +#[derive(Debug, Args)] +#[group(multiple = false)] +pub struct IntallationTypeOpt { /// install local spu/sc - #[arg(long, conflicts_with_all = &["k8", "local_k8", "read_only"])] + #[arg(long)] local: bool, /// install local spu/sc with metadata stored in K8s @@ -179,11 +188,11 @@ pub struct StartOpt { local_k8: bool, /// install on K8s - #[arg(long, default_value = "true", conflicts_with_all = &["local", "local_k8", "read_only"])] + #[arg(long, default_value = "true")] k8: bool, /// Start SC in read only mode - #[arg(long, conflicts_with_all = &["k8", "local", "local_k8"], value_name = "config path")] + #[arg(long, value_name = "config path")] read_only: Option, } @@ -195,7 +204,7 @@ impl StartOpt { if self.sys_only { process_sys(&self, upgrade)?; - } else if self.local || self.local_k8 || self.read_only.is_some() { + } else if self.installation_type.is_local_group() { process_local(self, platform_version).await?; } else { process_k8(self, platform_version, upgrade).await?; @@ -205,6 +214,21 @@ impl StartOpt { } } +impl IntallationTypeOpt { + fn is_local_group(&self) -> bool { + self.local || self.local_k8 || self.read_only.is_some() + } + + fn get(&self) -> InstallationType { + match (self.local, self.local_k8, &self.read_only) { + (true, _, _) => InstallationType::Local, + (_, true, _) => InstallationType::LocalK8, + (_, _, Some(_)) => InstallationType::ReadOnly, + _ => InstallationType::K8, + } + } +} + #[derive(Debug, Parser)] pub struct UpgradeOpt { #[clap(flatten)] diff --git a/crates/fluvio-cluster/src/delete.rs b/crates/fluvio-cluster/src/delete.rs index e48c8b4733..eb5abf018a 100644 --- a/crates/fluvio-cluster/src/delete.rs +++ b/crates/fluvio-cluster/src/delete.rs @@ -84,15 +84,14 @@ impl ClusterUninstaller { pub async fn uninstall(&self) -> Result<(), ClusterError> { if self.config.uninstall_k8 { self.uninstall_k8().await?; + if let Err(err) = self.cleanup_k8().await { + warn!("Cleanup failed: {}", err); + } } if self.config.uninstall_local { self.uninstall_local().await?; } - if let Err(err) = self.cleanup().await { - warn!("Cleanup failed: {}", err); - } - if self.config.uninstall_sys { self.uninstall_sys().await?; } @@ -213,10 +212,10 @@ impl ClusterUninstaller { Ok(()) } - /// Clean up objects and secrets created during the installation process + /// Clean up k8 objects and secrets created during the installation process /// /// Ignore any errors, cleanup should be idempotent - async fn cleanup(&self) -> Result<(), ClusterError> { + async fn cleanup_k8(&self) -> Result<(), ClusterError> { let pb = self.pb_factory.create()?; pb.set_message("Cleaning up objects and secrets created during the installation process"); let ns = &self.config.namespace; diff --git a/crates/fluvio-cluster/src/lib.rs b/crates/fluvio-cluster/src/lib.rs index 25c29e6ebe..e948552de1 100644 --- a/crates/fluvio-cluster/src/lib.rs +++ b/crates/fluvio-cluster/src/lib.rs @@ -50,15 +50,21 @@ pub use delete::*; pub use fluvio::config as fluvio_config; pub(crate) const DEFAULT_NAMESPACE: &str = "default"; +const INSTALLATION_METADATA_NAME: &str = "installation"; pub use common::*; mod common { + use std::str::FromStr; use std::{path::PathBuf, borrow::Cow}; use std::io::Error as IoError; + use fluvio::FluvioConfig; use fluvio::config::{TlsPaths, TlsConfig}; + use serde::{Serialize, Deserialize}; + + use crate::INSTALLATION_METADATA_NAME; /// The result of a successful startup of a Fluvio cluster /// @@ -137,4 +143,89 @@ mod common { }; Ok(cert_paths) } + + #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] + #[serde(rename_all = "snake_case")] + pub enum InstallationType { + #[default] + K8, + Local, + LocalK8, + ReadOnly, + } + + impl FromStr for InstallationType { + type Err = String; + + fn from_str(s: &str) -> Result { + if s.eq_ignore_ascii_case("k8") { + return Ok(Self::K8); + } + if s.eq_ignore_ascii_case("local") { + return Ok(Self::Local); + } + if s.eq_ignore_ascii_case("local-k8") { + return Ok(Self::LocalK8); + } + if s.eq_ignore_ascii_case("local_k8") { + return Ok(Self::LocalK8); + } + if s.eq_ignore_ascii_case("localk8") { + return Ok(Self::LocalK8); + } + if s.eq_ignore_ascii_case("read_only") { + return Ok(Self::ReadOnly); + } + if s.eq_ignore_ascii_case("read-only") { + return Ok(Self::ReadOnly); + } + if s.eq_ignore_ascii_case("readonly") { + return Ok(Self::ReadOnly); + } + Err(format!("unsupported instalaltion type '{s}'")) + } + } + + impl std::fmt::Display for InstallationType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } + } + + impl InstallationType { + pub fn load_or_default(config: &FluvioConfig) -> Self { + config + .query_metadata_by_name(INSTALLATION_METADATA_NAME) + .unwrap_or_default() + } + + pub fn save_to(&self, config: &mut FluvioConfig) -> anyhow::Result<()> { + config.update_metadata_by_name(INSTALLATION_METADATA_NAME, self) + } + } +} + +#[cfg(test)] +mod tests { + use fluvio::FluvioConfig; + + use super::*; + + #[test] + fn test_installation_in_config_load_and_update() { + //given + let mut config = FluvioConfig::new("test"); + let installation = InstallationType::Local; + + //when + assert_eq!( + InstallationType::load_or_default(&config), + InstallationType::K8 + ); + + installation.save_to(&mut config).expect("saved"); + + //then + assert_eq!(InstallationType::load_or_default(&config), installation); + } } diff --git a/crates/fluvio-cluster/src/start/k8.rs b/crates/fluvio-cluster/src/start/k8.rs index 7799025d89..b54112ea2b 100644 --- a/crates/fluvio-cluster/src/start/k8.rs +++ b/crates/fluvio-cluster/src/start/k8.rs @@ -39,6 +39,7 @@ use k8_types::core::service::{LoadBalancerType, ServiceSpec, TargetPort}; use k8_types::core::node::{NodeSpec, NodeAddress}; use fluvio_command::CommandExt; +use crate::InstallationType; use crate::check::ClusterCheckError; use crate::check::{AlreadyInstalled, SysChartCheck}; use crate::error::K8InstallError; @@ -1273,6 +1274,10 @@ impl ClusterInstaller { external_addr, &self.config.client_tls_policy, )?; + let config = config_file.mut_config().current_cluster_mut()?; + InstallationType::K8.save_to(config)?; + config_file.save()?; + pb.println(InstallProgressMessage::ProfileSet.msg()); pb.finish_and_clear(); Ok(()) diff --git a/crates/fluvio-cluster/src/start/local.rs b/crates/fluvio-cluster/src/start/local.rs index 0c5604af3e..4c78f6369e 100644 --- a/crates/fluvio-cluster/src/start/local.rs +++ b/crates/fluvio-cluster/src/start/local.rs @@ -18,7 +18,7 @@ use k8_types::{InputK8Obj, InputObjectMeta}; use k8_client::SharedK8Client; use crate::render::{ProgressRenderedText, ProgressRenderer}; -use crate::{ClusterChecker, LocalInstallError, StartStatus, UserChartLocation}; +use crate::{ClusterChecker, LocalInstallError, StartStatus, UserChartLocation, InstallationType}; use crate::charts::ChartConfig; use crate::check::{SysChartCheck, ClusterCheckError}; use crate::runtime::local::{LocalSpuProcessClusterManager, ScProcess, ScMode}; @@ -29,10 +29,10 @@ use super::common::check_crd; pub static DEFAULT_DATA_DIR: Lazy> = Lazy::new(|| directories::BaseDirs::new().map(|it| it.home_dir().join(".fluvio/data"))); +pub const DEFAULT_METADATA_SUB_DIR: &str = "metadata"; const DEFAULT_LOG_DIR: &str = "/tmp"; const DEFAULT_RUST_LOG: &str = "info"; -const DEFAULT_METADATA_SUB_DIR: &str = "metadata"; const DEFAULT_SPU_REPLICAS: u16 = 1; const DEFAULT_TLS_POLICY: TlsPolicy = TlsPolicy::Disabled; const LOCAL_SC_ADDRESS: &str = "localhost:9003"; @@ -168,16 +168,10 @@ pub struct LocalConfig { #[builder(default = "true")] hide_spinner: bool, - #[builder(default)] - mode: LocalMode, -} + installation_type: InstallationType, -#[derive(Debug, Default, Clone)] -pub enum LocalMode { - Local, - #[default] - LocalK8, - ReadOnly(PathBuf), + #[builder(default)] + read_only_config: Option, } impl LocalConfig { @@ -361,8 +355,8 @@ impl LocalInstaller { /// Checks if all of the prerequisites for installing Fluvio locally are met /// and tries to auto-fix the issues observed pub async fn preflight_check(&self, fix: bool) -> Result<(), ClusterCheckError> { - match &self.config.mode { - LocalMode::Local | LocalMode::ReadOnly(_) => { + match &self.config.installation_type { + InstallationType::Local | InstallationType::ReadOnly => { self.pb_factory .println(InstallProgressMessage::PreFlightCheck.msg()); @@ -373,7 +367,7 @@ impl LocalInstaller { Ok(()) } - LocalMode::LocalK8 => { + InstallationType::LocalK8 => { let mut sys_config: ChartConfig = ChartConfig::sys_builder() .version(self.config.chart_version.clone()) .build() @@ -395,6 +389,9 @@ impl LocalInstaller { .await?; Ok(()) } + InstallationType::K8 => Err(ClusterCheckError::Other( + "Installation type K8 is not supported for local clusters".to_string(), + )), } } @@ -418,7 +415,7 @@ impl LocalInstaller { })?; } - let maybe_k8_client = if let LocalMode::LocalK8 = self.config.mode { + let maybe_k8_client = if let InstallationType::LocalK8 = self.config.installation_type { use k8_client::load_and_share; Some(load_and_share()?) } else { @@ -488,10 +485,14 @@ impl LocalInstaller { pb.set_message(InstallProgressMessage::LaunchingSC.msg()); - let mode = match &self.config.mode { - LocalMode::Local => ScMode::Local(self.config.data_dir.join(DEFAULT_METADATA_SUB_DIR)), - LocalMode::LocalK8 => ScMode::K8s, - LocalMode::ReadOnly(path) => ScMode::ReadOnly(path.clone()), + let mode = match &self.config.installation_type { + InstallationType::Local => { + ScMode::Local(self.config.data_dir.join(DEFAULT_METADATA_SUB_DIR)) + } + InstallationType::LocalK8 | InstallationType::K8 => ScMode::K8s, + InstallationType::ReadOnly => { + ScMode::ReadOnly(self.config.read_only_config.clone().unwrap_or_default()) + } }; let sc_process = ScProcess { @@ -532,6 +533,9 @@ impl LocalInstaller { LOCAL_SC_ADDRESS, &self.config.client_tls_policy, )?; + let config = config_file.mut_config().current_cluster_mut()?; + self.config.installation_type.save_to(config)?; + config_file.save()?; pb.println(InstallProgressMessage::ProfileSet.msg()); diff --git a/crates/fluvio-spu/Makefile b/crates/fluvio-spu/Makefile index 19cb28b5d3..fa8503babb 100644 --- a/crates/fluvio-spu/Makefile +++ b/crates/fluvio-spu/Makefile @@ -7,7 +7,7 @@ fluvio: # make -f src/spu/Makefile test_replica test_replica: fluvio - $(FLUVIO_BIN) cluster delete --local + $(FLUVIO_BIN) cluster delete $(FLUVIO_BIN) cluster start --spu $(SPU) --local --develop --rust-log=fluvio_spu=debug $(FLUVIO_BIN) topic create test --replication $(REPLICATION) echo "hello world" | $(FLUVIO_BIN) produce test diff --git a/crates/fluvio-test-util/setup/environment/local.rs b/crates/fluvio-test-util/setup/environment/local.rs index bcee1c17e3..c79461b6ec 100644 --- a/crates/fluvio-test-util/setup/environment/local.rs +++ b/crates/fluvio-test-util/setup/environment/local.rs @@ -2,7 +2,9 @@ use async_trait::async_trait; use crate::tls::load_tls; use crate::test_meta::environment::{EnvironmentSetup, EnvDetail}; -use fluvio_cluster::{LocalConfig, LocalInstaller, StartStatus, ClusterUninstallConfig}; +use fluvio_cluster::{ + LocalConfig, LocalInstaller, StartStatus, ClusterUninstallConfig, InstallationType, +}; use super::EnvironmentDriver; @@ -45,6 +47,7 @@ impl LocalEnvDriver { let (client, server) = load_tls(&option.tls_user()); builder.tls(client, server); } + builder.installation_type(InstallationType::Local); builder.build().expect("should build LocalConfig") } diff --git a/crates/fluvio/src/config/config.rs b/crates/fluvio/src/config/config.rs index 0cbf7190a6..0c16be911c 100644 --- a/crates/fluvio/src/config/config.rs +++ b/crates/fluvio/src/config/config.rs @@ -395,6 +395,17 @@ impl Config { Ok(cluster) } + /// Returns the mutable reference to FluvioConfig belonging to the current profile. + pub fn current_cluster_mut(&mut self) -> Result<&mut FluvioConfig, FluvioError> { + let profile = self.current_profile()?.clone(); + let maybe_cluster = self.cluster.get_mut(&profile.cluster); + let cluster = maybe_cluster.ok_or_else(|| { + let profile = profile.cluster; + ConfigError::NoClusterForProfile { profile } + })?; + Ok(cluster) + } + /// Returns the FluvioConfig belonging to the named profile. pub fn cluster_with_profile(&self, profile_name: &str) -> Option<&FluvioConfig> { self.profile diff --git a/tests/cli/fluvio_read_only/basic.bats b/tests/cli/fluvio_read_only/basic.bats index f3a3227e1d..f85c4e0b63 100644 --- a/tests/cli/fluvio_read_only/basic.bats +++ b/tests/cli/fluvio_read_only/basic.bats @@ -22,7 +22,7 @@ setup_file() { } teardown_file() { - run timeout 15s "$FLUVIO_BIN" cluster shutdown --local + run timeout 15s "$FLUVIO_BIN" cluster shutdown } @test "Cannot create a new topic" { diff --git a/tls/Makefile b/tls/Makefile index 00dc974e37..c45c3aa221 100644 --- a/tls/Makefile +++ b/tls/Makefile @@ -29,7 +29,7 @@ install-local-tls: --client-key tls/certs/client-root.key --domain fluvio.local uninstall-local: - $(FLUVIO_BIN) cluster delete --local + $(FLUVIO_BIN) cluster delete install-k8-tls: $(FLUVIO_BIN) cluster start --develop \