use std::net::IpAddr;
use std::str::FromStr;
use thiserror::Error;
use semver::Version;
use k8_config::{ConfigError as K8ConfigError, K8Config};
use url::{Url, ParseError};
use crate::helm::{HelmError, HelmClient};
#[derive(Error, Debug)]
pub enum CheckError {
#[error("The fluvio-sys chart is not installed")]
MissingSystemChart,
#[error("The fluvio-app chart is already installed")]
AlreadyInstalled,
#[error("The minikube context is not active or does not match your minikube ip")]
InvalidMinikubeContext,
#[error("There is no active Kubernetes context")]
NoActiveKubernetesContext,
#[error("Failed to parse server url from Kubernetes context")]
BadKubernetesServerUrl {
#[from]
source: ParseError,
},
#[error("Cannot have multiple versions of fluvio-sys installed")]
MultipleSystemCharts,
#[error("Missing Kubernetes server host")]
MissingKubernetesServerHost,
#[error("Kubernetes server must be a hostname, not an IP address")]
KubernetesServerIsIp,
#[error("Must have helm version {required} or later. You have {installed}")]
IncompatibleHelmVersion {
installed: String,
required: String,
},
#[error("Helm client error")]
HelmError {
#[from]
source: HelmError,
},
#[error("Kubernetes config error")]
K8ConfigError {
#[from]
source: K8ConfigError,
},
}
pub fn check_cluster_server_host() -> Result<(), CheckError> {
let config = K8Config::load()?;
let context = match config {
K8Config::Pod(_) => return Ok(()),
K8Config::KubeConfig(context) => context,
};
let cluster_context = context
.config
.current_cluster()
.ok_or(CheckError::NoActiveKubernetesContext)?;
let server_url = cluster_context.cluster.server.to_owned();
let url =
Url::parse(&server_url).map_err(|source| CheckError::BadKubernetesServerUrl { source })?;
let host = url
.host()
.ok_or(CheckError::MissingKubernetesServerHost)?
.to_string();
if host.is_empty() {
return Err(CheckError::MissingKubernetesServerHost);
}
if IpAddr::from_str(&host).is_ok() {
return Err(CheckError::KubernetesServerIsIp);
}
Ok(())
}
pub fn check_helm_version(helm: &HelmClient, required: &str) -> Result<(), CheckError> {
let helm_version = helm.get_helm_version()?;
if Version::parse(&helm_version) < Version::parse(required) {
return Err(CheckError::IncompatibleHelmVersion {
installed: helm_version,
required: required.to_string(),
});
}
Ok(())
}
pub fn check_system_chart(helm: &HelmClient, sys_repo: &str) -> Result<(), CheckError> {
let sys_charts = helm.get_installed_chart_by_name(sys_repo)?;
if sys_charts.is_empty() {
return Err(CheckError::MissingSystemChart);
} else if sys_charts.len() > 1 {
return Err(CheckError::MultipleSystemCharts);
}
Ok(())
}
pub fn check_already_installed(helm: &HelmClient, app_repo: &str) -> Result<(), CheckError> {
let app_charts = helm.get_installed_chart_by_name(app_repo)?;
if !app_charts.is_empty() {
return Err(CheckError::AlreadyInstalled);
}
Ok(())
}