diff --git a/CHANGELOG.md b/CHANGELOG.md index 68df4c2..dfc4c42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,10 @@ Released on +- [Issue 268](https://github.com/veeso/termscp/issues/268): Pods and container explorer for Kube protocol. + - BREAKING ‼️ Kube address argument has changed; see manual! + - Pod and container argumets have been removed; from now on you will connect with the following syntax to the provided namespace: `/pod-name/container-name/path/to/file` + ## 0.14.0 Released on 17/07/2024 diff --git a/Cargo.lock b/Cargo.lock index f1dc1f1..0346006 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -568,6 +568,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "dbus-secret-service" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1caa0c241c01ad8d99a78d553567d38f873dd3ac16eca33a5370d650ab25584e" +dependencies = [ + "dbus", + "futures-util", + "num", + "once_cell", + "rand", +] + [[package]] name = "debug-helper" version = "0.3.13" @@ -1450,6 +1463,12 @@ name = "keyring" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fa83d1ca02db069b5fbe94b23b584d588e989218310c9c15015bb5571ef1a94" +dependencies = [ + "byteorder", + "dbus-secret-service", + "security-framework", + "windows-sys 0.59.0", +] [[package]] name = "kqueue" @@ -1809,12 +1828,76 @@ dependencies = [ "tauri-winrt-notification", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" diff --git a/Cargo.toml b/Cargo.toml index 5fdb62d..40fdc20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ dirs = "^5.0" edit = "^0.1" filetime = "^0.2" hostname = "^0.4" -keyring = { version = "^3", optional = true } +keyring = { version = "^3", optional = true, features = ["apple-native", "windows-native", "sync-secret-service"] } lazy-regex = "^3" lazy_static = "^1" log = "^0.4" diff --git a/docs/de/man.md b/docs/de/man.md index 6569698..e4b731b 100644 --- a/docs/de/man.md +++ b/docs/de/man.md @@ -133,7 +133,7 @@ s3://buckethead@eu-central-1:default:/assets Falls Sie eine Verbindung zu Kube herstellen möchten, verwenden Sie die folgende Syntax ```txt -kube://@ +kube://[namespace][@][$] ``` #### SMB Adressargument diff --git a/docs/es/man.md b/docs/es/man.md index cceaad1..81788a6 100644 --- a/docs/es/man.md +++ b/docs/es/man.md @@ -110,7 +110,7 @@ s3://buckethead@eu-central-1:default:/assets En caso de que quieras conectarte a Kube, utiliza la siguiente sintaxis ```txt -kube://@ +kube://[namespace][@][$] ``` #### Argumento de dirección de WebDAV diff --git a/docs/fr/man.md b/docs/fr/man.md index 8e7e3c5..562a543 100644 --- a/docs/fr/man.md +++ b/docs/fr/man.md @@ -108,7 +108,7 @@ s3://buckethead@eu-central-1:default:/assets Si vous souhaitez vous connecter à Kube, utilisez la syntaxe suivante ```txt -kube://@ +kube://[namespace][@][$] ``` #### Argument d'adresse WebDAV diff --git a/docs/it/man.md b/docs/it/man.md index 93d7c80..fe4e663 100644 --- a/docs/it/man.md +++ b/docs/it/man.md @@ -106,7 +106,7 @@ s3://buckethead@eu-central-1:default:/assets Nel caso tu voglia connetterti a Kube usa la seguente sintassi ```txt -kube://@ +kube://[namespace][@][$] ``` #### Argomento indirizzo per WebDAV diff --git a/docs/man.md b/docs/man.md index a89996d..b37525a 100644 --- a/docs/man.md +++ b/docs/man.md @@ -111,7 +111,7 @@ s3://buckethead@eu-central-1:default:/assets In case you want to connect to Kube use the following syntax ```txt -kube://@ +kube://[namespace][@][$] ``` #### WebDAV address argument diff --git a/docs/ptbr/man.md b/docs/ptbr/man.md index 6f0d5b1..64da190 100644 --- a/docs/ptbr/man.md +++ b/docs/ptbr/man.md @@ -111,7 +111,7 @@ s3://buckethead@eu-central-1:default:/assets Caso queira se conectar ao Kube, use a seguinte sintaxe ```txt -kube://@ +kube://[namespace][@][$] ``` #### Argumento de Endereço do WebDAV diff --git a/docs/zh-CN/man.md b/docs/zh-CN/man.md index 2c8a3ff..9512e3e 100644 --- a/docs/zh-CN/man.md +++ b/docs/zh-CN/man.md @@ -108,7 +108,7 @@ s3://buckethead@eu-central-1:default:/assets 如果您想连接到 Kube,请使用以下语法 ```txt -kube://@ +kube://[namespace][@][$] ``` #### WebDAV 地址参数 diff --git a/src/config/bookmarks.rs b/src/config/bookmarks.rs index 53161d0..8e422b8 100644 --- a/src/config/bookmarks.rs +++ b/src/config/bookmarks.rs @@ -351,8 +351,6 @@ mod tests { #[test] fn bookmark_from_kube_ftparams() { let params = ProtocolParams::Kube(KubeProtocolParams { - pod: "pod".to_string(), - container: "container".to_string(), namespace: Some("default".to_string()), username: Some("root".to_string()), cluster_url: Some("https://localhost:6443".to_string()), @@ -368,8 +366,6 @@ mod tests { assert!(bookmark.username.is_none()); assert!(bookmark.password.is_none()); let kube: &KubeParams = bookmark.kube.as_ref().unwrap(); - assert_eq!(kube.pod_name.as_str(), "pod"); - assert_eq!(kube.container.as_str(), "container"); assert_eq!(kube.namespace.as_deref().unwrap(), "default"); assert_eq!( kube.cluster_url.as_deref().unwrap(), @@ -494,8 +490,6 @@ mod tests { remote_path: Some(PathBuf::from("/tmp")), local_path: Some(PathBuf::from("/usr")), kube: Some(KubeParams { - pod_name: String::from("pod"), - container: String::from("container"), namespace: Some(String::from("default")), cluster_url: Some(String::from("https://localhost:6443")), username: Some(String::from("root")), @@ -516,7 +510,6 @@ mod tests { std::path::Path::new("/usr") ); let gparams = params.params.kube_params().unwrap(); - assert_eq!(gparams.pod.as_str(), "pod"); assert_eq!(gparams.namespace.as_deref().unwrap(), "default"); assert_eq!( gparams.cluster_url.as_deref().unwrap(), diff --git a/src/config/bookmarks/kube.rs b/src/config/bookmarks/kube.rs index ed26c2a..25c9647 100644 --- a/src/config/bookmarks/kube.rs +++ b/src/config/bookmarks/kube.rs @@ -5,8 +5,6 @@ use crate::filetransfer::params::KubeProtocolParams; /// Extra Connection parameters for Kube protocol #[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Default)] pub struct KubeParams { - pub pod_name: String, - pub container: String, pub namespace: Option, pub cluster_url: Option, pub username: Option, @@ -17,8 +15,6 @@ pub struct KubeParams { impl From for KubeProtocolParams { fn from(value: KubeParams) -> Self { Self { - pod: value.pod_name, - container: value.container, namespace: value.namespace, cluster_url: value.cluster_url, username: value.username, @@ -31,8 +27,6 @@ impl From for KubeProtocolParams { impl From for KubeParams { fn from(value: KubeProtocolParams) -> Self { Self { - pod_name: value.pod, - container: value.container, namespace: value.namespace, cluster_url: value.cluster_url, username: value.username, diff --git a/src/config/serialization.rs b/src/config/serialization.rs index 8a82438..12d4be4 100644 --- a/src/config/serialization.rs +++ b/src/config/serialization.rs @@ -412,8 +412,6 @@ mod tests { assert_eq!(host.password, None); assert_eq!(host.protocol, FileTransferProtocol::Kube); let kube = host.kube.as_ref().unwrap(); - assert_eq!(kube.pod_name.as_str(), "my-pod"); - assert_eq!(kube.container.as_str(), "my-container"); assert_eq!(kube.namespace.as_deref().unwrap(), "my-namespace"); assert_eq!(kube.cluster_url.as_deref().unwrap(), "https://my-cluster"); assert_eq!(kube.username.as_deref().unwrap(), "my-username"); @@ -515,8 +513,6 @@ mod tests { s3: None, smb: None, kube: Some(KubeParams { - pod_name: "my-pod".to_string(), - container: "my-container".to_string(), namespace: Some("my-namespace".to_string()), cluster_url: Some("https://my-cluster".to_string()), username: Some("my-username".to_string()), @@ -593,6 +589,22 @@ mod tests { assert!(deserialize::(Box::new(toml_file)).is_err()); } + #[test] + fn test_should_deserialize_v14_pod_bookmark() { + let toml = create_v14_pod_bookmark(); + toml.as_file().sync_all().unwrap(); + toml.as_file().rewind().unwrap(); + let deserialized: UserHosts = deserialize(Box::new(toml)).unwrap(); + let kube = deserialized.bookmarks.get("pod").unwrap(); + assert_eq!(kube.protocol, FileTransferProtocol::Kube); + let kube = kube.kube.as_ref().unwrap(); + assert_eq!(kube.namespace.as_deref().unwrap(), "my-namespace"); + assert_eq!(kube.cluster_url.as_deref().unwrap(), "https://my-cluster"); + assert_eq!(kube.username.as_deref().unwrap(), "my-username"); + assert_eq!(kube.client_cert.as_deref().unwrap(), "my-cert"); + assert_eq!(kube.client_key.as_deref().unwrap(), "my-key"); + } + fn create_good_toml_bookmarks() -> tempfile::NamedTempFile { // Write let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap(); @@ -617,8 +629,6 @@ mod tests { [bookmarks.pod] protocol = "KUBE" [bookmarks.pod.kube] - pod_name = "my-pod" - container = "my-container" namespace = "my-namespace" cluster_url = "https://my-cluster" username = "my-username" @@ -644,6 +654,29 @@ mod tests { tmpfile } + fn create_v14_pod_bookmark() -> tempfile::NamedTempFile { + let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap(); + let file_content: &str = r#" + [bookmarks] + + [bookmarks.pod] + protocol = "KUBE" + [bookmarks.pod.kube] + pod_name = "my-pod" + container = "my-container" + namespace = "my-namespace" + cluster_url = "https://my-cluster" + username = "my-username" + client_cert = "my-cert" + client_key = "my-key" + + [recents] + "#; + tmpfile.write_all(file_content.as_bytes()).unwrap(); + //write!(tmpfile, "[bookmarks]\nraspberrypi2 = {{ address = \"192.168.1.31\", port = 22, protocol = \"SFTP\", username = \"root\" }}\nmsi-estrem = {{ address = \"192.168.1.30\", port = 22, protocol = \"SFTP\", username = \"cvisintin\" }}\naws-server-prod1 = {{ address = \"51.23.67.12\", port = 21, protocol = \"FTPS\", username = \"aws001\" }}\n\n[recents]\nISO20201215T094000Z = {{ address = \"172.16.104.10\", port = 22, protocol = \"SCP\", username = \"root\" }}\n"); + tmpfile + } + fn create_bad_toml_bookmarks() -> tempfile::NamedTempFile { // Write let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap(); diff --git a/src/filetransfer/builder.rs b/src/filetransfer/builder.rs index 620ec8f..1845281 100644 --- a/src/filetransfer/builder.rs +++ b/src/filetransfer/builder.rs @@ -8,7 +8,7 @@ use std::sync::Arc; use remotefs::RemoteFs; use remotefs_aws_s3::AwsS3Fs; use remotefs_ftp::FtpFs; -use remotefs_kube::KubeContainerFs as KubeFs; +use remotefs_kube::KubeMultiPodFs as KubeFs; #[cfg(smb_unix)] use remotefs_smb::SmbOptions; #[cfg(smb)] @@ -119,7 +119,7 @@ impl Builder { .build() .expect("Unable to create tokio runtime"), ); - let kube_fs = KubeFs::new(¶ms.pod, ¶ms.container, &rt); + let kube_fs = KubeFs::new(&rt); if let Some(config) = params.config() { kube_fs.config(config) } else { @@ -281,8 +281,6 @@ mod test { #[test] fn test_should_build_kube_fs() { let params = ProtocolParams::Kube(KubeProtocolParams { - pod: "pod".to_string(), - container: "container".to_string(), namespace: Some("namespace".to_string()), cluster_url: Some("cluster_url".to_string()), username: Some("username".to_string()), diff --git a/src/filetransfer/params/kube.rs b/src/filetransfer/params/kube.rs index ce2aa13..c9ac991 100644 --- a/src/filetransfer/params/kube.rs +++ b/src/filetransfer/params/kube.rs @@ -3,8 +3,6 @@ use remotefs_kube::Config; /// Protocol params used by WebDAV #[derive(Debug, Clone)] pub struct KubeProtocolParams { - pub pod: String, - pub container: String, pub namespace: Option, pub cluster_url: Option, pub username: Option, diff --git a/src/system/keys/keyringstorage.rs b/src/system/keys/keyringstorage.rs index 002f56c..20f2486 100644 --- a/src/system/keys/keyringstorage.rs +++ b/src/system/keys/keyringstorage.rs @@ -76,16 +76,12 @@ impl KeyStorage for KeyringStorage { #[cfg(test)] mod tests { - #[cfg(linux)] use pretty_assertions::assert_eq; - #[cfg(linux)] use whoami::username; - #[cfg(linux)] use super::*; #[test] - #[cfg(linux)] fn test_system_keys_keyringstorage() { let username: String = username(); let storage: KeyringStorage = KeyringStorage::new(username.as_str()); diff --git a/src/ui/activities/auth/bookmarks.rs b/src/ui/activities/auth/bookmarks.rs index 67f9d1a..fae5c6e 100644 --- a/src/ui/activities/auth/bookmarks.rs +++ b/src/ui/activities/auth/bookmarks.rs @@ -193,8 +193,6 @@ impl AuthActivity { } fn load_bookmark_kube_into_gui(&mut self, params: KubeProtocolParams) { - self.mount_kube_pod_name(params.pod.as_str()); - self.mount_kube_container(¶ms.container); self.mount_kube_cluster_url(params.cluster_url.as_deref().unwrap_or("")); self.mount_kube_namespace(params.namespace.as_deref().unwrap_or("")); self.mount_kube_client_cert(params.client_cert.as_deref().unwrap_or("")); diff --git a/src/ui/activities/auth/components/form.rs b/src/ui/activities/auth/components/form.rs index b813c2e..d37e5e9 100644 --- a/src/ui/activities/auth/components/form.rs +++ b/src/ui/activities/auth/components/form.rs @@ -832,40 +832,6 @@ impl Component for InputWebDAVUri { // kube -#[derive(MockComponent)] -pub struct InputKubePodName { - component: Input, -} - -impl InputKubePodName { - pub fn new(bucket: &str, color: Color) -> Self { - Self { - component: Input::default() - .borders( - Borders::default() - .color(color) - .modifiers(BorderType::Rounded), - ) - .foreground(color) - .placeholder("pod-name", Style::default().fg(Color::Rgb(128, 128, 128))) - .title("Pod name", Alignment::Left) - .input_type(InputType::Text) - .value(bucket), - } - } -} - -impl Component for InputKubePodName { - fn on(&mut self, ev: Event) -> Option { - handle_input_ev( - self, - ev, - Msg::Ui(UiMsg::KubePodNameBlurDown), - Msg::Ui(UiMsg::KubePodNameBlurUp), - ) - } -} - #[derive(MockComponent)] pub struct InputKubeNamespace { component: Input, @@ -937,40 +903,6 @@ impl Component for InputKubeClusterUrl { } } -#[derive(MockComponent)] -pub struct InputKubeContainer { - component: Input, -} - -impl InputKubeContainer { - pub fn new(bucket: &str, color: Color) -> Self { - Self { - component: Input::default() - .borders( - Borders::default() - .color(color) - .modifiers(BorderType::Rounded), - ) - .foreground(color) - .placeholder("container", Style::default().fg(Color::Rgb(128, 128, 128))) - .title("Kube container", Alignment::Left) - .input_type(InputType::Text) - .value(bucket), - } - } -} - -impl Component for InputKubeContainer { - fn on(&mut self, ev: Event) -> Option { - handle_input_ev( - self, - ev, - Msg::Ui(UiMsg::KubeContainerBlurDown), - Msg::Ui(UiMsg::KubeContainerBlurUp), - ) - } -} - #[derive(MockComponent)] pub struct InputKubeUsername { component: Input, diff --git a/src/ui/activities/auth/components/mod.rs b/src/ui/activities/auth/components/mod.rs index 2d875f0..75c5ae5 100644 --- a/src/ui/activities/auth/components/mod.rs +++ b/src/ui/activities/auth/components/mod.rs @@ -16,12 +16,11 @@ pub use bookmarks::{ #[cfg(unix)] pub use form::InputSmbWorkgroup; pub use form::{ - InputAddress, InputKubeClientCert, InputKubeClientKey, InputKubeClusterUrl, InputKubeContainer, - InputKubeNamespace, InputKubePodName, InputKubeUsername, InputLocalDirectory, InputPassword, - InputPort, InputRemoteDirectory, InputS3AccessKey, InputS3Bucket, InputS3Endpoint, - InputS3Profile, InputS3Region, InputS3SecretAccessKey, InputS3SecurityToken, - InputS3SessionToken, InputSmbShare, InputUsername, InputWebDAVUri, ProtocolRadio, - RadioS3NewPathStyle, + InputAddress, InputKubeClientCert, InputKubeClientKey, InputKubeClusterUrl, InputKubeNamespace, + InputKubeUsername, InputLocalDirectory, InputPassword, InputPort, InputRemoteDirectory, + InputS3AccessKey, InputS3Bucket, InputS3Endpoint, InputS3Profile, InputS3Region, + InputS3SecretAccessKey, InputS3SecurityToken, InputS3SessionToken, InputSmbShare, + InputUsername, InputWebDAVUri, ProtocolRadio, RadioS3NewPathStyle, }; pub use popup::{ ErrorPopup, InfoPopup, InstallUpdatePopup, Keybindings, QuitPopup, ReleaseNotes, WaitPopup, diff --git a/src/ui/activities/auth/misc.rs b/src/ui/activities/auth/misc.rs index c3b9790..a9da774 100644 --- a/src/ui/activities/auth/misc.rs +++ b/src/ui/activities/auth/misc.rs @@ -85,9 +85,7 @@ impl AuthActivity { /// Get input values from fields or return an error if fields are invalid to work as aws s3 pub(super) fn collect_kube_host_params(&self) -> Result { let params = self.get_kube_params_input(); - if params.pod.is_empty() { - return Err("Invalid pod name"); - } + Ok(FileTransferParams { protocol: FileTransferProtocol::Kube, params: ProtocolParams::Kube(params), diff --git a/src/ui/activities/auth/mod.rs b/src/ui/activities/auth/mod.rs index de095ca..cebf5ec 100644 --- a/src/ui/activities/auth/mod.rs +++ b/src/ui/activities/auth/mod.rs @@ -48,8 +48,6 @@ pub enum Id { InfoPopup, InstallUpdatePopup, Keybindings, - KubePodName, - KubeContainer, KubeNamespace, KubeClusterUrl, KubeUsername, @@ -119,10 +117,6 @@ pub enum UiMsg { CloseKeybindingsPopup, CloseQuitPopup, CloseSaveBookmark, - KubePodNameBlurDown, - KubePodNameBlurUp, - KubeContainerBlurDown, - KubeContainerBlurUp, KubeNamespaceBlurDown, KubeNamespaceBlurUp, KubeClusterUrlBlurDown, diff --git a/src/ui/activities/auth/update.rs b/src/ui/activities/auth/update.rs index 930b7aa..79adde7 100644 --- a/src/ui/activities/auth/update.rs +++ b/src/ui/activities/auth/update.rs @@ -70,7 +70,7 @@ impl AuthActivity { InputMask::Generic => &Id::Password, InputMask::Smb => &Id::Password, InputMask::AwsS3 => &Id::S3Bucket, - InputMask::Kube => &Id::KubePodName, + InputMask::Kube => &Id::KubeNamespace, InputMask::WebDAV => &Id::Password, }) .is_ok()); @@ -84,7 +84,7 @@ impl AuthActivity { InputMask::Generic => &Id::Password, InputMask::Smb => &Id::Password, InputMask::AwsS3 => &Id::S3Bucket, - InputMask::Kube => &Id::KubePodName, + InputMask::Kube => &Id::KubeNamespace, InputMask::WebDAV => &Id::Password, }) .is_ok()); @@ -210,7 +210,7 @@ impl AuthActivity { InputMask::Generic => &Id::Address, InputMask::Smb => &Id::Address, InputMask::AwsS3 => &Id::S3Bucket, - InputMask::Kube => &Id::KubePodName, + InputMask::Kube => &Id::KubeNamespace, InputMask::WebDAV => &Id::WebDAVUri, }) .is_ok()); @@ -305,23 +305,11 @@ impl AuthActivity { UiMsg::KubeClientKeyBlurUp => { assert!(self.app.active(&Id::KubeClientCert).is_ok()); } - UiMsg::KubeContainerBlurDown => { - assert!(self.app.active(&Id::KubeNamespace).is_ok()); - } - UiMsg::KubeContainerBlurUp => { - assert!(self.app.active(&Id::KubePodName).is_ok()); - } - UiMsg::KubePodNameBlurDown => { - assert!(self.app.active(&Id::KubeContainer).is_ok()); - } - UiMsg::KubePodNameBlurUp => { - assert!(self.app.active(&Id::Protocol).is_ok()); - } UiMsg::KubeNamespaceBlurDown => { assert!(self.app.active(&Id::KubeClusterUrl).is_ok()); } UiMsg::KubeNamespaceBlurUp => { - assert!(self.app.active(&Id::KubeContainer).is_ok()); + assert!(self.app.active(&Id::Protocol).is_ok()); } UiMsg::KubeClusterUrlBlurDown => { assert!(self.app.active(&Id::KubeUsername).is_ok()); diff --git a/src/ui/activities/auth/view.rs b/src/ui/activities/auth/view.rs index 44ab3d1..fc93707 100644 --- a/src/ui/activities/auth/view.rs +++ b/src/ui/activities/auth/view.rs @@ -64,9 +64,7 @@ impl AuthActivity { self.mount_kube_client_cert(""); self.mount_kube_client_key(""); self.mount_kube_cluster_url(""); - self.mount_kube_container(""); self.mount_kube_namespace(""); - self.mount_kube_pod_name(""); self.mount_kube_username(""); self.mount_smb_share(""); #[cfg(unix)] @@ -748,30 +746,6 @@ impl AuthActivity { .is_ok()); } - pub(super) fn mount_kube_pod_name(&mut self, value: &str) { - let color = self.theme().auth_address; - assert!(self - .app - .remount( - Id::KubePodName, - Box::new(components::InputKubePodName::new(value, color)), - vec![] - ) - .is_ok()); - } - - pub(super) fn mount_kube_container(&mut self, value: &str) { - let color = self.theme().auth_password; - assert!(self - .app - .remount( - Id::KubeContainer, - Box::new(components::InputKubeContainer::new(value, color)), - vec![] - ) - .is_ok()); - } - pub(super) fn mount_kube_namespace(&mut self, value: &str) { let color = self.theme().auth_port; assert!(self @@ -906,16 +880,12 @@ impl AuthActivity { /// Collect s3 input values from view pub(super) fn get_kube_params_input(&self) -> KubeProtocolParams { - let pod = self.get_input_kube_pod_name(); - let container = self.get_input_kube_container(); let namespace = self.get_input_kube_namespace(); let cluster_url = self.get_input_kube_cluster_url(); let username = self.get_input_kube_username(); let client_cert = self.get_input_kube_client_cert(); let client_key = self.get_input_kube_client_key(); KubeProtocolParams { - pod, - container, namespace, cluster_url, username, @@ -1083,20 +1053,6 @@ impl AuthActivity { ) } - pub(super) fn get_input_kube_pod_name(&self) -> String { - match self.app.state(&Id::KubePodName) { - Ok(State::One(StateValue::String(x))) => x, - _ => String::new(), - } - } - - pub(super) fn get_input_kube_container(&self) -> String { - match self.app.state(&Id::KubeContainer) { - Ok(State::One(StateValue::String(x))) => x, - _ => String::new(), - } - } - pub(super) fn get_input_kube_namespace(&self) -> Option { match self.app.state(&Id::KubeNamespace) { Ok(State::One(StateValue::String(x))) if !x.is_empty() => Some(x), @@ -1214,15 +1170,13 @@ impl AuthActivity { } ProtocolParams::Kube(params) => { format!( - "{}://{}@{}{}{}", + "{}://{}{}", protocol, - params.container, - params.pod, params .namespace .as_deref() .map(|x| format!("/{x}")) - .unwrap_or_default(), + .unwrap_or_else(|| String::from("default")), params .cluster_url .as_deref() @@ -1318,18 +1272,6 @@ impl AuthActivity { /// Get the visible element in the kube form, based on current focus fn get_kube_view(&self) -> [Id; 4] { match self.app.focus() { - Some(&Id::KubePodName) => [ - Id::KubePodName, - Id::KubeContainer, - Id::KubeNamespace, - Id::KubeClusterUrl, - ], - Some(&Id::KubeUsername) => [ - Id::KubeContainer, - Id::KubeNamespace, - Id::KubeClusterUrl, - Id::KubeUsername, - ], Some(&Id::KubeClientCert) => [ Id::KubeNamespace, Id::KubeClusterUrl, @@ -1355,10 +1297,10 @@ impl AuthActivity { Id::LocalDirectory, ], _ => [ - Id::KubePodName, - Id::KubeContainer, Id::KubeNamespace, Id::KubeClusterUrl, + Id::KubeUsername, + Id::KubeClientCert, ], } } diff --git a/src/ui/activities/filetransfer/misc.rs b/src/ui/activities/filetransfer/misc.rs index e61613e..52aaae0 100644 --- a/src/ui/activities/filetransfer/misc.rs +++ b/src/ui/activities/filetransfer/misc.rs @@ -111,7 +111,9 @@ impl FileTransferActivity { match &ft_params.params { ProtocolParams::Generic(params) => params.address.clone(), ProtocolParams::AwsS3(params) => params.bucket_name.clone(), - ProtocolParams::Kube(params) => params.pod.clone(), + ProtocolParams::Kube(params) => { + params.namespace.clone().unwrap_or("default".to_string()) + } ProtocolParams::Smb(params) => params.address.clone(), ProtocolParams::WebDAV(params) => params.uri.clone(), } @@ -137,11 +139,9 @@ impl FileTransferActivity { format!("Connecting to {}…", params.bucket_name) } ProtocolParams::Kube(params) => { - info!( - "Client is not connected to remote; connecting to pod {}", - params.pod, - ); - format!("Connecting to {}…", params.pod) + let namespace = params.namespace.as_deref().unwrap_or("default"); + info!("Client is not connected to remote; connecting to namespace {namespace}",); + format!("Connecting to Kube namespace {namespace}…",) } ProtocolParams::Smb(params) => { info!( diff --git a/src/ui/activities/filetransfer/session.rs b/src/ui/activities/filetransfer/session.rs index f8541eb..420e4cf 100644 --- a/src/ui/activities/filetransfer/session.rs +++ b/src/ui/activities/filetransfer/session.rs @@ -57,7 +57,11 @@ impl FileTransferActivity { // Connect to remote match self.client.connect() { Ok(Welcome { banner, .. }) => { - self.connected = true; + self.connected = self.client.is_connected(); + if !self.connected { + return; + } + if let Some(banner) = banner { // Log welcome self.log( @@ -68,6 +72,15 @@ impl FileTransferActivity { banner ), ); + } else { + // Log welcome + self.log( + LogLevel::Info, + format!( + "Established connection with '{}'", + self.get_remote_hostname() + ), + ); } // Try to change directory to entry directory let mut remote_chdir: Option = None; @@ -111,16 +124,28 @@ impl FileTransferActivity { /// Reload remote directory entries and update browser pub(super) fn reload_remote_dir(&mut self) { + if !self.connected { + return; + } // Get current entries if let Ok(wrkdir) = self.client.pwd() { self.mount_blocking_wait("Loading remote directory..."); - if self.remote_scan(wrkdir.as_path()).is_ok() { - // Set wrkdir - self.remote_mut().wrkdir = wrkdir; - } + let res = self.remote_scan(wrkdir.as_path()); self.umount_wait(); + + match res { + Ok(_) => { + self.remote_mut().wrkdir = wrkdir; + } + Err(err) => { + self.log_and_alert( + LogLevel::Error, + format!("Could not scan current remote directory: {err}"), + ); + } + } } } @@ -130,11 +155,21 @@ impl FileTransferActivity { let wrkdir: PathBuf = self.host.pwd(); - if self.local_scan(wrkdir.as_path()).is_ok() { - self.local_mut().wrkdir = wrkdir; - } + let res = self.local_scan(wrkdir.as_path()); self.umount_wait(); + + match res { + Ok(_) => { + self.local_mut().wrkdir = wrkdir; + } + Err(err) => { + self.log_and_alert( + LogLevel::Error, + format!("Could not scan current local directory: {err}"), + ); + } + } } /// Scan current local directory @@ -146,13 +181,7 @@ impl FileTransferActivity { Ok(()) } - Err(err) => { - self.log_and_alert( - LogLevel::Error, - format!("Could not scan current directory: {err}"), - ); - Err(err) - } + Err(err) => Err(err), } } @@ -164,13 +193,7 @@ impl FileTransferActivity { self.remote_mut().set_files(files); Ok(()) } - Err(err) => { - self.log_and_alert( - LogLevel::Error, - format!("Could not scan current directory: {err}"), - ); - Err(err) - } + Err(err) => Err(err), } } diff --git a/src/ui/activities/filetransfer/view.rs b/src/ui/activities/filetransfer/view.rs index 182c5ac..d7d2bdd 100644 --- a/src/ui/activities/filetransfer/view.rs +++ b/src/ui/activities/filetransfer/view.rs @@ -80,7 +80,7 @@ impl FileTransferActivity { self.refresh_remote_status_bar(); // Update components self.update_local_filelist(); - self.update_remote_filelist(); + // self.update_remote_filelist(); // Global listener self.mount_global_listener(); // Give focus to local explorer diff --git a/src/utils/parser.rs b/src/utils/parser.rs index aa0a5aa..cb81718 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -56,12 +56,12 @@ static REMOTE_WEBDAV_OPT_REGEX: Lazy = lazy_regex!(r"(?:([^:]+):)(?:(.+[^@])@)(?:([^/]+))(?:(.+))?"); /** - * Regex matches: {container}@{pod}/{path} - * - group 1: Container - * - group 2: Pod - * - group 3: Some(path) | None + * Regex matches: {namespace}[@{cluster_url}]$/{path} + * - group 1: Namespace + * - group 3: Some(cluster_url) | None + * - group 5: Some(path) | None */ -static REMOTE_KUBE_OPT_REGEX: Lazy = lazy_regex!(r"(?:(.+[^@])@)(?:([^/]+))(?:(.+))?"); +static REMOTE_KUBE_OPT_REGEX: Lazy = lazy_regex!(r"(?:([^@]+))(@(?:([^$]+)))?(\$(?:(.+)))?"); /** * Regex matches: @@ -313,23 +313,15 @@ fn parse_s3_remote_opt(s: &str) -> Result { fn parse_kube_remote_opt(s: &str) -> Result { match REMOTE_KUBE_OPT_REGEX.captures(s) { Some(groups) => { - let container: String = groups - .get(1) - .map(|x| x.as_str().to_string()) - .unwrap_or_default(); - let pod: String = groups - .get(2) - .map(|x| x.as_str().to_string()) - .unwrap_or_default(); + let namespace: Option = groups.get(1).map(|x| x.as_str().to_string()); + let cluster_url: Option = groups.get(3).map(|x| x.as_str().to_string()); let remote_path: Option = - groups.get(3).map(|group| PathBuf::from(group.as_str())); + groups.get(5).map(|group| PathBuf::from(group.as_str())); Ok(FileTransferParams::new( FileTransferProtocol::Kube, ProtocolParams::Kube(KubeProtocolParams { - pod, - container, - namespace: None, - cluster_url: None, + namespace, + cluster_url, username: None, client_cert: None, client_key: None, @@ -753,13 +745,13 @@ mod tests { #[test] fn should_parse_kube_address() { - let result = parse_remote_opt("kube://alpine@my-pod/tmp").ok().unwrap(); + let result = parse_remote_opt("kube://my-namespace@http://localhost:1234$/tmp") + .ok() + .unwrap(); let params = result.params.kube_params().unwrap(); - assert_eq!(params.container.as_str(), "alpine"); - assert_eq!(params.pod.as_str(), "my-pod"); - assert_eq!(params.namespace, None); - assert_eq!(params.cluster_url, None); + assert_eq!(params.namespace, Some("my-namespace".to_string())); + assert_eq!(params.cluster_url.as_deref(), Some("http://localhost:1234")); assert_eq!(params.username, None); assert_eq!(params.client_cert, None); assert_eq!(params.client_key, None);