mirror of
https://github.com/jlengrand/engine.git
synced 2026-03-10 08:11:21 +00:00
340 lines
13 KiB
Rust
340 lines
13 KiB
Rust
use qovery_engine::cloud_provider::helm::{ChartInfo, ChartSetValue, CommonChart, HelmChartNamespaces};
|
|
use qovery_engine::cmd::helm::Helm;
|
|
|
|
use serde_derive::Deserialize;
|
|
use serde_derive::Serialize;
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use test_utilities::utilities::FuncTestsSecrets;
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Certificate {
|
|
pub api_version: String,
|
|
pub items: Vec<Item>,
|
|
pub kind: String,
|
|
pub metadata: Metadata2,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Item {
|
|
pub api_version: String,
|
|
pub kind: String,
|
|
pub metadata: Metadata,
|
|
pub spec: Spec,
|
|
pub status: Status,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Metadata {
|
|
pub annotations: Annotations,
|
|
pub creation_timestamp: String,
|
|
pub generation: i64,
|
|
pub labels: Labels,
|
|
pub name: String,
|
|
pub namespace: String,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Annotations {
|
|
#[serde(rename = "meta.helm.sh/release-name")]
|
|
pub meta_helm_sh_release_name: String,
|
|
#[serde(rename = "meta.helm.sh/release-namespace")]
|
|
pub meta_helm_sh_release_namespace: String,
|
|
#[serde(default, rename = "kubectl.kubernetes.io/last-applied-configuration")]
|
|
pub last_applied_configuration: String,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Labels {
|
|
#[serde(rename = "app.kubernetes.io/managed-by")]
|
|
pub app_kubernetes_io_managed_by: String,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Spec {
|
|
pub dns_names: Vec<String>,
|
|
pub issuer_ref: IssuerRef,
|
|
pub secret_name: String,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct IssuerRef {
|
|
pub kind: String,
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Status {}
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Metadata2 {
|
|
pub self_link: String,
|
|
}
|
|
|
|
#[allow(dead_code)] // TODO(pmavro): fix this by using the correct tag
|
|
fn cert_manager_conf() -> (Helm, PathBuf, CommonChart, CommonChart) {
|
|
let vault_secrets = FuncTestsSecrets::new();
|
|
let mut kube_config = dirs::home_dir().unwrap();
|
|
kube_config.push(".kube/config");
|
|
let helm = Helm::new(kube_config.to_str().unwrap(), &[]).unwrap();
|
|
let cert_manager = CommonChart {
|
|
chart_info: ChartInfo {
|
|
name: "cert-manager".to_string(),
|
|
path: "lib/common/bootstrap/charts/cert-manager".to_string(),
|
|
namespace: HelmChartNamespaces::CertManager,
|
|
values: vec![
|
|
ChartSetValue {
|
|
key: "installCRDs".to_string(),
|
|
value: "true".to_string(),
|
|
},
|
|
ChartSetValue {
|
|
key: "replicaCount".to_string(),
|
|
value: "1".to_string(),
|
|
},
|
|
// https://cert-manager.io/docs/configuration/acme/dns01/#setting-nameservers-for-dns01-self-check
|
|
ChartSetValue {
|
|
key: "extraArgs".to_string(),
|
|
value: "{--dns01-recursive-nameservers-only,--dns01-recursive-nameservers=1.1.1.1:53\\,8.8.8.8:53}"
|
|
.to_string(),
|
|
},
|
|
ChartSetValue {
|
|
key: "prometheus.servicemonitor.enabled".to_string(),
|
|
// Due to cycle, prometheus need tls certificate from cert manager, and enabling this will require
|
|
// prometheus to be already installed
|
|
value: "false".to_string(),
|
|
},
|
|
ChartSetValue {
|
|
key: "prometheus.servicemonitor.prometheusInstance".to_string(),
|
|
value: "qovery".to_string(),
|
|
},
|
|
],
|
|
..Default::default()
|
|
},
|
|
};
|
|
|
|
let cert_manager_config = CommonChart {
|
|
chart_info: ChartInfo {
|
|
name: "cert-manager-configs".to_string(),
|
|
path: "lib/common/bootstrap/charts/cert-manager-configs".to_string(),
|
|
namespace: HelmChartNamespaces::CertManager,
|
|
values: vec![
|
|
ChartSetValue {
|
|
key: "externalDnsProvider".to_string(),
|
|
value: "cloudflare".to_string(),
|
|
},
|
|
ChartSetValue {
|
|
key: "provider.cloudflare.apiToken".to_string(),
|
|
value: vault_secrets.CLOUDFLARE_TOKEN.unwrap(),
|
|
},
|
|
ChartSetValue {
|
|
key: "provider.cloudflare.email".to_string(),
|
|
value: vault_secrets.CLOUDFLARE_ID.as_ref().unwrap().to_string(),
|
|
},
|
|
ChartSetValue {
|
|
key: "acme.letsEncrypt.emailReport".to_string(),
|
|
value: vault_secrets.CLOUDFLARE_ID.unwrap(),
|
|
},
|
|
ChartSetValue {
|
|
key: "acme.letsEncrypt.acmeUrl".to_string(),
|
|
value: "https://acme-staging-v02.api.letsencrypt.org/directory".to_string(),
|
|
},
|
|
],
|
|
..Default::default()
|
|
},
|
|
};
|
|
|
|
(helm, kube_config, cert_manager, cert_manager_config)
|
|
}
|
|
|
|
#[cfg(feature = "test-with-kube")]
|
|
#[test]
|
|
fn test_create_chart_backup() {
|
|
let (helm, kube_config, cert_manager, cert_manager_config) = cert_manager_conf();
|
|
|
|
let lvl_1: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager.clone())];
|
|
let lvl_2: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager_config.clone())];
|
|
|
|
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_1], false).map_err(|_| assert!(false));
|
|
|
|
sleep(Duration::from_secs(30));
|
|
|
|
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_2], false).map_err(|_| assert!(false));
|
|
|
|
let tmp_dir = TempDir::new("workspace_directory").expect("error creating temporary dir");
|
|
let root_dir_path = Path::new(tmp_dir.path());
|
|
let backup_infos = helm
|
|
.prepare_chart_backup(root_dir_path, &cert_manager.chart_info, &vec![], vec!["cert".to_string()])
|
|
.unwrap();
|
|
let secrets = kubectl_exec_get_secrets(
|
|
kube_config.as_path(),
|
|
cert_manager.chart_info.namespace.to_string().as_str(),
|
|
"",
|
|
vec![],
|
|
)
|
|
.unwrap();
|
|
assert_eq!(backup_infos.len(), 1);
|
|
|
|
for backup_info in backup_infos {
|
|
let backup_name = format!("{}-{}-q-backup", &cert_manager.chart_info.name, backup_info.name.clone());
|
|
assert!(Path::new(backup_info.path.as_str()).exists());
|
|
let secret = secrets
|
|
.items
|
|
.clone()
|
|
.into_iter()
|
|
.filter(|secret| secret.metadata.name == backup_name)
|
|
.collect::<Vec<SecretItem>>();
|
|
let secret_content = decode(secret[0].data[&backup_info.name].clone()).unwrap();
|
|
let content = from_utf8(secret_content.as_slice()).unwrap().to_string();
|
|
let file = OpenOptions::new().read(true).open(backup_info.path.as_str()).unwrap();
|
|
let file_content = BufReader::new(file.try_clone().unwrap())
|
|
.lines()
|
|
.map(|line| line.unwrap())
|
|
.collect::<Vec<String>>()
|
|
.join("\n");
|
|
assert_ne!(content.len(), 0);
|
|
assert_ne!(file_content.len(), 0);
|
|
assert!(content.contains(&file_content));
|
|
}
|
|
|
|
let _ = kubectl_exec_delete_namespace(kube_config.as_path(), "cert-manager", vec![]);
|
|
}
|
|
|
|
#[cfg(feature = "test-with-kube")]
|
|
#[test]
|
|
fn test_apply_chart_backup() {
|
|
let (helm, kube_config, cert_manager, cert_manager_config) = cert_manager_conf();
|
|
|
|
let lvl_1: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager.clone())];
|
|
let lvl_2: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager_config.clone())];
|
|
|
|
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_1], false).map_err(|_| assert!(false));
|
|
|
|
sleep(Duration::from_secs(30));
|
|
|
|
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_2], false).map_err(|_| assert!(false));
|
|
|
|
let tmp_dir = TempDir::new("workspace_directory").expect("error creating temporary dir");
|
|
let root_dir_path = Path::new(tmp_dir.path());
|
|
let _ = helm
|
|
.prepare_chart_backup(
|
|
root_dir_path,
|
|
cert_manager_config.get_chart_info(),
|
|
&vec![],
|
|
vec!["cert".to_string()],
|
|
)
|
|
.unwrap();
|
|
|
|
match helm.apply_chart_backup(root_dir_path, &vec![], cert_manager_config.get_chart_info()) {
|
|
Err(_) => {
|
|
assert!(false)
|
|
}
|
|
Ok(..) => {
|
|
let string_path = list_yaml_backup_files(root_dir_path).unwrap().first().unwrap().clone();
|
|
let str_path = string_path.as_str();
|
|
let path = Path::new(str_path);
|
|
let backup_string = fs::read_to_string(path).unwrap();
|
|
let cert_string = kubectl_get_resource_yaml(
|
|
kube_config.as_path(),
|
|
vec![],
|
|
"cert",
|
|
Some(cert_manager_config.namespace().as_str()),
|
|
)
|
|
.unwrap();
|
|
let backup_cert = serde_yaml::from_str::<Certificate>(backup_string.as_str()).unwrap();
|
|
let cert = serde_yaml::from_str::<Certificate>(cert_string.as_str()).unwrap();
|
|
assert_eq!(backup_cert.items.first().unwrap().spec, cert.items.first().unwrap().spec)
|
|
}
|
|
};
|
|
|
|
let _ = kubectl_exec_delete_namespace(kube_config.as_path(), "cert-manager", vec![]);
|
|
}
|
|
|
|
#[cfg(feature = "test-with-kube")]
|
|
#[test]
|
|
fn test_should_not_create_chart_backup() {
|
|
let (helm, kube_config, cert_manager, cert_manager_config) = cert_manager_conf();
|
|
|
|
let lvl_1: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager.clone())];
|
|
let lvl_2: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager_config.clone())];
|
|
|
|
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_1], false).map_err(|_| assert!(false));
|
|
|
|
sleep(Duration::from_secs(30));
|
|
|
|
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_2], false).map_err(|_| assert!(false));
|
|
|
|
let tmp_dir = TempDir::new("workspace_directory").expect("error creating temporary dir");
|
|
let root_dir_path = Path::new(tmp_dir.path());
|
|
|
|
// trying to create a backup from an unknown (toto) resource
|
|
let backup_infos = helm
|
|
.prepare_chart_backup(root_dir_path, &cert_manager.chart_info, &vec![], vec!["toto".to_string()])
|
|
.unwrap();
|
|
|
|
assert_eq!(backup_infos.len(), 0);
|
|
|
|
let _ = kubectl_exec_delete_namespace(kube_config.as_path(), "cert-manager", vec![]);
|
|
}
|
|
|
|
#[cfg(feature = "test-with-kube")]
|
|
#[test]
|
|
fn test_should_apply_chart_backup() {
|
|
let (helm, kube_config, cert_manager, mut cert_manager_config) = cert_manager_conf();
|
|
|
|
let lvl_1: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager.clone())];
|
|
let lvl_2: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager_config.clone())];
|
|
|
|
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_1], false).map_err(|_| assert!(false));
|
|
|
|
sleep(Duration::from_secs(30));
|
|
|
|
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_2], false).map_err(|_| assert!(false));
|
|
|
|
sleep(Duration::from_secs(30));
|
|
|
|
cert_manager_config.chart_info.backup_resources = Some(vec!["cert".to_string()]);
|
|
|
|
let lvl_2_bis: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager_config.clone())];
|
|
|
|
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_2_bis], false).map_err(|_| assert!(false));
|
|
|
|
let secrets = kubectl_exec_get_secrets(
|
|
kube_config.as_path(),
|
|
cert_manager.chart_info.namespace.to_string().as_str(),
|
|
"",
|
|
vec![],
|
|
)
|
|
.unwrap();
|
|
|
|
let cert_secret = secrets
|
|
.items
|
|
.into_iter()
|
|
.filter(|secret| secret.metadata.name == "cert-manager-configs-cert-q-backup")
|
|
.collect::<Vec<SecretItem>>();
|
|
|
|
assert_eq!(cert_secret.len(), 0);
|
|
|
|
let cert_string = kubectl_get_resource_yaml(
|
|
kube_config.as_path(),
|
|
vec![],
|
|
"cert",
|
|
Some(cert_manager_config.namespace().as_str()),
|
|
)
|
|
.unwrap();
|
|
let cert = serde_yaml::from_str::<Certificate>(cert_string.as_str()).unwrap();
|
|
|
|
assert_ne!(cert.items[0].metadata.annotations.last_applied_configuration, "");
|
|
|
|
let _ = kubectl_exec_delete_namespace(kube_config.as_path(), "cert-manager", vec![]);
|
|
}
|