mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
feat: kube protocol support (#267)
This commit is contained in:
committed by
GitHub
parent
cf529c1678
commit
f757336d75
@@ -2,6 +2,10 @@
|
||||
//!
|
||||
//! `bookmarks` is the module which provides data types and de/serializer for bookmarks
|
||||
|
||||
mod aws_s3;
|
||||
mod kube;
|
||||
mod smb;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
@@ -9,9 +13,12 @@ use std::str::FromStr;
|
||||
use serde::de::Error as DeError;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
pub use self::aws_s3::S3Params;
|
||||
pub use self::kube::KubeParams;
|
||||
pub use self::smb::SmbParams;
|
||||
use crate::filetransfer::params::{
|
||||
AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams as TransferSmbParams,
|
||||
WebDAVProtocolParams,
|
||||
AwsS3Params, GenericProtocolParams, KubeProtocolParams, ProtocolParams,
|
||||
SmbParams as TransferSmbParams, WebDAVProtocolParams,
|
||||
};
|
||||
use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
|
||||
|
||||
@@ -44,32 +51,14 @@ pub struct Bookmark {
|
||||
pub remote_path: Option<PathBuf>,
|
||||
/// local folder to open at startup
|
||||
pub local_path: Option<PathBuf>,
|
||||
/// Kube params; optional. When used other fields are empty for sure
|
||||
pub kube: Option<KubeParams>,
|
||||
/// S3 params; optional. When used other fields are empty for sure
|
||||
pub s3: Option<S3Params>,
|
||||
/// SMB params; optional. Extra params required for SMB protocol
|
||||
pub smb: Option<SmbParams>,
|
||||
}
|
||||
|
||||
/// Connection parameters for Aws s3 protocol
|
||||
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
|
||||
pub struct S3Params {
|
||||
pub bucket: String,
|
||||
pub region: Option<String>,
|
||||
pub endpoint: Option<String>,
|
||||
pub profile: Option<String>,
|
||||
pub access_key: Option<String>,
|
||||
pub secret_access_key: Option<String>,
|
||||
/// NOTE: there are no session token and security token since they are always temporary
|
||||
pub new_path_style: Option<bool>,
|
||||
}
|
||||
|
||||
/// Extra Connection parameters for SMB protocol
|
||||
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
|
||||
pub struct SmbParams {
|
||||
pub share: String,
|
||||
pub workgroup: Option<String>,
|
||||
}
|
||||
|
||||
// -- impls
|
||||
|
||||
impl From<FileTransferParams> for Bookmark {
|
||||
@@ -87,6 +76,7 @@ impl From<FileTransferParams> for Bookmark {
|
||||
password: params.password,
|
||||
remote_path,
|
||||
local_path,
|
||||
kube: None,
|
||||
s3: None,
|
||||
smb: None,
|
||||
},
|
||||
@@ -98,9 +88,22 @@ impl From<FileTransferParams> for Bookmark {
|
||||
password: None,
|
||||
remote_path,
|
||||
local_path,
|
||||
kube: None,
|
||||
s3: Some(S3Params::from(params)),
|
||||
smb: None,
|
||||
},
|
||||
ProtocolParams::Kube(params) => Self {
|
||||
protocol,
|
||||
address: None,
|
||||
port: None,
|
||||
username: None,
|
||||
password: None,
|
||||
remote_path,
|
||||
local_path,
|
||||
kube: Some(KubeParams::from(params)),
|
||||
s3: None,
|
||||
smb: None,
|
||||
},
|
||||
ProtocolParams::Smb(params) => Self {
|
||||
smb: Some(SmbParams::from(params.clone())),
|
||||
protocol,
|
||||
@@ -113,6 +116,7 @@ impl From<FileTransferParams> for Bookmark {
|
||||
password: params.password,
|
||||
remote_path,
|
||||
local_path,
|
||||
kube: None,
|
||||
s3: None,
|
||||
},
|
||||
ProtocolParams::WebDAV(parms) => Self {
|
||||
@@ -123,6 +127,7 @@ impl From<FileTransferParams> for Bookmark {
|
||||
password: Some(parms.password),
|
||||
remote_path,
|
||||
local_path,
|
||||
kube: None,
|
||||
s3: None,
|
||||
smb: None,
|
||||
},
|
||||
@@ -149,6 +154,11 @@ impl From<Bookmark> for FileTransferParams {
|
||||
.password(bookmark.password);
|
||||
Self::new(bookmark.protocol, ProtocolParams::Generic(params))
|
||||
}
|
||||
FileTransferProtocol::Kube => {
|
||||
let params = bookmark.kube.unwrap_or_default();
|
||||
let params = KubeProtocolParams::from(params);
|
||||
Self::new(bookmark.protocol, ProtocolParams::Kube(params))
|
||||
}
|
||||
#[cfg(unix)]
|
||||
FileTransferProtocol::Smb => {
|
||||
let params = TransferSmbParams::new(
|
||||
@@ -187,50 +197,6 @@ impl From<Bookmark> for FileTransferParams {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AwsS3Params> for S3Params {
|
||||
fn from(params: AwsS3Params) -> Self {
|
||||
S3Params {
|
||||
bucket: params.bucket_name,
|
||||
region: params.region,
|
||||
endpoint: params.endpoint,
|
||||
profile: params.profile,
|
||||
access_key: params.access_key,
|
||||
secret_access_key: params.secret_access_key,
|
||||
new_path_style: Some(params.new_path_style),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<S3Params> for AwsS3Params {
|
||||
fn from(params: S3Params) -> Self {
|
||||
AwsS3Params::new(params.bucket, params.region, params.profile)
|
||||
.endpoint(params.endpoint)
|
||||
.access_key(params.access_key)
|
||||
.secret_access_key(params.secret_access_key)
|
||||
.new_path_style(params.new_path_style.unwrap_or(false))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl From<TransferSmbParams> for SmbParams {
|
||||
fn from(params: TransferSmbParams) -> Self {
|
||||
Self {
|
||||
share: params.share,
|
||||
workgroup: params.workgroup,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl From<TransferSmbParams> for SmbParams {
|
||||
fn from(params: TransferSmbParams) -> Self {
|
||||
Self {
|
||||
share: params.share,
|
||||
workgroup: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_protocol<'de, D>(deserializer: D) -> Result<FileTransferProtocol, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
@@ -276,6 +242,7 @@ mod tests {
|
||||
password: Some(String::from("password")),
|
||||
remote_path: Some(PathBuf::from("/tmp")),
|
||||
local_path: Some(PathBuf::from("/usr")),
|
||||
kube: None,
|
||||
s3: None,
|
||||
smb: None,
|
||||
};
|
||||
@@ -287,6 +254,7 @@ mod tests {
|
||||
password: Some(String::from("password")),
|
||||
remote_path: Some(PathBuf::from("/home")),
|
||||
local_path: Some(PathBuf::from("/usr")),
|
||||
kube: None,
|
||||
s3: None,
|
||||
smb: None,
|
||||
};
|
||||
@@ -380,6 +348,38 @@ mod tests {
|
||||
assert_eq!(s3.secret_access_key.as_deref().unwrap(), "pluto");
|
||||
}
|
||||
|
||||
#[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()),
|
||||
client_cert: Some("cert".to_string()),
|
||||
client_key: Some("key".to_string()),
|
||||
});
|
||||
let params: FileTransferParams =
|
||||
FileTransferParams::new(FileTransferProtocol::Kube, params);
|
||||
let bookmark = Bookmark::from(params);
|
||||
assert_eq!(bookmark.protocol, FileTransferProtocol::Kube);
|
||||
assert!(bookmark.address.is_none());
|
||||
assert!(bookmark.port.is_none());
|
||||
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(),
|
||||
"https://localhost:6443"
|
||||
);
|
||||
assert_eq!(kube.username.as_deref().unwrap(), "root");
|
||||
assert_eq!(kube.client_cert.as_deref().unwrap(), "cert");
|
||||
assert_eq!(kube.client_key.as_deref().unwrap(), "key");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ftparams_from_generic_bookmark() {
|
||||
let bookmark: Bookmark = Bookmark {
|
||||
@@ -390,6 +390,7 @@ mod tests {
|
||||
password: Some(String::from("password")),
|
||||
remote_path: Some(PathBuf::from("/tmp")),
|
||||
local_path: Some(PathBuf::from("/usr")),
|
||||
kube: None,
|
||||
s3: None,
|
||||
smb: None,
|
||||
};
|
||||
@@ -420,6 +421,7 @@ mod tests {
|
||||
password: Some(String::from("password")),
|
||||
remote_path: Some(PathBuf::from("/tmp")),
|
||||
local_path: Some(PathBuf::from("/usr")),
|
||||
kube: None,
|
||||
s3: None,
|
||||
smb: None,
|
||||
};
|
||||
@@ -449,6 +451,7 @@ mod tests {
|
||||
password: None,
|
||||
remote_path: Some(PathBuf::from("/tmp")),
|
||||
local_path: Some(PathBuf::from("/usr")),
|
||||
kube: None,
|
||||
s3: Some(S3Params {
|
||||
bucket: String::from("veeso"),
|
||||
region: Some(String::from("eu-west-1")),
|
||||
@@ -480,6 +483,50 @@ mod tests {
|
||||
assert_eq!(gparams.new_path_style, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ftparams_from_kube_bookmark() {
|
||||
let bookmark: Bookmark = Bookmark {
|
||||
protocol: FileTransferProtocol::Kube,
|
||||
address: None,
|
||||
port: None,
|
||||
username: None,
|
||||
password: None,
|
||||
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")),
|
||||
client_cert: Some(String::from("cert")),
|
||||
client_key: Some(String::from("key")),
|
||||
}),
|
||||
s3: None,
|
||||
smb: None,
|
||||
};
|
||||
let params = FileTransferParams::from(bookmark);
|
||||
assert_eq!(params.protocol, FileTransferProtocol::Kube);
|
||||
assert_eq!(
|
||||
params.remote_path.as_deref().unwrap(),
|
||||
std::path::Path::new("/tmp")
|
||||
);
|
||||
assert_eq!(
|
||||
params.local_path.as_deref().unwrap(),
|
||||
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(),
|
||||
"https://localhost:6443"
|
||||
);
|
||||
assert_eq!(gparams.username.as_deref().unwrap(), "root");
|
||||
assert_eq!(gparams.client_cert.as_deref().unwrap(), "cert");
|
||||
assert_eq!(gparams.client_key.as_deref().unwrap(), "key");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn should_get_ftparams_from_smb_bookmark() {
|
||||
@@ -491,6 +538,7 @@ mod tests {
|
||||
password: Some("bar".to_string()),
|
||||
remote_path: Some(PathBuf::from("/tmp")),
|
||||
local_path: Some(PathBuf::from("/usr")),
|
||||
kube: None,
|
||||
s3: None,
|
||||
smb: Some(SmbParams {
|
||||
share: "test".to_string(),
|
||||
@@ -529,6 +577,7 @@ mod tests {
|
||||
remote_path: Some(PathBuf::from("/tmp")),
|
||||
local_path: Some(PathBuf::from("/usr")),
|
||||
s3: None,
|
||||
kube: None,
|
||||
smb: Some(SmbParams {
|
||||
share: "test".to_string(),
|
||||
workgroup: None,
|
||||
|
||||
40
src/config/bookmarks/aws_s3.rs
Normal file
40
src/config/bookmarks/aws_s3.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::filetransfer::params::AwsS3Params;
|
||||
|
||||
/// Connection parameters for Aws s3 protocol
|
||||
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
|
||||
pub struct S3Params {
|
||||
pub bucket: String,
|
||||
pub region: Option<String>,
|
||||
pub endpoint: Option<String>,
|
||||
pub profile: Option<String>,
|
||||
pub access_key: Option<String>,
|
||||
pub secret_access_key: Option<String>,
|
||||
/// NOTE: there are no session token and security token since they are always temporary
|
||||
pub new_path_style: Option<bool>,
|
||||
}
|
||||
|
||||
impl From<AwsS3Params> for S3Params {
|
||||
fn from(params: AwsS3Params) -> Self {
|
||||
S3Params {
|
||||
bucket: params.bucket_name,
|
||||
region: params.region,
|
||||
endpoint: params.endpoint,
|
||||
profile: params.profile,
|
||||
access_key: params.access_key,
|
||||
secret_access_key: params.secret_access_key,
|
||||
new_path_style: Some(params.new_path_style),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<S3Params> for AwsS3Params {
|
||||
fn from(params: S3Params) -> Self {
|
||||
AwsS3Params::new(params.bucket, params.region, params.profile)
|
||||
.endpoint(params.endpoint)
|
||||
.access_key(params.access_key)
|
||||
.secret_access_key(params.secret_access_key)
|
||||
.new_path_style(params.new_path_style.unwrap_or(false))
|
||||
}
|
||||
}
|
||||
43
src/config/bookmarks/kube.rs
Normal file
43
src/config/bookmarks/kube.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
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<String>,
|
||||
pub cluster_url: Option<String>,
|
||||
pub username: Option<String>,
|
||||
pub client_cert: Option<String>,
|
||||
pub client_key: Option<String>,
|
||||
}
|
||||
|
||||
impl From<KubeParams> 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,
|
||||
client_cert: value.client_cert,
|
||||
client_key: value.client_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KubeProtocolParams> 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,
|
||||
client_cert: value.client_cert,
|
||||
client_key: value.client_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/config/bookmarks/smb.rs
Normal file
30
src/config/bookmarks/smb.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::filetransfer::params::SmbParams as TransferSmbParams;
|
||||
|
||||
/// Extra Connection parameters for SMB protocol
|
||||
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
|
||||
pub struct SmbParams {
|
||||
pub share: String,
|
||||
pub workgroup: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl From<TransferSmbParams> for SmbParams {
|
||||
fn from(params: TransferSmbParams) -> Self {
|
||||
Self {
|
||||
share: params.share,
|
||||
workgroup: params.workgroup,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl From<TransferSmbParams> for SmbParams {
|
||||
fn from(params: TransferSmbParams) -> Self {
|
||||
Self {
|
||||
share: params.share,
|
||||
workgroup: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ mod tests {
|
||||
use tuirealm::tui::style::Color;
|
||||
|
||||
use super::*;
|
||||
use crate::config::bookmarks::{Bookmark, S3Params, SmbParams, UserHosts};
|
||||
use crate::config::bookmarks::{Bookmark, KubeParams, S3Params, SmbParams, UserHosts};
|
||||
use crate::config::params::UserConfig;
|
||||
use crate::config::themes::Theme;
|
||||
use crate::filetransfer::FileTransferProtocol;
|
||||
@@ -366,7 +366,7 @@ mod tests {
|
||||
assert_eq!(host.username.as_deref().unwrap(), "root");
|
||||
assert_eq!(host.password, None);
|
||||
// Verify bookmarks
|
||||
assert_eq!(hosts.bookmarks.len(), 5);
|
||||
assert_eq!(hosts.bookmarks.len(), 6);
|
||||
let host: &Bookmark = hosts.bookmarks.get("raspberrypi2").unwrap();
|
||||
assert_eq!(host.address.as_deref().unwrap(), "192.168.1.31");
|
||||
assert_eq!(host.port.unwrap(), 22);
|
||||
@@ -404,6 +404,21 @@ mod tests {
|
||||
assert_eq!(s3.access_key.as_deref().unwrap(), "pippo");
|
||||
assert_eq!(s3.secret_access_key.as_deref().unwrap(), "pluto");
|
||||
assert_eq!(s3.new_path_style.unwrap(), true);
|
||||
// Kube pod
|
||||
let host: &Bookmark = hosts.bookmarks.get("pod").unwrap();
|
||||
assert_eq!(host.address, None);
|
||||
assert_eq!(host.port, None);
|
||||
assert_eq!(host.username, None);
|
||||
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");
|
||||
assert_eq!(kube.client_cert.as_deref().unwrap(), "my-cert");
|
||||
assert_eq!(kube.client_key.as_deref().unwrap(), "my-key");
|
||||
|
||||
// smb
|
||||
let host = hosts.bookmarks.get("smb").unwrap();
|
||||
@@ -443,6 +458,7 @@ mod tests {
|
||||
password: None,
|
||||
remote_path: None,
|
||||
local_path: None,
|
||||
kube: None,
|
||||
s3: None,
|
||||
smb: None,
|
||||
},
|
||||
@@ -457,6 +473,7 @@ mod tests {
|
||||
password: Some(String::from("password")),
|
||||
remote_path: Some(PathBuf::from("/tmp")),
|
||||
local_path: Some(PathBuf::from("/usr")),
|
||||
kube: None,
|
||||
s3: None,
|
||||
smb: None,
|
||||
},
|
||||
@@ -480,9 +497,35 @@ mod tests {
|
||||
secret_access_key: None,
|
||||
new_path_style: None,
|
||||
}),
|
||||
kube: None,
|
||||
smb: None,
|
||||
},
|
||||
);
|
||||
// push kube pod
|
||||
bookmarks.insert(
|
||||
String::from("pod"),
|
||||
Bookmark {
|
||||
address: None,
|
||||
port: None,
|
||||
protocol: FileTransferProtocol::Kube,
|
||||
username: None,
|
||||
password: None,
|
||||
remote_path: None,
|
||||
local_path: None,
|
||||
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()),
|
||||
client_cert: Some("my-cert".to_string()),
|
||||
client_key: Some("my-key".to_string()),
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
let smb_params: Option<SmbParams> = Some(SmbParams {
|
||||
share: "test".to_string(),
|
||||
workgroup: None,
|
||||
@@ -498,6 +541,7 @@ mod tests {
|
||||
remote_path: None,
|
||||
local_path: None,
|
||||
s3: None,
|
||||
kube: None,
|
||||
smb: smb_params,
|
||||
},
|
||||
);
|
||||
@@ -513,6 +557,7 @@ mod tests {
|
||||
remote_path: Some(PathBuf::from("/tmp")),
|
||||
local_path: Some(PathBuf::from("/usr")),
|
||||
s3: None,
|
||||
kube: None,
|
||||
smb: None,
|
||||
},
|
||||
);
|
||||
@@ -569,6 +614,17 @@ mod tests {
|
||||
secret_access_key = "pluto"
|
||||
new_path_style = true
|
||||
|
||||
[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"
|
||||
|
||||
[bookmarks.smb]
|
||||
protocol = "SMB"
|
||||
address = "localhost"
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
//! Remotefs client builder
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use remotefs::RemoteFs;
|
||||
use remotefs_aws_s3::AwsS3Fs;
|
||||
use remotefs_ftp::FtpFs;
|
||||
use remotefs_kube::KubeFs;
|
||||
#[cfg(smb_unix)]
|
||||
use remotefs_smb::SmbOptions;
|
||||
#[cfg(smb)]
|
||||
@@ -14,11 +16,11 @@ use remotefs_smb::{SmbCredentials, SmbFs};
|
||||
use remotefs_ssh::{ScpFs, SftpFs, SshAgentIdentity, SshConfigParseRule, SshOpts};
|
||||
use remotefs_webdav::WebDAVFs;
|
||||
|
||||
use super::params::WebDAVProtocolParams;
|
||||
#[cfg(not(smb))]
|
||||
use super::params::{AwsS3Params, GenericProtocolParams};
|
||||
#[cfg(smb)]
|
||||
use super::params::{AwsS3Params, GenericProtocolParams, SmbParams};
|
||||
use super::params::{KubeProtocolParams, WebDAVProtocolParams};
|
||||
use super::{FileTransferProtocol, ProtocolParams};
|
||||
use crate::system::config_client::ConfigClient;
|
||||
use crate::system::sshkey_storage::SshKeyStorage;
|
||||
@@ -43,6 +45,9 @@ impl Builder {
|
||||
(FileTransferProtocol::Ftp(secure), ProtocolParams::Generic(params)) => {
|
||||
Box::new(Self::ftp_client(params, secure))
|
||||
}
|
||||
(FileTransferProtocol::Kube, ProtocolParams::Kube(params)) => {
|
||||
Box::new(Self::kube_client(params))
|
||||
}
|
||||
(FileTransferProtocol::Scp, ProtocolParams::Generic(params)) => {
|
||||
Box::new(Self::scp_client(params, config_client))
|
||||
}
|
||||
@@ -105,6 +110,23 @@ impl Builder {
|
||||
client
|
||||
}
|
||||
|
||||
/// Build kube client
|
||||
fn kube_client(params: KubeProtocolParams) -> KubeFs {
|
||||
let rt = Arc::new(
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(1)
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Unable to create tokio runtime"),
|
||||
);
|
||||
let kube_fs = KubeFs::new(¶ms.pod, ¶ms.container, &rt);
|
||||
if let Some(config) = params.config() {
|
||||
kube_fs.config(config)
|
||||
} else {
|
||||
kube_fs
|
||||
}
|
||||
}
|
||||
|
||||
/// Build scp client
|
||||
fn scp_client(params: GenericProtocolParams, config_client: &ConfigClient) -> ScpFs {
|
||||
Self::build_ssh_opts(params, config_client).into()
|
||||
@@ -256,6 +278,21 @@ mod test {
|
||||
let _ = Builder::build(FileTransferProtocol::Ftp(true), params, &config_client);
|
||||
}
|
||||
|
||||
#[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()),
|
||||
client_cert: Some("client_cert".to_string()),
|
||||
client_key: Some("client_key".to_string()),
|
||||
});
|
||||
let config_client = get_config_client();
|
||||
let _ = Builder::build(FileTransferProtocol::Kube, params, &config_client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_build_scp_fs() {
|
||||
let params = ProtocolParams::Generic(
|
||||
|
||||
@@ -15,6 +15,7 @@ pub use params::{FileTransferParams, ProtocolParams};
|
||||
pub enum FileTransferProtocol {
|
||||
AwsS3,
|
||||
Ftp(bool), // Bool is for secure (true => ftps)
|
||||
Kube,
|
||||
Scp,
|
||||
Sftp,
|
||||
Smb,
|
||||
@@ -34,6 +35,7 @@ impl std::fmt::Display for FileTransferProtocol {
|
||||
true => "FTPS",
|
||||
false => "FTP",
|
||||
},
|
||||
FileTransferProtocol::Kube => "KUBE",
|
||||
FileTransferProtocol::Scp => "SCP",
|
||||
FileTransferProtocol::Sftp => "SFTP",
|
||||
FileTransferProtocol::Smb => "SMB",
|
||||
@@ -49,6 +51,7 @@ impl std::str::FromStr for FileTransferProtocol {
|
||||
match s.to_ascii_uppercase().as_str() {
|
||||
"FTP" => Ok(FileTransferProtocol::Ftp(false)),
|
||||
"FTPS" => Ok(FileTransferProtocol::Ftp(true)),
|
||||
"KUBE" => Ok(FileTransferProtocol::Kube),
|
||||
"S3" => Ok(FileTransferProtocol::AwsS3),
|
||||
"SCP" => Ok(FileTransferProtocol::Scp),
|
||||
"SFTP" => Ok(FileTransferProtocol::Sftp),
|
||||
@@ -114,6 +117,14 @@ mod tests {
|
||||
FileTransferProtocol::from_str("scp").ok().unwrap(),
|
||||
FileTransferProtocol::Scp
|
||||
);
|
||||
assert_eq!(
|
||||
FileTransferProtocol::from_str("kube").ok().unwrap(),
|
||||
FileTransferProtocol::Kube
|
||||
);
|
||||
assert_eq!(
|
||||
FileTransferProtocol::from_str("KUBE").ok().unwrap(),
|
||||
FileTransferProtocol::Kube
|
||||
);
|
||||
assert_eq!(
|
||||
FileTransferProtocol::from_str("SMB").ok().unwrap(),
|
||||
FileTransferProtocol::Smb
|
||||
@@ -153,5 +164,6 @@ mod tests {
|
||||
FileTransferProtocol::WebDAV.to_string(),
|
||||
String::from("WEBDAV")
|
||||
);
|
||||
assert_eq!(FileTransferProtocol::Kube.to_string(), String::from("KUBE"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,17 @@
|
||||
//!
|
||||
//! file transfer parameters
|
||||
|
||||
mod aws_s3;
|
||||
mod kube;
|
||||
mod smb;
|
||||
mod webdav;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub use self::aws_s3::AwsS3Params;
|
||||
pub use self::kube::KubeProtocolParams;
|
||||
pub use self::smb::SmbParams;
|
||||
pub use self::webdav::WebDAVProtocolParams;
|
||||
use super::FileTransferProtocol;
|
||||
|
||||
/// Holds connection parameters for file transfers
|
||||
@@ -20,6 +29,7 @@ pub struct FileTransferParams {
|
||||
pub enum ProtocolParams {
|
||||
Generic(GenericProtocolParams),
|
||||
AwsS3(AwsS3Params),
|
||||
Kube(KubeProtocolParams),
|
||||
Smb(SmbParams),
|
||||
WebDAV(WebDAVProtocolParams),
|
||||
}
|
||||
@@ -33,33 +43,6 @@ pub struct GenericProtocolParams {
|
||||
pub password: Option<String>,
|
||||
}
|
||||
|
||||
/// Connection parameters for AWS S3 protocol
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AwsS3Params {
|
||||
pub bucket_name: String,
|
||||
pub region: Option<String>,
|
||||
pub endpoint: Option<String>,
|
||||
pub profile: Option<String>,
|
||||
pub access_key: Option<String>,
|
||||
pub secret_access_key: Option<String>,
|
||||
pub security_token: Option<String>,
|
||||
pub session_token: Option<String>,
|
||||
pub new_path_style: bool,
|
||||
}
|
||||
|
||||
/// Connection parameters for SMB protocol
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SmbParams {
|
||||
pub address: String,
|
||||
#[cfg(unix)]
|
||||
pub port: u16,
|
||||
pub share: String,
|
||||
pub username: Option<String>,
|
||||
pub password: Option<String>,
|
||||
#[cfg(unix)]
|
||||
pub workgroup: Option<String>,
|
||||
}
|
||||
|
||||
impl FileTransferParams {
|
||||
/// Instantiates a new `FileTransferParams`
|
||||
pub fn new(protocol: FileTransferProtocol, params: ProtocolParams) -> Self {
|
||||
@@ -89,6 +72,7 @@ impl FileTransferParams {
|
||||
match &self.params {
|
||||
ProtocolParams::AwsS3(params) => params.password_missing(),
|
||||
ProtocolParams::Generic(params) => params.password_missing(),
|
||||
ProtocolParams::Kube(params) => params.password_missing(),
|
||||
ProtocolParams::Smb(params) => params.password_missing(),
|
||||
ProtocolParams::WebDAV(params) => params.password_missing(),
|
||||
}
|
||||
@@ -99,30 +83,13 @@ impl FileTransferParams {
|
||||
match &mut self.params {
|
||||
ProtocolParams::AwsS3(params) => params.set_default_secret(secret),
|
||||
ProtocolParams::Generic(params) => params.set_default_secret(secret),
|
||||
ProtocolParams::Kube(params) => params.set_default_secret(secret),
|
||||
ProtocolParams::Smb(params) => params.set_default_secret(secret),
|
||||
ProtocolParams::WebDAV(params) => params.set_default_secret(secret),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Protocol params used by WebDAV
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WebDAVProtocolParams {
|
||||
pub uri: String,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
impl WebDAVProtocolParams {
|
||||
fn set_default_secret(&mut self, secret: String) {
|
||||
self.password = secret;
|
||||
}
|
||||
|
||||
fn password_missing(&self) -> bool {
|
||||
self.password.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FileTransferParams {
|
||||
fn default() -> Self {
|
||||
Self::new(FileTransferProtocol::Sftp, ProtocolParams::default())
|
||||
@@ -162,6 +129,15 @@ impl ProtocolParams {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Retrieve Kube params parameters if any
|
||||
pub fn kube_params(&self) -> Option<&KubeProtocolParams> {
|
||||
match self {
|
||||
ProtocolParams::Kube(params) => Some(params),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Retrieve SMB parameters if any
|
||||
pub fn smb_params(&self) -> Option<&SmbParams> {
|
||||
@@ -231,127 +207,6 @@ impl GenericProtocolParams {
|
||||
}
|
||||
}
|
||||
|
||||
// -- S3 params
|
||||
|
||||
impl AwsS3Params {
|
||||
/// Instantiates a new `AwsS3Params` struct
|
||||
pub fn new<S: AsRef<str>>(bucket: S, region: Option<S>, profile: Option<S>) -> Self {
|
||||
Self {
|
||||
bucket_name: bucket.as_ref().to_string(),
|
||||
region: region.map(|x| x.as_ref().to_string()),
|
||||
profile: profile.map(|x| x.as_ref().to_string()),
|
||||
endpoint: None,
|
||||
access_key: None,
|
||||
secret_access_key: None,
|
||||
security_token: None,
|
||||
session_token: None,
|
||||
new_path_style: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct aws s3 params with specified endpoint
|
||||
pub fn endpoint<S: AsRef<str>>(mut self, endpoint: Option<S>) -> Self {
|
||||
self.endpoint = endpoint.map(|x| x.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Construct aws s3 params with provided access key
|
||||
pub fn access_key<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
|
||||
self.access_key = key.map(|x| x.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Construct aws s3 params with provided secret_access_key
|
||||
pub fn secret_access_key<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
|
||||
self.secret_access_key = key.map(|x| x.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Construct aws s3 params with provided security_token
|
||||
pub fn security_token<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
|
||||
self.security_token = key.map(|x| x.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Construct aws s3 params with provided session_token
|
||||
pub fn session_token<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
|
||||
self.session_token = key.map(|x| x.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify new path style when constructing aws s3 params
|
||||
pub fn new_path_style(mut self, new_path_style: bool) -> Self {
|
||||
self.new_path_style = new_path_style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns whether a password is supposed to be required for this protocol params.
|
||||
/// The result true is returned ONLY if the supposed secret is MISSING!!!
|
||||
pub fn password_missing(&self) -> bool {
|
||||
self.secret_access_key.is_none() && self.security_token.is_none()
|
||||
}
|
||||
|
||||
/// Set password
|
||||
pub fn set_default_secret(&mut self, secret: String) {
|
||||
self.secret_access_key = Some(secret);
|
||||
}
|
||||
}
|
||||
|
||||
// -- SMB params
|
||||
|
||||
impl SmbParams {
|
||||
/// Instantiates a new `AwsS3Params` struct
|
||||
pub fn new<S: AsRef<str>>(address: S, share: S) -> Self {
|
||||
Self {
|
||||
address: address.as_ref().to_string(),
|
||||
#[cfg(unix)]
|
||||
port: 445,
|
||||
share: share.as_ref().to_string(),
|
||||
username: None,
|
||||
password: None,
|
||||
#[cfg(unix)]
|
||||
workgroup: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn port(mut self, port: u16) -> Self {
|
||||
self.port = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn username(mut self, username: Option<impl ToString>) -> Self {
|
||||
self.username = username.map(|x| x.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn password(mut self, password: Option<impl ToString>) -> Self {
|
||||
self.password = password.map(|x| x.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn workgroup(mut self, workgroup: Option<impl ToString>) -> Self {
|
||||
self.workgroup = workgroup.map(|x| x.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns whether a password is supposed to be required for this protocol params.
|
||||
/// The result true is returned ONLY if the supposed secret is MISSING!!!
|
||||
pub fn password_missing(&self) -> bool {
|
||||
self.password.is_none()
|
||||
}
|
||||
|
||||
/// Set password
|
||||
#[cfg(unix)]
|
||||
pub fn set_default_secret(&mut self, secret: String) {
|
||||
self.password = Some(secret);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn set_default_secret(&mut self, _secret: String) {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
@@ -386,87 +241,6 @@ mod test {
|
||||
assert!(params.password.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_init_aws_s3_params() {
|
||||
let params: AwsS3Params = AwsS3Params::new("omar", Some("eu-west-1"), Some("test"));
|
||||
assert_eq!(params.bucket_name.as_str(), "omar");
|
||||
assert_eq!(params.region.as_deref().unwrap(), "eu-west-1");
|
||||
assert_eq!(params.profile.as_deref().unwrap(), "test");
|
||||
assert!(params.endpoint.is_none());
|
||||
assert!(params.access_key.is_none());
|
||||
assert!(params.secret_access_key.is_none());
|
||||
assert!(params.security_token.is_none());
|
||||
assert!(params.session_token.is_none());
|
||||
assert_eq!(params.new_path_style, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_init_aws_s3_params_with_optionals() {
|
||||
let params: AwsS3Params = AwsS3Params::new("omar", Some("eu-west-1"), Some("test"))
|
||||
.endpoint(Some("http://omar.it"))
|
||||
.access_key(Some("pippo"))
|
||||
.secret_access_key(Some("pluto"))
|
||||
.security_token(Some("omar"))
|
||||
.session_token(Some("gerry-scotti"))
|
||||
.new_path_style(true);
|
||||
assert_eq!(params.bucket_name.as_str(), "omar");
|
||||
assert_eq!(params.region.as_deref().unwrap(), "eu-west-1");
|
||||
assert_eq!(params.profile.as_deref().unwrap(), "test");
|
||||
assert_eq!(params.endpoint.as_deref().unwrap(), "http://omar.it");
|
||||
assert_eq!(params.access_key.as_deref().unwrap(), "pippo");
|
||||
assert_eq!(params.secret_access_key.as_deref().unwrap(), "pluto");
|
||||
assert_eq!(params.security_token.as_deref().unwrap(), "omar");
|
||||
assert_eq!(params.session_token.as_deref().unwrap(), "gerry-scotti");
|
||||
assert_eq!(params.new_path_style, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_init_smb_params() {
|
||||
let params = SmbParams::new("localhost", "temp");
|
||||
assert_eq!(¶ms.address, "localhost");
|
||||
|
||||
#[cfg(unix)]
|
||||
assert_eq!(params.port, 445);
|
||||
assert_eq!(¶ms.share, "temp");
|
||||
|
||||
#[cfg(unix)]
|
||||
assert!(params.username.is_none());
|
||||
#[cfg(unix)]
|
||||
assert!(params.password.is_none());
|
||||
#[cfg(unix)]
|
||||
assert!(params.workgroup.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn should_init_smb_params_with_optionals() {
|
||||
let params = SmbParams::new("localhost", "temp")
|
||||
.port(3456)
|
||||
.username(Some("foo"))
|
||||
.password(Some("bar"))
|
||||
.workgroup(Some("baz"));
|
||||
|
||||
assert_eq!(¶ms.address, "localhost");
|
||||
assert_eq!(params.port, 3456);
|
||||
assert_eq!(¶ms.share, "temp");
|
||||
assert_eq!(params.username.as_deref().unwrap(), "foo");
|
||||
assert_eq!(params.password.as_deref().unwrap(), "bar");
|
||||
assert_eq!(params.workgroup.as_deref().unwrap(), "baz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn should_init_smb_params_with_optionals() {
|
||||
let params = SmbParams::new("localhost", "temp")
|
||||
.username(Some("foo"))
|
||||
.password(Some("bar"));
|
||||
|
||||
assert_eq!(¶ms.address, "localhost");
|
||||
assert_eq!(¶ms.share, "temp");
|
||||
assert_eq!(params.username.as_deref().unwrap(), "foo");
|
||||
assert_eq!(params.password.as_deref().unwrap(), "bar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references() {
|
||||
let mut params =
|
||||
|
||||
121
src/filetransfer/params/aws_s3.rs
Normal file
121
src/filetransfer/params/aws_s3.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
/// Connection parameters for AWS S3 protocol
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AwsS3Params {
|
||||
pub bucket_name: String,
|
||||
pub region: Option<String>,
|
||||
pub endpoint: Option<String>,
|
||||
pub profile: Option<String>,
|
||||
pub access_key: Option<String>,
|
||||
pub secret_access_key: Option<String>,
|
||||
pub security_token: Option<String>,
|
||||
pub session_token: Option<String>,
|
||||
pub new_path_style: bool,
|
||||
}
|
||||
|
||||
// -- S3 params
|
||||
|
||||
impl AwsS3Params {
|
||||
/// Instantiates a new `AwsS3Params` struct
|
||||
pub fn new<S: AsRef<str>>(bucket: S, region: Option<S>, profile: Option<S>) -> Self {
|
||||
Self {
|
||||
bucket_name: bucket.as_ref().to_string(),
|
||||
region: region.map(|x| x.as_ref().to_string()),
|
||||
profile: profile.map(|x| x.as_ref().to_string()),
|
||||
endpoint: None,
|
||||
access_key: None,
|
||||
secret_access_key: None,
|
||||
security_token: None,
|
||||
session_token: None,
|
||||
new_path_style: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct aws s3 params with specified endpoint
|
||||
pub fn endpoint<S: AsRef<str>>(mut self, endpoint: Option<S>) -> Self {
|
||||
self.endpoint = endpoint.map(|x| x.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Construct aws s3 params with provided access key
|
||||
pub fn access_key<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
|
||||
self.access_key = key.map(|x| x.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Construct aws s3 params with provided secret_access_key
|
||||
pub fn secret_access_key<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
|
||||
self.secret_access_key = key.map(|x| x.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Construct aws s3 params with provided security_token
|
||||
pub fn security_token<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
|
||||
self.security_token = key.map(|x| x.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Construct aws s3 params with provided session_token
|
||||
pub fn session_token<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
|
||||
self.session_token = key.map(|x| x.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify new path style when constructing aws s3 params
|
||||
pub fn new_path_style(mut self, new_path_style: bool) -> Self {
|
||||
self.new_path_style = new_path_style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns whether a password is supposed to be required for this protocol params.
|
||||
/// The result true is returned ONLY if the supposed secret is MISSING!!!
|
||||
pub fn password_missing(&self) -> bool {
|
||||
self.secret_access_key.is_none() && self.security_token.is_none()
|
||||
}
|
||||
|
||||
/// Set password
|
||||
pub fn set_default_secret(&mut self, secret: String) {
|
||||
self.secret_access_key = Some(secret);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_init_aws_s3_params() {
|
||||
let params: AwsS3Params = AwsS3Params::new("omar", Some("eu-west-1"), Some("test"));
|
||||
assert_eq!(params.bucket_name.as_str(), "omar");
|
||||
assert_eq!(params.region.as_deref().unwrap(), "eu-west-1");
|
||||
assert_eq!(params.profile.as_deref().unwrap(), "test");
|
||||
assert!(params.endpoint.is_none());
|
||||
assert!(params.access_key.is_none());
|
||||
assert!(params.secret_access_key.is_none());
|
||||
assert!(params.security_token.is_none());
|
||||
assert!(params.session_token.is_none());
|
||||
assert_eq!(params.new_path_style, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_init_aws_s3_params_with_optionals() {
|
||||
let params: AwsS3Params = AwsS3Params::new("omar", Some("eu-west-1"), Some("test"))
|
||||
.endpoint(Some("http://omar.it"))
|
||||
.access_key(Some("pippo"))
|
||||
.secret_access_key(Some("pluto"))
|
||||
.security_token(Some("omar"))
|
||||
.session_token(Some("gerry-scotti"))
|
||||
.new_path_style(true);
|
||||
assert_eq!(params.bucket_name.as_str(), "omar");
|
||||
assert_eq!(params.region.as_deref().unwrap(), "eu-west-1");
|
||||
assert_eq!(params.profile.as_deref().unwrap(), "test");
|
||||
assert_eq!(params.endpoint.as_deref().unwrap(), "http://omar.it");
|
||||
assert_eq!(params.access_key.as_deref().unwrap(), "pippo");
|
||||
assert_eq!(params.secret_access_key.as_deref().unwrap(), "pluto");
|
||||
assert_eq!(params.security_token.as_deref().unwrap(), "omar");
|
||||
assert_eq!(params.session_token.as_deref().unwrap(), "gerry-scotti");
|
||||
assert_eq!(params.new_path_style, true);
|
||||
}
|
||||
}
|
||||
37
src/filetransfer/params/kube.rs
Normal file
37
src/filetransfer/params/kube.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use remotefs_kube::Config;
|
||||
|
||||
/// Protocol params used by WebDAV
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KubeProtocolParams {
|
||||
pub pod: String,
|
||||
pub container: String,
|
||||
pub namespace: Option<String>,
|
||||
pub cluster_url: Option<String>,
|
||||
pub username: Option<String>,
|
||||
pub client_cert: Option<String>,
|
||||
pub client_key: Option<String>,
|
||||
}
|
||||
|
||||
impl KubeProtocolParams {
|
||||
pub fn set_default_secret(&mut self, _secret: String) {}
|
||||
|
||||
pub fn password_missing(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn config(self) -> Option<Config> {
|
||||
if let Some(cluster_url) = self.cluster_url {
|
||||
let mut config = Config::new(cluster_url.parse().unwrap_or_default());
|
||||
config.auth_info.username = self.username;
|
||||
config.auth_info.client_certificate = self.client_cert;
|
||||
config.auth_info.client_key = self.client_key;
|
||||
if let Some(namespace) = self.namespace {
|
||||
config.default_namespace = namespace;
|
||||
}
|
||||
|
||||
Some(config)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
122
src/filetransfer/params/smb.rs
Normal file
122
src/filetransfer/params/smb.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
/// Connection parameters for SMB protocol
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SmbParams {
|
||||
pub address: String,
|
||||
#[cfg(unix)]
|
||||
pub port: u16,
|
||||
pub share: String,
|
||||
pub username: Option<String>,
|
||||
pub password: Option<String>,
|
||||
#[cfg(unix)]
|
||||
pub workgroup: Option<String>,
|
||||
}
|
||||
|
||||
// -- SMB params
|
||||
|
||||
impl SmbParams {
|
||||
/// Instantiates a new `AwsS3Params` struct
|
||||
pub fn new<S: AsRef<str>>(address: S, share: S) -> Self {
|
||||
Self {
|
||||
address: address.as_ref().to_string(),
|
||||
#[cfg(unix)]
|
||||
port: 445,
|
||||
share: share.as_ref().to_string(),
|
||||
username: None,
|
||||
password: None,
|
||||
#[cfg(unix)]
|
||||
workgroup: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn port(mut self, port: u16) -> Self {
|
||||
self.port = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn username(mut self, username: Option<impl ToString>) -> Self {
|
||||
self.username = username.map(|x| x.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn password(mut self, password: Option<impl ToString>) -> Self {
|
||||
self.password = password.map(|x| x.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn workgroup(mut self, workgroup: Option<impl ToString>) -> Self {
|
||||
self.workgroup = workgroup.map(|x| x.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns whether a password is supposed to be required for this protocol params.
|
||||
/// The result true is returned ONLY if the supposed secret is MISSING!!!
|
||||
pub fn password_missing(&self) -> bool {
|
||||
self.password.is_none()
|
||||
}
|
||||
|
||||
/// Set password
|
||||
#[cfg(unix)]
|
||||
pub fn set_default_secret(&mut self, secret: String) {
|
||||
self.password = Some(secret);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn set_default_secret(&mut self, _secret: String) {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_init_smb_params() {
|
||||
let params = SmbParams::new("localhost", "temp");
|
||||
assert_eq!(¶ms.address, "localhost");
|
||||
|
||||
#[cfg(unix)]
|
||||
assert_eq!(params.port, 445);
|
||||
assert_eq!(¶ms.share, "temp");
|
||||
|
||||
#[cfg(unix)]
|
||||
assert!(params.username.is_none());
|
||||
#[cfg(unix)]
|
||||
assert!(params.password.is_none());
|
||||
#[cfg(unix)]
|
||||
assert!(params.workgroup.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn should_init_smb_params_with_optionals() {
|
||||
let params = SmbParams::new("localhost", "temp")
|
||||
.port(3456)
|
||||
.username(Some("foo"))
|
||||
.password(Some("bar"))
|
||||
.workgroup(Some("baz"));
|
||||
|
||||
assert_eq!(¶ms.address, "localhost");
|
||||
assert_eq!(params.port, 3456);
|
||||
assert_eq!(¶ms.share, "temp");
|
||||
assert_eq!(params.username.as_deref().unwrap(), "foo");
|
||||
assert_eq!(params.password.as_deref().unwrap(), "bar");
|
||||
assert_eq!(params.workgroup.as_deref().unwrap(), "baz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn should_init_smb_params_with_optionals() {
|
||||
let params = SmbParams::new("localhost", "temp")
|
||||
.username(Some("foo"))
|
||||
.password(Some("bar"));
|
||||
|
||||
assert_eq!(¶ms.address, "localhost");
|
||||
assert_eq!(¶ms.share, "temp");
|
||||
assert_eq!(params.username.as_deref().unwrap(), "foo");
|
||||
assert_eq!(params.password.as_deref().unwrap(), "bar");
|
||||
}
|
||||
}
|
||||
17
src/filetransfer/params/webdav.rs
Normal file
17
src/filetransfer/params/webdav.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
/// Protocol params used by WebDAV
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WebDAVProtocolParams {
|
||||
pub uri: String,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
impl WebDAVProtocolParams {
|
||||
pub fn set_default_secret(&mut self, secret: String) {
|
||||
self.password = secret;
|
||||
}
|
||||
|
||||
pub fn password_missing(&self) -> bool {
|
||||
self.password.is_empty()
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,8 @@
|
||||
// Locals
|
||||
use super::{AuthActivity, FileTransferParams};
|
||||
use crate::filetransfer::params::{
|
||||
AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams, WebDAVProtocolParams,
|
||||
AwsS3Params, GenericProtocolParams, KubeProtocolParams, ProtocolParams, SmbParams,
|
||||
WebDAVProtocolParams,
|
||||
};
|
||||
|
||||
impl AuthActivity {
|
||||
@@ -164,6 +165,8 @@ impl AuthActivity {
|
||||
);
|
||||
match bookmark.params {
|
||||
ProtocolParams::AwsS3(params) => self.load_bookmark_s3_into_gui(params),
|
||||
ProtocolParams::Kube(params) => self.load_bookmark_kube_into_gui(params),
|
||||
|
||||
ProtocolParams::Generic(params) => self.load_bookmark_generic_into_gui(params),
|
||||
ProtocolParams::Smb(params) => self.load_bookmark_smb_into_gui(params),
|
||||
ProtocolParams::WebDAV(params) => self.load_bookmark_webdav_into_gui(params),
|
||||
@@ -189,6 +192,16 @@ impl AuthActivity {
|
||||
self.mount_s3_new_path_style(params.new_path_style);
|
||||
}
|
||||
|
||||
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(""));
|
||||
self.mount_kube_client_key(params.client_key.as_deref().unwrap_or(""));
|
||||
self.mount_kube_username(params.username.as_deref().unwrap_or(""));
|
||||
}
|
||||
|
||||
fn load_bookmark_smb_into_gui(&mut self, params: SmbParams) {
|
||||
self.mount_address(params.address.as_str());
|
||||
#[cfg(unix)]
|
||||
|
||||
@@ -10,8 +10,8 @@ use tuirealm::{Component, Event, MockComponent, NoUserEvent, State, StateValue};
|
||||
|
||||
use super::{FileTransferProtocol, FormMsg, Msg, UiMsg};
|
||||
use crate::ui::activities::auth::{
|
||||
RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_S3, RADIO_PROTOCOL_SCP,
|
||||
RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, RADIO_PROTOCOL_WEBDAV,
|
||||
RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_KUBE, RADIO_PROTOCOL_S3,
|
||||
RADIO_PROTOCOL_SCP, RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, RADIO_PROTOCOL_WEBDAV,
|
||||
};
|
||||
|
||||
// -- protocol
|
||||
@@ -31,9 +31,9 @@ impl ProtocolRadio {
|
||||
.modifiers(BorderType::Rounded),
|
||||
)
|
||||
.choices(if cfg!(smb) {
|
||||
&["SFTP", "SCP", "FTP", "FTPS", "S3", "WebDAV", "SMB"]
|
||||
&["SFTP", "SCP", "FTP", "FTPS", "S3", "Kube", "WebDAV", "SMB"]
|
||||
} else {
|
||||
&["SFTP", "SCP", "FTP", "FTPS", "S3", "WebDAV"]
|
||||
&["SFTP", "SCP", "FTP", "FTPS", "S3", "Kube", "WebDAV"]
|
||||
})
|
||||
.foreground(color)
|
||||
.rewind(true)
|
||||
@@ -50,6 +50,7 @@ impl ProtocolRadio {
|
||||
RADIO_PROTOCOL_FTPS => FileTransferProtocol::Ftp(true),
|
||||
RADIO_PROTOCOL_S3 => FileTransferProtocol::AwsS3,
|
||||
RADIO_PROTOCOL_SMB => FileTransferProtocol::Smb,
|
||||
RADIO_PROTOCOL_KUBE => FileTransferProtocol::Kube,
|
||||
RADIO_PROTOCOL_WEBDAV => FileTransferProtocol::WebDAV,
|
||||
_ => FileTransferProtocol::Sftp,
|
||||
}
|
||||
@@ -63,6 +64,7 @@ impl ProtocolRadio {
|
||||
FileTransferProtocol::Ftp(false) => RADIO_PROTOCOL_FTP,
|
||||
FileTransferProtocol::Ftp(true) => RADIO_PROTOCOL_FTPS,
|
||||
FileTransferProtocol::AwsS3 => RADIO_PROTOCOL_S3,
|
||||
FileTransferProtocol::Kube => RADIO_PROTOCOL_KUBE,
|
||||
FileTransferProtocol::Smb => RADIO_PROTOCOL_SMB,
|
||||
FileTransferProtocol::WebDAV => RADIO_PROTOCOL_WEBDAV,
|
||||
}
|
||||
@@ -827,3 +829,252 @@ impl Component<Msg, NoUserEvent> 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<Msg, NoUserEvent> for InputKubePodName {
|
||||
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||
handle_input_ev(
|
||||
self,
|
||||
ev,
|
||||
Msg::Ui(UiMsg::KubePodNameBlurDown),
|
||||
Msg::Ui(UiMsg::KubePodNameBlurUp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(MockComponent)]
|
||||
pub struct InputKubeNamespace {
|
||||
component: Input,
|
||||
}
|
||||
|
||||
impl InputKubeNamespace {
|
||||
pub fn new(bucket: &str, color: Color) -> Self {
|
||||
Self {
|
||||
component: Input::default()
|
||||
.borders(
|
||||
Borders::default()
|
||||
.color(color)
|
||||
.modifiers(BorderType::Rounded),
|
||||
)
|
||||
.foreground(color)
|
||||
.placeholder("namespace", Style::default().fg(Color::Rgb(128, 128, 128)))
|
||||
.title("Pod namespace (optional)", Alignment::Left)
|
||||
.input_type(InputType::Text)
|
||||
.value(bucket),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component<Msg, NoUserEvent> for InputKubeNamespace {
|
||||
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||
handle_input_ev(
|
||||
self,
|
||||
ev,
|
||||
Msg::Ui(UiMsg::KubeNamespaceBlurDown),
|
||||
Msg::Ui(UiMsg::KubeNamespaceBlurUp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(MockComponent)]
|
||||
pub struct InputKubeClusterUrl {
|
||||
component: Input,
|
||||
}
|
||||
|
||||
impl InputKubeClusterUrl {
|
||||
pub fn new(bucket: &str, color: Color) -> Self {
|
||||
Self {
|
||||
component: Input::default()
|
||||
.borders(
|
||||
Borders::default()
|
||||
.color(color)
|
||||
.modifiers(BorderType::Rounded),
|
||||
)
|
||||
.foreground(color)
|
||||
.placeholder(
|
||||
"cluster url",
|
||||
Style::default().fg(Color::Rgb(128, 128, 128)),
|
||||
)
|
||||
.title("Kube cluster url (optional)", Alignment::Left)
|
||||
.input_type(InputType::Text)
|
||||
.value(bucket),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component<Msg, NoUserEvent> for InputKubeClusterUrl {
|
||||
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||
handle_input_ev(
|
||||
self,
|
||||
ev,
|
||||
Msg::Ui(UiMsg::KubeClusterUrlBlurDown),
|
||||
Msg::Ui(UiMsg::KubeClusterUrlBlurUp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[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<Msg, NoUserEvent> for InputKubeContainer {
|
||||
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||
handle_input_ev(
|
||||
self,
|
||||
ev,
|
||||
Msg::Ui(UiMsg::KubeContainerBlurDown),
|
||||
Msg::Ui(UiMsg::KubeContainerBlurUp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(MockComponent)]
|
||||
pub struct InputKubeUsername {
|
||||
component: Input,
|
||||
}
|
||||
|
||||
impl InputKubeUsername {
|
||||
pub fn new(bucket: &str, color: Color) -> Self {
|
||||
Self {
|
||||
component: Input::default()
|
||||
.borders(
|
||||
Borders::default()
|
||||
.color(color)
|
||||
.modifiers(BorderType::Rounded),
|
||||
)
|
||||
.foreground(color)
|
||||
.placeholder("username", Style::default().fg(Color::Rgb(128, 128, 128)))
|
||||
.title("Kube username (optional)", Alignment::Left)
|
||||
.input_type(InputType::Text)
|
||||
.value(bucket),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component<Msg, NoUserEvent> for InputKubeUsername {
|
||||
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||
handle_input_ev(
|
||||
self,
|
||||
ev,
|
||||
Msg::Ui(UiMsg::KubeUsernameBlurDown),
|
||||
Msg::Ui(UiMsg::KubeUsernameBlurUp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(MockComponent)]
|
||||
pub struct InputKubeClientCert {
|
||||
component: Input,
|
||||
}
|
||||
|
||||
impl InputKubeClientCert {
|
||||
pub fn new(bucket: &str, color: Color) -> Self {
|
||||
Self {
|
||||
component: Input::default()
|
||||
.borders(
|
||||
Borders::default()
|
||||
.color(color)
|
||||
.modifiers(BorderType::Rounded),
|
||||
)
|
||||
.foreground(color)
|
||||
.placeholder(
|
||||
"/home/user/.kube/client.crt",
|
||||
Style::default().fg(Color::Rgb(128, 128, 128)),
|
||||
)
|
||||
.title("Kube client cert path (optional)", Alignment::Left)
|
||||
.input_type(InputType::Text)
|
||||
.value(bucket),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component<Msg, NoUserEvent> for InputKubeClientCert {
|
||||
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||
handle_input_ev(
|
||||
self,
|
||||
ev,
|
||||
Msg::Ui(UiMsg::KubeClientCertBlurDown),
|
||||
Msg::Ui(UiMsg::KubeClientCertBlurUp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(MockComponent)]
|
||||
pub struct InputKubeClientKey {
|
||||
component: Input,
|
||||
}
|
||||
|
||||
impl InputKubeClientKey {
|
||||
pub fn new(bucket: &str, color: Color) -> Self {
|
||||
Self {
|
||||
component: Input::default()
|
||||
.borders(
|
||||
Borders::default()
|
||||
.color(color)
|
||||
.modifiers(BorderType::Rounded),
|
||||
)
|
||||
.foreground(color)
|
||||
.placeholder(
|
||||
"/home/user/.kube/client.key",
|
||||
Style::default().fg(Color::Rgb(128, 128, 128)),
|
||||
)
|
||||
.title("Kube client key path (optional)", Alignment::Left)
|
||||
.input_type(InputType::Text)
|
||||
.value(bucket),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component<Msg, NoUserEvent> for InputKubeClientKey {
|
||||
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||
handle_input_ev(
|
||||
self,
|
||||
ev,
|
||||
Msg::Ui(UiMsg::KubeClientKeyBlurDown),
|
||||
Msg::Ui(UiMsg::KubeClientKeyBlurUp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,12 @@ pub use bookmarks::{
|
||||
#[cfg(unix)]
|
||||
pub use form::InputSmbWorkgroup;
|
||||
pub use form::{
|
||||
InputAddress, InputLocalDirectory, InputPassword, InputPort, InputRemoteDirectory,
|
||||
InputS3AccessKey, InputS3Bucket, InputS3Endpoint, InputS3Profile, InputS3Region,
|
||||
InputS3SecretAccessKey, InputS3SecurityToken, InputS3SessionToken, InputSmbShare,
|
||||
InputUsername, InputWebDAVUri, ProtocolRadio, RadioS3NewPathStyle,
|
||||
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,
|
||||
};
|
||||
pub use popup::{
|
||||
ErrorPopup, InfoPopup, InstallUpdatePopup, Keybindings, QuitPopup, ReleaseNotes, WaitPopup,
|
||||
|
||||
@@ -14,6 +14,7 @@ impl AuthActivity {
|
||||
FileTransferProtocol::Sftp | FileTransferProtocol::Scp => 22,
|
||||
FileTransferProtocol::Ftp(_) => 21,
|
||||
FileTransferProtocol::AwsS3 => 22, // Doesn't matter, since not used
|
||||
FileTransferProtocol::Kube => 22, // Doesn't matter, since not used
|
||||
FileTransferProtocol::Smb => 445,
|
||||
FileTransferProtocol::WebDAV => 80, // Doesn't matter, since not used
|
||||
}
|
||||
@@ -38,6 +39,7 @@ impl AuthActivity {
|
||||
pub(super) fn collect_host_params(&self) -> Result<FileTransferParams, &'static str> {
|
||||
match self.protocol {
|
||||
FileTransferProtocol::AwsS3 => self.collect_s3_host_params(),
|
||||
FileTransferProtocol::Kube => self.collect_kube_host_params(),
|
||||
FileTransferProtocol::Smb => self.collect_smb_host_params(),
|
||||
FileTransferProtocol::Ftp(_)
|
||||
| FileTransferProtocol::Scp
|
||||
@@ -80,6 +82,20 @@ 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<FileTransferParams, &'static str> {
|
||||
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),
|
||||
local_path: self.get_input_local_directory(),
|
||||
remote_path: self.get_input_remote_directory(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn collect_smb_host_params(&self) -> Result<FileTransferParams, &'static str> {
|
||||
let params = self.get_smb_params_input();
|
||||
if params.address.is_empty() {
|
||||
|
||||
@@ -29,8 +29,9 @@ const RADIO_PROTOCOL_SCP: usize = 1;
|
||||
const RADIO_PROTOCOL_FTP: usize = 2;
|
||||
const RADIO_PROTOCOL_FTPS: usize = 3;
|
||||
const RADIO_PROTOCOL_S3: usize = 4;
|
||||
const RADIO_PROTOCOL_WEBDAV: usize = 5;
|
||||
const RADIO_PROTOCOL_SMB: usize = 6;
|
||||
const RADIO_PROTOCOL_KUBE: usize = 5;
|
||||
const RADIO_PROTOCOL_WEBDAV: usize = 6;
|
||||
const RADIO_PROTOCOL_SMB: usize = 7;
|
||||
|
||||
// -- components
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
||||
@@ -47,6 +48,13 @@ pub enum Id {
|
||||
InfoPopup,
|
||||
InstallUpdatePopup,
|
||||
Keybindings,
|
||||
KubePodName,
|
||||
KubeContainer,
|
||||
KubeNamespace,
|
||||
KubeClusterUrl,
|
||||
KubeUsername,
|
||||
KubeClientCert,
|
||||
KubeClientKey,
|
||||
LocalDirectory,
|
||||
NewVersionChangelog,
|
||||
NewVersionDisclaimer,
|
||||
@@ -111,6 +119,20 @@ pub enum UiMsg {
|
||||
CloseKeybindingsPopup,
|
||||
CloseQuitPopup,
|
||||
CloseSaveBookmark,
|
||||
KubePodNameBlurDown,
|
||||
KubePodNameBlurUp,
|
||||
KubeContainerBlurDown,
|
||||
KubeContainerBlurUp,
|
||||
KubeNamespaceBlurDown,
|
||||
KubeNamespaceBlurUp,
|
||||
KubeClusterUrlBlurDown,
|
||||
KubeClusterUrlBlurUp,
|
||||
KubeUsernameBlurDown,
|
||||
KubeUsernameBlurUp,
|
||||
KubeClientCertBlurDown,
|
||||
KubeClientCertBlurUp,
|
||||
KubeClientKeyBlurDown,
|
||||
KubeClientKeyBlurUp,
|
||||
LocalDirectoryBlurDown,
|
||||
LocalDirectoryBlurUp,
|
||||
ParamsFormBlur,
|
||||
@@ -167,6 +189,7 @@ pub enum UiMsg {
|
||||
enum InputMask {
|
||||
Generic,
|
||||
AwsS3,
|
||||
Kube,
|
||||
Smb,
|
||||
WebDAV,
|
||||
}
|
||||
@@ -244,6 +267,7 @@ impl AuthActivity {
|
||||
FileTransferProtocol::Ftp(_)
|
||||
| FileTransferProtocol::Scp
|
||||
| FileTransferProtocol::Sftp => InputMask::Generic,
|
||||
FileTransferProtocol::Kube => InputMask::Kube,
|
||||
FileTransferProtocol::Smb => InputMask::Smb,
|
||||
FileTransferProtocol::WebDAV => InputMask::WebDAV,
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ impl AuthActivity {
|
||||
InputMask::Generic => &Id::Password,
|
||||
InputMask::Smb => &Id::Password,
|
||||
InputMask::AwsS3 => &Id::S3Bucket,
|
||||
InputMask::Kube => &Id::KubePodName,
|
||||
InputMask::WebDAV => &Id::Password,
|
||||
})
|
||||
.is_ok());
|
||||
@@ -83,6 +84,7 @@ impl AuthActivity {
|
||||
InputMask::Generic => &Id::Password,
|
||||
InputMask::Smb => &Id::Password,
|
||||
InputMask::AwsS3 => &Id::S3Bucket,
|
||||
InputMask::Kube => &Id::KubePodName,
|
||||
InputMask::WebDAV => &Id::Password,
|
||||
})
|
||||
.is_ok());
|
||||
@@ -179,6 +181,7 @@ impl AuthActivity {
|
||||
#[cfg(windows)]
|
||||
InputMask::Smb => &Id::RemoteDirectory,
|
||||
InputMask::AwsS3 => panic!("this shouldn't happen (password on s3)"),
|
||||
InputMask::Kube => panic!("this shouldn't happen (password on kube)"),
|
||||
InputMask::WebDAV => &Id::RemoteDirectory,
|
||||
})
|
||||
.is_ok());
|
||||
@@ -192,8 +195,8 @@ impl AuthActivity {
|
||||
.active(match self.input_mask() {
|
||||
InputMask::Generic => &Id::Username,
|
||||
InputMask::Smb => &Id::SmbShare,
|
||||
InputMask::AwsS3 | InputMask::WebDAV =>
|
||||
panic!("this shouldn't happen (port on s3)"),
|
||||
InputMask::AwsS3 | InputMask::Kube | InputMask::WebDAV =>
|
||||
panic!("this shouldn't happen (port on s3/kube/webdav)"),
|
||||
})
|
||||
.is_ok());
|
||||
}
|
||||
@@ -207,6 +210,7 @@ impl AuthActivity {
|
||||
InputMask::Generic => &Id::Address,
|
||||
InputMask::Smb => &Id::Address,
|
||||
InputMask::AwsS3 => &Id::S3Bucket,
|
||||
InputMask::Kube => &Id::KubePodName,
|
||||
InputMask::WebDAV => &Id::WebDAVUri,
|
||||
})
|
||||
.is_ok());
|
||||
@@ -229,6 +233,7 @@ impl AuthActivity {
|
||||
InputMask::Smb => &Id::SmbWorkgroup,
|
||||
#[cfg(windows)]
|
||||
InputMask::Smb => &Id::Password,
|
||||
InputMask::Kube => &Id::KubeClientKey,
|
||||
InputMask::AwsS3 => &Id::S3NewPathStyle,
|
||||
InputMask::WebDAV => &Id::Password,
|
||||
})
|
||||
@@ -288,6 +293,48 @@ impl AuthActivity {
|
||||
UiMsg::S3NewPathStyleBlurUp => {
|
||||
assert!(self.app.active(&Id::S3SessionToken).is_ok());
|
||||
}
|
||||
UiMsg::KubeClientCertBlurDown => {
|
||||
assert!(self.app.active(&Id::KubeClientKey).is_ok());
|
||||
}
|
||||
UiMsg::KubeClientCertBlurUp => {
|
||||
assert!(self.app.active(&Id::KubeUsername).is_ok());
|
||||
}
|
||||
UiMsg::KubeClientKeyBlurDown => {
|
||||
assert!(self.app.active(&Id::RemoteDirectory).is_ok());
|
||||
}
|
||||
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());
|
||||
}
|
||||
UiMsg::KubeClusterUrlBlurDown => {
|
||||
assert!(self.app.active(&Id::KubeUsername).is_ok());
|
||||
}
|
||||
UiMsg::KubeClusterUrlBlurUp => {
|
||||
assert!(self.app.active(&Id::KubeNamespace).is_ok());
|
||||
}
|
||||
UiMsg::KubeUsernameBlurDown => {
|
||||
assert!(self.app.active(&Id::KubeClientCert).is_ok());
|
||||
}
|
||||
UiMsg::KubeUsernameBlurUp => {
|
||||
assert!(self.app.active(&Id::KubeClusterUrl).is_ok());
|
||||
}
|
||||
UiMsg::SmbShareBlurDown => {
|
||||
assert!(self.app.active(&Id::Username).is_ok());
|
||||
}
|
||||
@@ -337,6 +384,7 @@ impl AuthActivity {
|
||||
.active(match self.input_mask() {
|
||||
InputMask::Generic => &Id::Port,
|
||||
InputMask::Smb => &Id::SmbShare,
|
||||
InputMask::Kube => panic!("this shouldn't happen (username on kube)"),
|
||||
InputMask::AwsS3 => panic!("this shouldn't happen (username on s3)"),
|
||||
InputMask::WebDAV => &Id::WebDAVUri,
|
||||
})
|
||||
|
||||
@@ -13,7 +13,8 @@ use tuirealm::{State, StateValue, Sub, SubClause, SubEventClause};
|
||||
|
||||
use super::{components, AuthActivity, Context, FileTransferProtocol, Id, InputMask};
|
||||
use crate::filetransfer::params::{
|
||||
AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams, WebDAVProtocolParams,
|
||||
AwsS3Params, GenericProtocolParams, KubeProtocolParams, ProtocolParams, SmbParams,
|
||||
WebDAVProtocolParams,
|
||||
};
|
||||
use crate::filetransfer::FileTransferParams;
|
||||
use crate::utils::ui::{Popup, Size};
|
||||
@@ -60,6 +61,13 @@ impl AuthActivity {
|
||||
self.mount_s3_security_token("");
|
||||
self.mount_s3_session_token("");
|
||||
self.mount_s3_new_path_style(false);
|
||||
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)]
|
||||
self.mount_smb_workgroup("");
|
||||
@@ -155,6 +163,16 @@ impl AuthActivity {
|
||||
)
|
||||
.direction(Direction::Vertical)
|
||||
.split(auth_chunks[4]),
|
||||
InputMask::Kube => Layout::default()
|
||||
.constraints([
|
||||
Constraint::Length(3), // ...
|
||||
Constraint::Length(3), // ...
|
||||
Constraint::Length(3), // ...
|
||||
Constraint::Length(3), // ...
|
||||
Constraint::Length(3), // remote directory
|
||||
])
|
||||
.direction(Direction::Vertical)
|
||||
.split(auth_chunks[4]),
|
||||
InputMask::Generic => Layout::default()
|
||||
.constraints(
|
||||
[
|
||||
@@ -238,6 +256,13 @@ impl AuthActivity {
|
||||
self.app.view(&view_ids[2], f, input_mask[2]);
|
||||
self.app.view(&view_ids[3], f, input_mask[3]);
|
||||
}
|
||||
InputMask::Kube => {
|
||||
let view_ids = self.get_kube_view();
|
||||
self.app.view(&view_ids[0], f, input_mask[0]);
|
||||
self.app.view(&view_ids[1], f, input_mask[1]);
|
||||
self.app.view(&view_ids[2], f, input_mask[2]);
|
||||
self.app.view(&view_ids[3], f, input_mask[3]);
|
||||
}
|
||||
InputMask::Smb => {
|
||||
let view_ids = self.get_smb_view();
|
||||
self.app.view(&view_ids[0], f, input_mask[0]);
|
||||
@@ -791,6 +816,90 @@ 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
|
||||
.app
|
||||
.remount(
|
||||
Id::KubeNamespace,
|
||||
Box::new(components::InputKubeNamespace::new(value, color)),
|
||||
vec![]
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
pub(super) fn mount_kube_cluster_url(&mut self, value: &str) {
|
||||
let color = self.theme().auth_username;
|
||||
assert!(self
|
||||
.app
|
||||
.remount(
|
||||
Id::KubeClusterUrl,
|
||||
Box::new(components::InputKubeClusterUrl::new(value, color)),
|
||||
vec![]
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
pub(super) fn mount_kube_username(&mut self, value: &str) {
|
||||
let color = self.theme().auth_password;
|
||||
assert!(self
|
||||
.app
|
||||
.remount(
|
||||
Id::KubeUsername,
|
||||
Box::new(components::InputKubeUsername::new(value, color)),
|
||||
vec![]
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
pub(super) fn mount_kube_client_cert(&mut self, value: &str) {
|
||||
let color = self.theme().auth_address;
|
||||
assert!(self
|
||||
.app
|
||||
.remount(
|
||||
Id::KubeClientCert,
|
||||
Box::new(components::InputKubeClientCert::new(value, color)),
|
||||
vec![]
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
pub(super) fn mount_kube_client_key(&mut self, value: &str) {
|
||||
let color = self.theme().auth_port;
|
||||
assert!(self
|
||||
.app
|
||||
.remount(
|
||||
Id::KubeClientKey,
|
||||
Box::new(components::InputKubeClientKey::new(value, color)),
|
||||
vec![]
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
pub(crate) fn mount_smb_share(&mut self, share: &str) {
|
||||
let color = self.theme().auth_password;
|
||||
assert!(self
|
||||
@@ -863,6 +972,26 @@ impl AuthActivity {
|
||||
.new_path_style(new_path_style)
|
||||
}
|
||||
|
||||
/// 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,
|
||||
client_cert,
|
||||
client_key,
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect s3 input values from view
|
||||
#[cfg(unix)]
|
||||
pub(super) fn get_smb_params_input(&self) -> SmbParams {
|
||||
@@ -1025,6 +1154,55 @@ 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<String> {
|
||||
match self.app.state(&Id::KubeNamespace) {
|
||||
Ok(State::One(StateValue::String(x))) if !x.is_empty() => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_input_kube_cluster_url(&self) -> Option<String> {
|
||||
match self.app.state(&Id::KubeClusterUrl) {
|
||||
Ok(State::One(StateValue::String(x))) if !x.is_empty() => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_input_kube_username(&self) -> Option<String> {
|
||||
match self.app.state(&Id::KubeUsername) {
|
||||
Ok(State::One(StateValue::String(x))) if !x.is_empty() => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_input_kube_client_cert(&self) -> Option<String> {
|
||||
match self.app.state(&Id::KubeClientCert) {
|
||||
Ok(State::One(StateValue::String(x))) if !x.is_empty() => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_input_kube_client_key(&self) -> Option<String> {
|
||||
match self.app.state(&Id::KubeClientKey) {
|
||||
Ok(State::One(StateValue::String(x))) if !x.is_empty() => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_input_smb_share(&self) -> String {
|
||||
match self.app.state(&Id::SmbShare) {
|
||||
Ok(State::One(StateValue::String(x))) => x,
|
||||
@@ -1063,6 +1241,7 @@ impl AuthActivity {
|
||||
match self.input_mask() {
|
||||
InputMask::AwsS3 => 12,
|
||||
InputMask::Generic => 12,
|
||||
InputMask::Kube => 12,
|
||||
InputMask::Smb => 12,
|
||||
InputMask::WebDAV => 12,
|
||||
}
|
||||
@@ -1104,6 +1283,24 @@ impl AuthActivity {
|
||||
protocol, username, params.address, params.port
|
||||
)
|
||||
}
|
||||
ProtocolParams::Kube(params) => {
|
||||
format!(
|
||||
"{}://{}@{}{}{}",
|
||||
protocol,
|
||||
params.container,
|
||||
params.pod,
|
||||
params
|
||||
.namespace
|
||||
.as_deref()
|
||||
.map(|x| format!("/{x}"))
|
||||
.unwrap_or_default(),
|
||||
params
|
||||
.cluster_url
|
||||
.as_deref()
|
||||
.map(|x| format!("@{x}"))
|
||||
.unwrap_or_default()
|
||||
)
|
||||
}
|
||||
#[cfg(unix)]
|
||||
ProtocolParams::Smb(params) => {
|
||||
let username: String = match params.username {
|
||||
@@ -1189,6 +1386,54 @@ 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,
|
||||
Id::KubeUsername,
|
||||
Id::KubeClientCert,
|
||||
],
|
||||
Some(&Id::KubeClientKey) => [
|
||||
Id::KubeClusterUrl,
|
||||
Id::KubeUsername,
|
||||
Id::KubeClientCert,
|
||||
Id::KubeClientKey,
|
||||
],
|
||||
Some(&Id::RemoteDirectory) => [
|
||||
Id::KubeUsername,
|
||||
Id::KubeClientCert,
|
||||
Id::KubeClientKey,
|
||||
Id::RemoteDirectory,
|
||||
],
|
||||
Some(&Id::LocalDirectory) => [
|
||||
Id::KubeClientCert,
|
||||
Id::KubeClientKey,
|
||||
Id::RemoteDirectory,
|
||||
Id::LocalDirectory,
|
||||
],
|
||||
_ => [
|
||||
Id::KubePodName,
|
||||
Id::KubeContainer,
|
||||
Id::KubeNamespace,
|
||||
Id::KubeClusterUrl,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_smb_view(&self) -> [Id; 4] {
|
||||
match self.app.focus() {
|
||||
|
||||
@@ -111,6 +111,7 @@ 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::Smb(params) => params.address.clone(),
|
||||
ProtocolParams::WebDAV(params) => params.uri.clone(),
|
||||
}
|
||||
@@ -135,6 +136,13 @@ 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)
|
||||
}
|
||||
ProtocolParams::Smb(params) => {
|
||||
info!(
|
||||
"Client is not connected to remote; connecting to {}:{}",
|
||||
|
||||
@@ -12,8 +12,8 @@ use super::{ConfigMsg, Msg};
|
||||
use crate::explorer::GroupDirs as GroupDirsEnum;
|
||||
use crate::filetransfer::FileTransferProtocol;
|
||||
use crate::ui::activities::setup::{
|
||||
RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_S3, RADIO_PROTOCOL_SCP,
|
||||
RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, RADIO_PROTOCOL_WEBDAV,
|
||||
RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_KUBE, RADIO_PROTOCOL_S3,
|
||||
RADIO_PROTOCOL_SCP, RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, RADIO_PROTOCOL_WEBDAV,
|
||||
};
|
||||
use crate::utils::parser::parse_bytesize;
|
||||
|
||||
@@ -67,7 +67,7 @@ impl DefaultProtocol {
|
||||
.color(Color::Cyan)
|
||||
.modifiers(BorderType::Rounded),
|
||||
)
|
||||
.choices(&["SFTP", "SCP", "FTP", "FTPS", "S3", "SMB", "WebDAV"])
|
||||
.choices(&["SFTP", "SCP", "FTP", "FTPS", "Kube", "S3", "SMB", "WebDAV"])
|
||||
.foreground(Color::Cyan)
|
||||
.rewind(true)
|
||||
.title("Default protocol", Alignment::Left)
|
||||
@@ -76,6 +76,7 @@ impl DefaultProtocol {
|
||||
FileTransferProtocol::Scp => RADIO_PROTOCOL_SCP,
|
||||
FileTransferProtocol::Ftp(false) => RADIO_PROTOCOL_FTP,
|
||||
FileTransferProtocol::Ftp(true) => RADIO_PROTOCOL_FTPS,
|
||||
FileTransferProtocol::Kube => RADIO_PROTOCOL_KUBE,
|
||||
FileTransferProtocol::AwsS3 => RADIO_PROTOCOL_S3,
|
||||
FileTransferProtocol::Smb => RADIO_PROTOCOL_SMB,
|
||||
FileTransferProtocol::WebDAV => RADIO_PROTOCOL_WEBDAV,
|
||||
|
||||
@@ -29,9 +29,10 @@ const RADIO_PROTOCOL_SFTP: usize = 0;
|
||||
const RADIO_PROTOCOL_SCP: usize = 1;
|
||||
const RADIO_PROTOCOL_FTP: usize = 2;
|
||||
const RADIO_PROTOCOL_FTPS: usize = 3;
|
||||
const RADIO_PROTOCOL_S3: usize = 4;
|
||||
const RADIO_PROTOCOL_SMB: usize = 5;
|
||||
const RADIO_PROTOCOL_WEBDAV: usize = 6;
|
||||
const RADIO_PROTOCOL_KUBE: usize = 4;
|
||||
const RADIO_PROTOCOL_S3: usize = 5;
|
||||
const RADIO_PROTOCOL_SMB: usize = 6;
|
||||
const RADIO_PROTOCOL_WEBDAV: usize = 7;
|
||||
|
||||
// -- components
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
||||
|
||||
@@ -11,7 +11,8 @@ use tuirealm::tui::layout::{Constraint, Direction, Layout};
|
||||
use tuirealm::{State, StateValue};
|
||||
|
||||
use super::{
|
||||
components, Context, Id, IdCommon, IdConfig, SetupActivity, ViewLayout, RADIO_PROTOCOL_WEBDAV,
|
||||
components, Context, Id, IdCommon, IdConfig, SetupActivity, ViewLayout, RADIO_PROTOCOL_KUBE,
|
||||
RADIO_PROTOCOL_WEBDAV,
|
||||
};
|
||||
use crate::explorer::GroupDirs;
|
||||
use crate::filetransfer::FileTransferProtocol;
|
||||
@@ -277,6 +278,7 @@ impl SetupActivity {
|
||||
RADIO_PROTOCOL_SCP => FileTransferProtocol::Scp,
|
||||
RADIO_PROTOCOL_FTP => FileTransferProtocol::Ftp(false),
|
||||
RADIO_PROTOCOL_FTPS => FileTransferProtocol::Ftp(true),
|
||||
RADIO_PROTOCOL_KUBE => FileTransferProtocol::Kube,
|
||||
RADIO_PROTOCOL_S3 => FileTransferProtocol::AwsS3,
|
||||
RADIO_PROTOCOL_SMB => FileTransferProtocol::Smb,
|
||||
RADIO_PROTOCOL_WEBDAV => FileTransferProtocol::WebDAV,
|
||||
|
||||
@@ -15,7 +15,7 @@ use tuirealm::utils::parser as tuirealm_parser;
|
||||
#[cfg(smb)]
|
||||
use crate::filetransfer::params::SmbParams;
|
||||
use crate::filetransfer::params::{
|
||||
AwsS3Params, GenericProtocolParams, ProtocolParams, WebDAVProtocolParams,
|
||||
AwsS3Params, GenericProtocolParams, KubeProtocolParams, ProtocolParams, WebDAVProtocolParams,
|
||||
};
|
||||
use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
|
||||
#[cfg(not(test))] // NOTE: don't use configuration during tests
|
||||
@@ -53,7 +53,15 @@ static REMOTE_GENERIC_OPT_REGEX: Lazy<Regex> = lazy_regex!(
|
||||
* - group 4: Some(path) | None
|
||||
*/
|
||||
static REMOTE_WEBDAV_OPT_REGEX: Lazy<Regex> =
|
||||
lazy_regex!(r"(?:([^:]+):)(?:(.+[^@])@)(?:([^/]+))(?:/(.+))?");
|
||||
lazy_regex!(r"(?:([^:]+):)(?:(.+[^@])@)(?:([^/]+))(?:(.+))?");
|
||||
|
||||
/**
|
||||
* Regex matches: {container}@{pod}/{path}
|
||||
* - group 1: Container
|
||||
* - group 2: Pod
|
||||
* - group 3: Some(path) | None
|
||||
*/
|
||||
static REMOTE_KUBE_OPT_REGEX: Lazy<Regex> = lazy_regex!(r"(?:(.+[^@])@)(?:([^/]+))(?:(.+))?");
|
||||
|
||||
/**
|
||||
* Regex matches:
|
||||
@@ -162,6 +170,7 @@ pub fn parse_remote_opt(s: &str) -> Result<FileTransferParams, String> {
|
||||
// Match against regex for protocol type
|
||||
match protocol {
|
||||
FileTransferProtocol::AwsS3 => parse_s3_remote_opt(remote.as_str()),
|
||||
FileTransferProtocol::Kube => parse_kube_remote_opt(remote.as_str()),
|
||||
#[cfg(smb)]
|
||||
FileTransferProtocol::Smb => parse_smb_remote_opts(remote.as_str()),
|
||||
FileTransferProtocol::WebDAV => {
|
||||
@@ -302,6 +311,37 @@ fn parse_s3_remote_opt(s: &str) -> Result<FileTransferParams, String> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_kube_remote_opt(s: &str) -> Result<FileTransferParams, String> {
|
||||
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 remote_path: Option<PathBuf> =
|
||||
groups.get(3).map(|group| PathBuf::from(group.as_str()));
|
||||
Ok(FileTransferParams::new(
|
||||
FileTransferProtocol::Kube,
|
||||
ProtocolParams::Kube(KubeProtocolParams {
|
||||
pod,
|
||||
container,
|
||||
namespace: None,
|
||||
cluster_url: None,
|
||||
username: None,
|
||||
client_cert: None,
|
||||
client_key: None,
|
||||
}),
|
||||
)
|
||||
.remote_path(remote_path))
|
||||
}
|
||||
None => Err(String::from("Bad remote host syntax!")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse remote options for smb protocol
|
||||
#[cfg(smb_unix)]
|
||||
fn parse_smb_remote_opts(s: &str) -> Result<FileTransferParams, String> {
|
||||
@@ -630,6 +670,12 @@ mod tests {
|
||||
assert_eq!(params.uri.as_str(), "http://myserver:4445");
|
||||
assert_eq!(params.username.as_str(), "omar");
|
||||
assert_eq!(params.password.as_str(), "password");
|
||||
|
||||
// remote path
|
||||
assert_eq!(
|
||||
result.remote_path.unwrap(),
|
||||
PathBuf::from("/myshare/dir/subdir")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -706,6 +752,24 @@ mod tests {
|
||||
assert_eq!(params.region.as_deref().unwrap(), "eu-central-1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_kube_address() {
|
||||
let result = parse_remote_opt("kube://alpine@my-pod/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.username, None);
|
||||
assert_eq!(params.client_cert, None);
|
||||
assert_eq!(params.client_key, None);
|
||||
assert_eq!(
|
||||
result.remote_path.as_deref().unwrap(),
|
||||
std::path::Path::new("/tmp")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(smb_unix)]
|
||||
fn should_parse_smb_address() {
|
||||
|
||||
Reference in New Issue
Block a user