use anyhow::{Result, bail};
use std::collections::HashMap;
use super::{NetworkProvider, ProviderSpec, reject_unknown_query};
pub struct TshProvider;
impl NetworkProvider for TshProvider {
fn scheme(&self) -> &'static str {
"tsh"
}
fn parse(
&self,
authority: &str,
segments: &[&str],
query: &HashMap<String, String>,
) -> Result<ProviderSpec> {
reject_unknown_query(query, &["local"])?;
match segments {
["app", app_name] => Ok(ProviderSpec::TshApp {
teleport_proxy: authority.to_string(),
app_name: (*app_name).to_string(),
target_port: None,
}),
["app", app_name, target_port] => Ok(ProviderSpec::TshApp {
teleport_proxy: authority.to_string(),
app_name: (*app_name).to_string(),
target_port: Some(target_port.parse::<u16>()?),
}),
[
"kube_cluster",
kube_cluster,
namespace,
kind,
name,
remote_port,
] => Ok(ProviderSpec::TshKubeCluster {
teleport_proxy: authority.to_string(),
kube_cluster: (*kube_cluster).to_string(),
namespace: (*namespace).to_string(),
kind: (*kind).to_string(),
name: (*name).to_string(),
remote_port: remote_port.parse::<u16>()?,
}),
_ => bail!(
"tsh URI must be /app/<app-name>[/<target-port>] or /kube_cluster/<kube-cluster>/<namespace>/<kind>/<name>/<remote-port>"
),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_app() {
let spec = TshProvider
.parse(
"teleport.example.com:443",
&["app", "example-app"],
&HashMap::new(),
)
.expect("parsed");
assert!(matches!(
spec,
ProviderSpec::TshApp {
app_name,
target_port: None,
..
} if app_name == "example-app"
));
}
#[test]
fn parses_app_target_port() {
let spec = TshProvider
.parse(
"teleport.example.com:443",
&["app", "example-app", "3000"],
&HashMap::new(),
)
.expect("parsed");
assert!(matches!(
spec,
ProviderSpec::TshApp {
app_name,
target_port: Some(3000),
..
} if app_name == "example-app"
));
}
#[test]
fn parses_kube_cluster() {
let spec = TshProvider
.parse(
"teleport.example.com:443",
&[
"kube_cluster",
"prod",
"monitoring",
"service",
"grafana",
"3000",
],
&HashMap::new(),
)
.expect("parsed");
assert!(matches!(
spec,
ProviderSpec::TshKubeCluster {
kube_cluster,
namespace,
..
} if kube_cluster == "prod" && namespace == "monitoring"
));
}
}