mirror of
https://github.com/jlengrand/engine.git
synced 2026-03-10 08:11:21 +00:00
Merge branch 'dev' into chore/upgrade_aws_charts
This commit is contained in:
@@ -106,3 +106,6 @@ test-all-whole-enchilada = ["test-aws-whole-enchilada", "test-do-whole-enchilada
|
||||
test-aws-all = ["test-aws-infra", "test-aws-managed-services", "test-aws-self-hosted", "test-aws-whole-enchilada"]
|
||||
test-do-all = ["test-do-infra", "test-do-managed-services", "test-do-self-hosted", "test-do-whole-enchilada"]
|
||||
test-scw-all = ["test-scw-infra", "test-scw-managed-services", "test-scw-self-hosted", "test-scw-whole-enchilada"]
|
||||
|
||||
# functionnal test with only a k8s cluster as a dependency
|
||||
test-with-kube = []
|
||||
|
||||
@@ -505,7 +505,7 @@ controller:
|
||||
|
||||
admissionWebhooks:
|
||||
annotations: {}
|
||||
enabled: true
|
||||
enabled: false
|
||||
failurePolicy: Fail
|
||||
# timeoutSeconds: 10
|
||||
port: 8443
|
||||
|
||||
@@ -1342,7 +1342,7 @@ prometheusOperator:
|
||||
## rules from making their way into prometheus and potentially preventing the container from starting
|
||||
admissionWebhooks:
|
||||
failurePolicy: Fail
|
||||
enabled: true
|
||||
enabled: false
|
||||
## A PEM encoded CA bundle which will be used to validate the webhook's server certificate.
|
||||
## If unspecified, system trust roots on the apiserver are used.
|
||||
caBundle: ""
|
||||
@@ -1377,7 +1377,7 @@ prometheusOperator:
|
||||
|
||||
# Use certmanager to generate webhook certs
|
||||
certManager:
|
||||
enabled: false
|
||||
enabled: true
|
||||
# issuerRef:
|
||||
# name: "issuer"
|
||||
# kind: "ClusterIssuer"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
apiVersion: v2
|
||||
appVersion: 0.10.1
|
||||
appVersion: 0.10.4
|
||||
description: Automatically removes Cloud managed services and Kubernetes resources
|
||||
based on tags with TTL
|
||||
home: https://github.com/Qovery/pleco
|
||||
icon: https://github.com/Qovery/pleco/raw/main/assets/pleco_logo.png
|
||||
name: pleco
|
||||
type: application
|
||||
version: 0.10.1
|
||||
version: 0.10.4
|
||||
|
||||
@@ -148,8 +148,6 @@ spec:
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
env:
|
||||
- name: "AWS_EXECUTION_ENV"
|
||||
value: "pleco_{{ .Values.image.plecoImageTag }}_{{ .Values.environmentVariables.PLECO_IDENTIFIER }}"
|
||||
{{ range $key, $value := .Values.environmentVariables -}}
|
||||
- name: "{{ $key }}"
|
||||
valueFrom:
|
||||
|
||||
@@ -3,7 +3,7 @@ replicaCount: 1
|
||||
image:
|
||||
repository: qoveryrd/pleco
|
||||
pullPolicy: IfNotPresent
|
||||
plecoImageTag: "0.10.1"
|
||||
plecoImageTag: "0.10.4"
|
||||
|
||||
cloudProvider: ""
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ charts:
|
||||
dest: services
|
||||
no_sync: true
|
||||
- name: pleco
|
||||
version: 0.10.1
|
||||
version: 0.10.4
|
||||
repo_name: pleco
|
||||
- name: do-k8s-token-rotate
|
||||
version: 0.1.3
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::cloud_provider::aws::kubernetes::{Options, VpcQoveryNetworkMode};
|
||||
use crate::cloud_provider::helm::{
|
||||
get_chart_for_shell_agent, get_engine_helm_action_from_location, ChartInfo, ChartPayload, ChartSetValue,
|
||||
ChartValuesGenerated, CommonChart, CoreDNSConfigChart, HelmAction, HelmChart, HelmChartNamespaces,
|
||||
ChartValuesGenerated, CommonChart, CoreDNSConfigChart, HelmChart, HelmChartNamespaces,
|
||||
PrometheusOperatorConfigChart, ShellAgentContext,
|
||||
};
|
||||
use crate::cloud_provider::qovery::{get_qovery_app_version, EngineLocation, QoveryAgent, QoveryAppName, QoveryEngine};
|
||||
@@ -459,6 +459,7 @@ pub fn aws_helm_charts(
|
||||
},
|
||||
};
|
||||
|
||||
/* Example to delete an old install
|
||||
let old_prometheus_operator = PrometheusOperatorConfigChart {
|
||||
chart_info: ChartInfo {
|
||||
name: "prometheus-operator".to_string(),
|
||||
@@ -466,7 +467,7 @@ pub fn aws_helm_charts(
|
||||
action: HelmAction::Destroy,
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
};*/
|
||||
|
||||
let kube_prometheus_stack = PrometheusOperatorConfigChart {
|
||||
chart_info: ChartInfo {
|
||||
@@ -705,7 +706,9 @@ datasources:
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "prometheus.servicemonitor.enabled".to_string(),
|
||||
value: chart_config_prerequisites.ff_metrics_history_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(),
|
||||
@@ -731,11 +734,11 @@ datasources:
|
||||
// Webhooks resources limits
|
||||
ChartSetValue {
|
||||
key: "webhook.resources.limits.cpu".to_string(),
|
||||
value: "20m".to_string(),
|
||||
value: "200m".to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "webhook.resources.requests.cpu".to_string(),
|
||||
value: "20m".to_string(),
|
||||
value: "50m".to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "webhook.resources.limits.memory".to_string(),
|
||||
@@ -1154,26 +1157,27 @@ datasources:
|
||||
Box::new(q_storage_class),
|
||||
Box::new(coredns_config),
|
||||
Box::new(aws_vpc_cni_chart),
|
||||
Box::new(old_prometheus_operator),
|
||||
];
|
||||
|
||||
let mut level_2: Vec<Box<dyn HelmChart>> = vec![];
|
||||
let level_2: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager)];
|
||||
|
||||
let mut level_3: Vec<Box<dyn HelmChart>> = vec![
|
||||
let mut level_3: Vec<Box<dyn HelmChart>> = vec![];
|
||||
|
||||
let mut level_4: Vec<Box<dyn HelmChart>> = vec![
|
||||
Box::new(cluster_autoscaler),
|
||||
Box::new(aws_iam_eks_user_mapper),
|
||||
Box::new(aws_calico),
|
||||
];
|
||||
|
||||
let mut level_4: Vec<Box<dyn HelmChart>> = vec![
|
||||
let mut level_5: Vec<Box<dyn HelmChart>> = vec![
|
||||
Box::new(metrics_server),
|
||||
Box::new(aws_node_term_handler),
|
||||
Box::new(external_dns),
|
||||
];
|
||||
|
||||
let mut level_5: Vec<Box<dyn HelmChart>> = vec![Box::new(nginx_ingress), Box::new(cert_manager)];
|
||||
let mut level_6: Vec<Box<dyn HelmChart>> = vec![Box::new(nginx_ingress)];
|
||||
|
||||
let mut level_6: Vec<Box<dyn HelmChart>> = vec![
|
||||
let mut level_7: Vec<Box<dyn HelmChart>> = vec![
|
||||
Box::new(cert_manager_config),
|
||||
Box::new(qovery_agent),
|
||||
Box::new(shell_agent),
|
||||
@@ -1182,26 +1186,26 @@ datasources:
|
||||
|
||||
// observability
|
||||
if chart_config_prerequisites.ff_metrics_history_enabled {
|
||||
level_2.push(Box::new(kube_prometheus_stack));
|
||||
level_4.push(Box::new(prometheus_adapter));
|
||||
level_4.push(Box::new(kube_state_metrics));
|
||||
level_3.push(Box::new(kube_prometheus_stack));
|
||||
level_5.push(Box::new(prometheus_adapter));
|
||||
level_5.push(Box::new(kube_state_metrics));
|
||||
}
|
||||
if chart_config_prerequisites.ff_log_history_enabled {
|
||||
level_3.push(Box::new(promtail));
|
||||
level_4.push(Box::new(loki));
|
||||
level_4.push(Box::new(promtail));
|
||||
level_5.push(Box::new(loki));
|
||||
}
|
||||
|
||||
if chart_config_prerequisites.ff_metrics_history_enabled || chart_config_prerequisites.ff_log_history_enabled {
|
||||
level_6.push(Box::new(grafana))
|
||||
level_7.push(Box::new(grafana))
|
||||
};
|
||||
|
||||
// pleco
|
||||
if !chart_config_prerequisites.disable_pleco {
|
||||
level_5.push(Box::new(pleco));
|
||||
level_6.push(Box::new(pleco));
|
||||
}
|
||||
|
||||
info!("charts configuration preparation finished");
|
||||
Ok(vec![level_1, level_2, level_3, level_4, level_5, level_6])
|
||||
Ok(vec![level_1, level_2, level_3, level_4, level_5, level_6, level_7])
|
||||
}
|
||||
|
||||
// AWS CNI
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::cloud_provider::aws::kubernetes::node::AwsInstancesType;
|
||||
use crate::cloud_provider::aws::kubernetes::roles::get_default_roles_to_create;
|
||||
use crate::cloud_provider::aws::regions::{AwsRegion, AwsZones};
|
||||
use crate::cloud_provider::environment::Environment;
|
||||
use crate::cloud_provider::helm::deploy_charts_levels;
|
||||
use crate::cloud_provider::helm::{deploy_charts_levels, ChartInfo};
|
||||
use crate::cloud_provider::kubernetes::{
|
||||
is_kubernetes_upgrade_required, send_progress_on_long_task, uninstall_cert_manager, Kind, Kubernetes,
|
||||
KubernetesNodesType, KubernetesUpgradeStatus, ProviderOptions,
|
||||
@@ -24,11 +24,11 @@ use crate::cloud_provider::qovery::EngineLocation;
|
||||
use crate::cloud_provider::utilities::print_action;
|
||||
use crate::cloud_provider::{kubernetes, CloudProvider};
|
||||
use crate::cmd;
|
||||
use crate::cmd::helm::{to_engine_error, Helm};
|
||||
use crate::cmd::kubectl::{
|
||||
kubectl_exec_api_custom_metrics, kubectl_exec_get_all_namespaces, kubectl_exec_get_events,
|
||||
kubectl_exec_scale_replicas, ScalingKind,
|
||||
};
|
||||
use crate::cmd::structs::HelmChart;
|
||||
use crate::cmd::terraform::{terraform_exec, terraform_init_validate_plan_apply, terraform_init_validate_state_list};
|
||||
use crate::deletion_utilities::{get_firsts_namespaces_to_delete, get_qovery_managed_namespaces};
|
||||
use crate::dns_provider;
|
||||
@@ -1247,15 +1247,14 @@ impl<'a> EKS<'a> {
|
||||
);
|
||||
|
||||
// delete custom metrics api to avoid stale namespaces on deletion
|
||||
let _ = cmd::helm::helm_uninstall_list(
|
||||
let helm = Helm::new(
|
||||
&kubernetes_config_file_path,
|
||||
vec![HelmChart {
|
||||
name: "metrics-server".to_string(),
|
||||
namespace: "kube-system".to_string(),
|
||||
version: None,
|
||||
}],
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
);
|
||||
&self.cloud_provider.credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| to_engine_error(&event_details, e))?;
|
||||
let chart = ChartInfo::new_from_release_name("metrics-server", "kube-system");
|
||||
helm.uninstall(&chart, &vec![])
|
||||
.map_err(|e| to_engine_error(&event_details, e))?;
|
||||
|
||||
// required to avoid namespace stuck on deletion
|
||||
uninstall_cert_manager(
|
||||
@@ -1275,50 +1274,27 @@ impl<'a> EKS<'a> {
|
||||
|
||||
let qovery_namespaces = get_qovery_managed_namespaces();
|
||||
for qovery_namespace in qovery_namespaces.iter() {
|
||||
let charts_to_delete = cmd::helm::helm_list(
|
||||
&kubernetes_config_file_path,
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
Some(qovery_namespace),
|
||||
);
|
||||
match charts_to_delete {
|
||||
Ok(charts) => {
|
||||
for chart in charts {
|
||||
match cmd::helm::helm_exec_uninstall(
|
||||
&kubernetes_config_file_path,
|
||||
&chart.namespace,
|
||||
&chart.name,
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
) {
|
||||
Ok(_) => self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!("Chart `{}` deleted", chart.name)),
|
||||
),
|
||||
),
|
||||
Err(e) => {
|
||||
let message_safe = format!("Can't delete chart `{}`", chart.name);
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new(message_safe, Some(e.message())),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if !(e.message().contains("not found")) {
|
||||
let charts_to_delete = helm
|
||||
.list_release(Some(qovery_namespace), &vec![])
|
||||
.map_err(|e| to_engine_error(&event_details, e))?;
|
||||
|
||||
for chart in charts_to_delete {
|
||||
let chart_info = ChartInfo::new_from_release_name(&chart.name, &chart.namespace);
|
||||
match helm.uninstall(&chart_info, &vec![]) {
|
||||
Ok(_) => self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!("Chart `{}` deleted", chart.name)),
|
||||
),
|
||||
),
|
||||
Err(e) => {
|
||||
let message_safe = format!("Can't delete chart `{}`: {}", &chart.name, e);
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"Can't delete the namespace {}",
|
||||
qovery_namespace
|
||||
)),
|
||||
EventMessage::new(message_safe, Some(e.to_string())),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -1373,18 +1349,11 @@ impl<'a> EKS<'a> {
|
||||
),
|
||||
);
|
||||
|
||||
match cmd::helm::helm_list(
|
||||
&kubernetes_config_file_path,
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
None,
|
||||
) {
|
||||
match helm.list_release(None, &vec![]) {
|
||||
Ok(helm_charts) => {
|
||||
for chart in helm_charts {
|
||||
match cmd::helm::helm_uninstall_list(
|
||||
&kubernetes_config_file_path,
|
||||
vec![chart.clone()],
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
) {
|
||||
let chart_info = ChartInfo::new_from_release_name(&chart.name, &chart.namespace);
|
||||
match helm.uninstall(&chart_info, &vec![]) {
|
||||
Ok(_) => self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
@@ -1393,12 +1362,12 @@ impl<'a> EKS<'a> {
|
||||
),
|
||||
),
|
||||
Err(e) => {
|
||||
let message_safe = format!("Error deleting chart `{}` deleted", chart.name);
|
||||
let message_safe = format!("Error deleting chart `{}`: {}", chart.name, e);
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new(message_safe, e.message),
|
||||
EventMessage::new(message_safe, Some(e.to_string())),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -1411,7 +1380,7 @@ impl<'a> EKS<'a> {
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new(message_safe.to_string(), Some(e.message())),
|
||||
EventMessage::new(message_safe.to_string(), Some(e.to_string())),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use tera::Context as TeraContext;
|
||||
|
||||
use crate::cloud_provider::helm::ChartInfo;
|
||||
use crate::cloud_provider::models::{CustomDomain, CustomDomainDataTemplate, Route, RouteDataTemplate};
|
||||
use crate::cloud_provider::service::{
|
||||
default_tera_context, delete_router, deploy_stateless_service_error, send_progress_on_long_task, Action, Create,
|
||||
@@ -7,8 +8,9 @@ use crate::cloud_provider::service::{
|
||||
};
|
||||
use crate::cloud_provider::utilities::{check_cname_for, print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope};
|
||||
use crate::cmd::helm;
|
||||
use crate::cmd::helm::{to_engine_error, Timeout};
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
@@ -325,25 +327,26 @@ impl Create for Router {
|
||||
}
|
||||
|
||||
// do exec helm upgrade and return the last deployment status
|
||||
let helm_history_row = crate::cmd::helm::helm_exec_with_upgrade_history(
|
||||
kubernetes_config_file_path.as_str(),
|
||||
environment.namespace(),
|
||||
helm_release_name.as_str(),
|
||||
self.selector(),
|
||||
workspace_dir.as_str(),
|
||||
self.start_timeout(),
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
self.service_type(),
|
||||
let helm = helm::Helm::new(
|
||||
&kubernetes_config_file_path,
|
||||
&kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
NewEngineError::new_helm_charts_upgrade_error(event_details.clone(), e).to_legacy_engine_error()
|
||||
})?;
|
||||
.map_err(|e| to_engine_error(&event_details, e).to_legacy_engine_error())?;
|
||||
let chart = ChartInfo::new_from_custom_namespace(
|
||||
helm_release_name,
|
||||
workspace_dir.clone(),
|
||||
environment.namespace().to_string(),
|
||||
600_i64,
|
||||
match self.service_type() {
|
||||
ServiceType::Database(_) => vec![format!("{}/q-values.yaml", &workspace_dir)],
|
||||
_ => vec![],
|
||||
},
|
||||
false,
|
||||
self.selector(),
|
||||
);
|
||||
|
||||
if helm_history_row.is_none() || !helm_history_row.unwrap().is_successfully_deployed() {
|
||||
return Err(self.engine_error(EngineErrorCause::Internal, "Router has failed to be deployed".into()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
helm.upgrade(&chart, &vec![])
|
||||
.map_err(|e| NewEngineError::new_helm_error(event_details.clone(), e).to_legacy_engine_error())
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use crate::cloud_provider::digitalocean::kubernetes::DoksOptions;
|
||||
use crate::cloud_provider::helm::{
|
||||
get_chart_for_shell_agent, get_engine_helm_action_from_location, ChartInfo, ChartSetValue, ChartValuesGenerated,
|
||||
CommonChart, CoreDNSConfigChart, HelmAction, HelmChart, HelmChartNamespaces, PrometheusOperatorConfigChart,
|
||||
ShellAgentContext,
|
||||
CommonChart, CoreDNSConfigChart, HelmChart, HelmChartNamespaces, PrometheusOperatorConfigChart, ShellAgentContext,
|
||||
};
|
||||
use crate::cloud_provider::qovery::{get_qovery_app_version, EngineLocation, QoveryAgent, QoveryAppName, QoveryEngine};
|
||||
use crate::errors::CommandError;
|
||||
@@ -309,6 +308,7 @@ pub fn do_helm_charts(
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
let old_prometheus_operator = PrometheusOperatorConfigChart {
|
||||
chart_info: ChartInfo {
|
||||
name: "prometheus-operator".to_string(),
|
||||
@@ -316,7 +316,7 @@ pub fn do_helm_charts(
|
||||
action: HelmAction::Destroy,
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
};*/
|
||||
|
||||
let kube_prometheus_stack = PrometheusOperatorConfigChart {
|
||||
chart_info: ChartInfo {
|
||||
@@ -544,7 +544,9 @@ datasources:
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "prometheus.servicemonitor.enabled".to_string(),
|
||||
value: chart_config_prerequisites.ff_metrics_history_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(),
|
||||
@@ -570,11 +572,11 @@ datasources:
|
||||
// Webhooks resources limits
|
||||
ChartSetValue {
|
||||
key: "webhook.resources.limits.cpu".to_string(),
|
||||
value: "20m".to_string(),
|
||||
value: "200m".to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "webhook.resources.requests.cpu".to_string(),
|
||||
value: "20m".to_string(),
|
||||
value: "50m".to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "webhook.resources.limits.memory".to_string(),
|
||||
@@ -1027,19 +1029,15 @@ datasources:
|
||||
};
|
||||
|
||||
// chart deployment order matters!!!
|
||||
let level_1: Vec<Box<dyn HelmChart>> = vec![
|
||||
Box::new(q_storage_class),
|
||||
Box::new(coredns_config),
|
||||
Box::new(old_prometheus_operator),
|
||||
];
|
||||
let level_1: Vec<Box<dyn HelmChart>> = vec![Box::new(q_storage_class), Box::new(coredns_config)];
|
||||
|
||||
let mut level_2: Vec<Box<dyn HelmChart>> = vec![Box::new(container_registry_secret)];
|
||||
let mut level_2: Vec<Box<dyn HelmChart>> = vec![Box::new(container_registry_secret), Box::new(cert_manager)];
|
||||
|
||||
let mut level_3: Vec<Box<dyn HelmChart>> = vec![];
|
||||
|
||||
let mut level_4: Vec<Box<dyn HelmChart>> = vec![Box::new(metrics_server), Box::new(external_dns)];
|
||||
|
||||
let mut level_5: Vec<Box<dyn HelmChart>> = vec![Box::new(nginx_ingress), Box::new(cert_manager)];
|
||||
let mut level_5: Vec<Box<dyn HelmChart>> = vec![Box::new(nginx_ingress)];
|
||||
|
||||
let mut level_6: Vec<Box<dyn HelmChart>> = vec![
|
||||
Box::new(cert_manager_config),
|
||||
|
||||
@@ -26,11 +26,10 @@ use crate::cloud_provider::models::NodeGroups;
|
||||
use crate::cloud_provider::qovery::EngineLocation;
|
||||
use crate::cloud_provider::utilities::{print_action, VersionsNumber};
|
||||
use crate::cloud_provider::{kubernetes, CloudProvider};
|
||||
use crate::cmd::helm::{helm_exec_upgrade_with_chart_info, helm_upgrade_diff_with_chart_info};
|
||||
use crate::cmd::helm::{to_engine_error, Helm};
|
||||
use crate::cmd::kubectl::{
|
||||
do_kubectl_exec_get_loadbalancer_id, kubectl_exec_get_all_namespaces, kubectl_exec_get_events,
|
||||
};
|
||||
use crate::cmd::structs::HelmChart;
|
||||
use crate::cmd::terraform::{terraform_exec, terraform_init_validate_plan_apply, terraform_init_validate_state_list};
|
||||
use crate::deletion_utilities::{get_firsts_namespaces_to_delete, get_qovery_managed_namespaces};
|
||||
use crate::dns_provider::DnsProvider;
|
||||
@@ -816,18 +815,16 @@ impl<'a> DOKS<'a> {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let _ = helm_upgrade_diff_with_chart_info(
|
||||
&kubeconfig_path,
|
||||
&credentials_environment_variables,
|
||||
&load_balancer_dns_hostname,
|
||||
);
|
||||
|
||||
helm_exec_upgrade_with_chart_info(
|
||||
let helm = Helm::new(
|
||||
&kubeconfig_path,
|
||||
&self.cloud_provider.credentials_environment_variables(),
|
||||
&load_balancer_dns_hostname,
|
||||
)
|
||||
.map_err(|e| EngineError::new_helm_charts_deploy_error(event_details.clone(), e))
|
||||
.map_err(|e| EngineError::new_helm_error(event_details.clone(), e))?;
|
||||
|
||||
// This will ony print the diff on stdout
|
||||
let _ = helm.upgrade_diff(&load_balancer_dns_hostname, &vec![]);
|
||||
helm.upgrade(&load_balancer_dns_hostname, &vec![])
|
||||
.map_err(|e| EngineError::new_helm_error(event_details.clone(), e))
|
||||
}
|
||||
|
||||
fn create_error(&self) -> Result<(), EngineError> {
|
||||
@@ -1096,15 +1093,14 @@ impl<'a> DOKS<'a> {
|
||||
);
|
||||
|
||||
// delete custom metrics api to avoid stale namespaces on deletion
|
||||
let _ = cmd::helm::helm_uninstall_list(
|
||||
let helm = Helm::new(
|
||||
&kubernetes_config_file_path,
|
||||
vec![HelmChart {
|
||||
name: "metrics-server".to_string(),
|
||||
namespace: "kube-system".to_string(),
|
||||
version: None,
|
||||
}],
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
);
|
||||
&self.cloud_provider.credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| to_engine_error(&event_details, e))?;
|
||||
let chart = ChartInfo::new_from_release_name("metrics-server", "kube-system");
|
||||
helm.uninstall(&chart, &vec![])
|
||||
.map_err(|e| to_engine_error(&event_details, e))?;
|
||||
|
||||
// required to avoid namespace stuck on deletion
|
||||
uninstall_cert_manager(
|
||||
@@ -1124,50 +1120,27 @@ impl<'a> DOKS<'a> {
|
||||
|
||||
let qovery_namespaces = get_qovery_managed_namespaces();
|
||||
for qovery_namespace in qovery_namespaces.iter() {
|
||||
let charts_to_delete = cmd::helm::helm_list(
|
||||
&kubernetes_config_file_path,
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
Some(qovery_namespace),
|
||||
);
|
||||
match charts_to_delete {
|
||||
Ok(charts) => {
|
||||
for chart in charts {
|
||||
match cmd::helm::helm_exec_uninstall(
|
||||
&kubernetes_config_file_path,
|
||||
&chart.namespace,
|
||||
&chart.name,
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
) {
|
||||
Ok(_) => self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!("Chart `{}` deleted", chart.name)),
|
||||
),
|
||||
),
|
||||
Err(e) => {
|
||||
let message_safe = format!("Can't delete chart `{}`", chart.name);
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new(message_safe, Some(e.message())),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if !(e.message().contains("not found")) {
|
||||
let charts_to_delete = helm
|
||||
.list_release(Some(qovery_namespace), &vec![])
|
||||
.map_err(|e| to_engine_error(&event_details, e))?;
|
||||
|
||||
for chart in charts_to_delete {
|
||||
let chart_info = ChartInfo::new_from_release_name(&chart.name, &chart.namespace);
|
||||
match helm.uninstall(&chart_info, &vec![]) {
|
||||
Ok(_) => self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!("Chart `{}` deleted", chart.name)),
|
||||
),
|
||||
),
|
||||
Err(e) => {
|
||||
let message_safe = format!("Can't delete chart `{}`", chart.name);
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"Can't delete the namespace {}",
|
||||
qovery_namespace
|
||||
)),
|
||||
EventMessage::new(message_safe, Some(e.to_string())),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -1222,18 +1195,11 @@ impl<'a> DOKS<'a> {
|
||||
),
|
||||
);
|
||||
|
||||
match cmd::helm::helm_list(
|
||||
&kubernetes_config_file_path,
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
None,
|
||||
) {
|
||||
match helm.list_release(None, &vec![]) {
|
||||
Ok(helm_charts) => {
|
||||
for chart in helm_charts {
|
||||
match cmd::helm::helm_uninstall_list(
|
||||
&kubernetes_config_file_path,
|
||||
vec![chart.clone()],
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
) {
|
||||
let chart_info = ChartInfo::new_from_release_name(&chart.name, &chart.namespace);
|
||||
match helm.uninstall(&chart_info, &vec![]) {
|
||||
Ok(_) => self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
@@ -1242,12 +1208,12 @@ impl<'a> DOKS<'a> {
|
||||
),
|
||||
),
|
||||
Err(e) => {
|
||||
let message_safe = format!("Error deleting chart `{}` deleted", chart.name);
|
||||
let message_safe = format!("Error deleting chart `{}`: {}", chart.name, e);
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new(message_safe, e.message),
|
||||
EventMessage::new(message_safe, Some(e.to_string())),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -1260,7 +1226,7 @@ impl<'a> DOKS<'a> {
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new(message_safe.to_string(), Some(e.message())),
|
||||
EventMessage::new(message_safe.to_string(), Some(e.to_string())),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use tera::Context as TeraContext;
|
||||
|
||||
use crate::cloud_provider::helm::ChartInfo;
|
||||
use crate::cloud_provider::models::{CustomDomain, CustomDomainDataTemplate, Route, RouteDataTemplate};
|
||||
use crate::cloud_provider::service::{
|
||||
default_tera_context, delete_router, deploy_stateless_service_error, send_progress_on_long_task, Action, Create,
|
||||
@@ -7,6 +8,7 @@ use crate::cloud_provider::service::{
|
||||
};
|
||||
use crate::cloud_provider::utilities::{check_cname_for, print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope};
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
@@ -345,25 +347,26 @@ impl Create for Router {
|
||||
}
|
||||
|
||||
// do exec helm upgrade and return the last deployment status
|
||||
let helm_history_row = crate::cmd::helm::helm_exec_with_upgrade_history(
|
||||
kubernetes_config_file_path.as_str(),
|
||||
environment.namespace(),
|
||||
helm_release_name.as_str(),
|
||||
self.selector(),
|
||||
workspace_dir.as_str(),
|
||||
self.start_timeout(),
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
self.service_type(),
|
||||
let helm = helm::Helm::new(
|
||||
&kubernetes_config_file_path,
|
||||
&kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
NewEngineError::new_helm_charts_upgrade_error(event_details.clone(), e).to_legacy_engine_error()
|
||||
})?;
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())?;
|
||||
let chart = ChartInfo::new_from_custom_namespace(
|
||||
helm_release_name,
|
||||
workspace_dir.clone(),
|
||||
environment.namespace().to_string(),
|
||||
600_i64,
|
||||
match self.service_type() {
|
||||
ServiceType::Database(_) => vec![format!("{}/q-values.yaml", &workspace_dir)],
|
||||
_ => vec![],
|
||||
},
|
||||
false,
|
||||
self.selector(),
|
||||
);
|
||||
|
||||
if helm_history_row.is_none() || !helm_history_row.unwrap().is_successfully_deployed() {
|
||||
return Err(self.engine_error(EngineErrorCause::Internal, "Router has failed to be deployed".into()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
helm.upgrade(&chart, &vec![])
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
use crate::cloud_provider::helm::HelmAction::Deploy;
|
||||
use crate::cloud_provider::helm::HelmChartNamespaces::KubeSystem;
|
||||
use crate::cloud_provider::qovery::{get_qovery_app_version, EngineLocation, QoveryAppName, QoveryShellAgent};
|
||||
use crate::cmd::helm::{
|
||||
helm_destroy_chart_if_breaking_changes_version_detected, helm_exec_uninstall_with_chart_info,
|
||||
helm_exec_upgrade_with_chart_info, helm_upgrade_diff_with_chart_info, is_chart_deployed,
|
||||
};
|
||||
use crate::cmd::helm::{to_command_error, Helm};
|
||||
use crate::cmd::kubectl::{
|
||||
kubectl_delete_crash_looping_pods, kubectl_exec_delete_crd, kubectl_exec_get_configmap, kubectl_exec_get_events,
|
||||
kubectl_exec_rollout_restart_deployment, kubectl_exec_with_output,
|
||||
@@ -20,7 +17,7 @@ use thread::spawn;
|
||||
use tracing::{span, Level};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum HelmAction {
|
||||
Deploy,
|
||||
Destroy,
|
||||
@@ -108,6 +105,15 @@ impl ChartInfo {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_release_name(name: &str, custom_namespace: &str) -> ChartInfo {
|
||||
ChartInfo {
|
||||
name: name.to_string(),
|
||||
namespace: HelmChartNamespaces::Custom,
|
||||
custom_namespace: Some(custom_namespace.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_namespace_string(&self) -> String {
|
||||
match self.namespace {
|
||||
HelmChartNamespaces::Custom => self
|
||||
@@ -130,7 +136,7 @@ impl Default for ChartInfo {
|
||||
atomic: true,
|
||||
force_upgrade: false,
|
||||
last_breaking_version_requiring_restart: None,
|
||||
timeout_in_seconds: 300,
|
||||
timeout_in_seconds: 600,
|
||||
dry_run: false,
|
||||
wait: true,
|
||||
values: Vec::new(),
|
||||
@@ -216,36 +222,22 @@ pub trait HelmChart: Send {
|
||||
) -> Result<Option<ChartPayload>, CommandError> {
|
||||
let environment_variables: Vec<(&str, &str)> = envs.iter().map(|x| (x.0.as_str(), x.1.as_str())).collect();
|
||||
let chart_info = self.get_chart_info();
|
||||
let helm = Helm::new(kubernetes_config, &environment_variables).map_err(to_command_error)?;
|
||||
|
||||
match chart_info.action {
|
||||
HelmAction::Deploy => {
|
||||
if let Err(e) = helm_destroy_chart_if_breaking_changes_version_detected(
|
||||
kubernetes_config,
|
||||
&environment_variables,
|
||||
chart_info,
|
||||
) {
|
||||
if let Err(e) = helm.uninstall_chart_if_breaking_version(chart_info, &vec![]) {
|
||||
warn!(
|
||||
"error while trying to destroy chart if breaking change is detected: {:?}",
|
||||
e.message()
|
||||
e.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
helm_exec_upgrade_with_chart_info(kubernetes_config, &environment_variables, chart_info)?
|
||||
helm.upgrade(&chart_info, &vec![]).map_err(to_command_error)?;
|
||||
}
|
||||
HelmAction::Destroy => {
|
||||
let chart_info = self.get_chart_info();
|
||||
match is_chart_deployed(
|
||||
kubernetes_config,
|
||||
environment_variables.clone(),
|
||||
Some(chart_info.get_namespace_string().as_str()),
|
||||
chart_info.name.clone(),
|
||||
) {
|
||||
Ok(deployed) => {
|
||||
if deployed {
|
||||
helm_exec_uninstall_with_chart_info(kubernetes_config, &environment_variables, chart_info)?
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
helm.uninstall(&chart_info, &vec![]).map_err(to_command_error)?;
|
||||
}
|
||||
HelmAction::Skip => {}
|
||||
}
|
||||
@@ -303,24 +295,31 @@ fn deploy_parallel_charts(
|
||||
handles.push(handle);
|
||||
}
|
||||
|
||||
let mut errors: Vec<Result<(), CommandError>> = vec![];
|
||||
for handle in handles {
|
||||
match handle.join() {
|
||||
Ok(helm_run_ret) => {
|
||||
if let Err(e) = helm_run_ret {
|
||||
return Err(e);
|
||||
errors.push(Err(e));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
let safe_message = "Thread panicked during parallel charts deployments.";
|
||||
return Err(CommandError::new(
|
||||
let error = Err(CommandError::new(
|
||||
format!("{}, error: {:?}", safe_message.to_string(), e),
|
||||
Some(safe_message.to_string()),
|
||||
));
|
||||
errors.push(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
if errors.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
error!("Deployments of charts failed with: {:?}", errors);
|
||||
errors.remove(0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deploy_charts_levels(
|
||||
@@ -330,24 +329,24 @@ pub fn deploy_charts_levels(
|
||||
dry_run: bool,
|
||||
) -> Result<(), CommandError> {
|
||||
// first show diff
|
||||
for level in &charts {
|
||||
for chart in level {
|
||||
let envs_ref: Vec<(&str, &str)> = envs.iter().map(|(x, y)| (x.as_str(), y.as_str())).collect();
|
||||
let helm = Helm::new(&kubernetes_config, &envs_ref).map_err(to_command_error)?;
|
||||
|
||||
for level in charts {
|
||||
// Show diff for all chart in this state
|
||||
for chart in &level {
|
||||
let chart_info = chart.get_chart_info();
|
||||
match chart_info.action {
|
||||
// don't do diff on destroy or skip
|
||||
HelmAction::Deploy => {
|
||||
let _ = helm_upgrade_diff_with_chart_info(&kubernetes_config, envs, chart.get_chart_info());
|
||||
}
|
||||
_ => {}
|
||||
// don't do diff on destroy or skip
|
||||
if chart_info.action == HelmAction::Deploy {
|
||||
let _ = helm.upgrade_diff(chart_info, &vec![]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then apply
|
||||
if dry_run {
|
||||
return Ok(());
|
||||
}
|
||||
for level in charts.into_iter() {
|
||||
// Skip actual deployment if dry run
|
||||
if dry_run {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Err(e) = deploy_parallel_charts(&kubernetes_config, &envs, level) {
|
||||
return Err(e);
|
||||
}
|
||||
@@ -591,47 +590,36 @@ impl HelmChart for PrometheusOperatorConfigChart {
|
||||
) -> Result<Option<ChartPayload>, CommandError> {
|
||||
let environment_variables: Vec<(&str, &str)> = envs.iter().map(|x| (x.0.as_str(), x.1.as_str())).collect();
|
||||
let chart_info = self.get_chart_info();
|
||||
let helm = Helm::new(kubernetes_config, &environment_variables).map_err(to_command_error)?;
|
||||
|
||||
match chart_info.action {
|
||||
HelmAction::Deploy => {
|
||||
if let Err(e) = helm_destroy_chart_if_breaking_changes_version_detected(
|
||||
kubernetes_config,
|
||||
&environment_variables,
|
||||
chart_info,
|
||||
) {
|
||||
if let Err(e) = helm.uninstall_chart_if_breaking_version(chart_info, &vec![]) {
|
||||
warn!(
|
||||
"error while trying to destroy chart if breaking change is detected: {}",
|
||||
e.message()
|
||||
e.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
helm_exec_upgrade_with_chart_info(kubernetes_config, &environment_variables, chart_info)?
|
||||
helm.upgrade(&chart_info, &vec![]).map_err(to_command_error)?;
|
||||
}
|
||||
HelmAction::Destroy => {
|
||||
let chart_info = self.get_chart_info();
|
||||
match is_chart_deployed(
|
||||
kubernetes_config,
|
||||
environment_variables.clone(),
|
||||
Some(chart_info.get_namespace_string().as_str()),
|
||||
chart_info.name.clone(),
|
||||
) {
|
||||
Ok(deployed) => {
|
||||
if deployed {
|
||||
let prometheus_crds = [
|
||||
"prometheuses.monitoring.coreos.com",
|
||||
"prometheusrules.monitoring.coreos.com",
|
||||
"servicemonitors.monitoring.coreos.com",
|
||||
"podmonitors.monitoring.coreos.com",
|
||||
"alertmanagers.monitoring.coreos.com",
|
||||
"thanosrulers.monitoring.coreos.com",
|
||||
];
|
||||
helm_exec_uninstall_with_chart_info(kubernetes_config, &environment_variables, chart_info)?;
|
||||
for crd in &prometheus_crds {
|
||||
kubectl_exec_delete_crd(kubernetes_config, crd, environment_variables.clone())?;
|
||||
}
|
||||
}
|
||||
if helm.check_release_exist(&chart_info, &vec![]).is_ok() {
|
||||
helm.uninstall(&chart_info, &vec![]).map_err(to_command_error)?;
|
||||
|
||||
let prometheus_crds = [
|
||||
"prometheuses.monitoring.coreos.com",
|
||||
"prometheusrules.monitoring.coreos.com",
|
||||
"servicemonitors.monitoring.coreos.com",
|
||||
"podmonitors.monitoring.coreos.com",
|
||||
"alertmanagers.monitoring.coreos.com",
|
||||
"thanosrulers.monitoring.coreos.com",
|
||||
];
|
||||
for crd in &prometheus_crds {
|
||||
let _ = kubectl_exec_delete_crd(kubernetes_config, crd, environment_variables.clone());
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
}
|
||||
}
|
||||
HelmAction::Skip => {}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::cloud_provider::helm::{
|
||||
get_chart_for_shell_agent, get_engine_helm_action_from_location, ChartInfo, ChartSetValue, ChartValuesGenerated,
|
||||
CommonChart, CoreDNSConfigChart, HelmAction, HelmChart, HelmChartNamespaces, PrometheusOperatorConfigChart,
|
||||
ShellAgentContext,
|
||||
CommonChart, CoreDNSConfigChart, HelmChart, HelmChartNamespaces, PrometheusOperatorConfigChart, ShellAgentContext,
|
||||
};
|
||||
use crate::cloud_provider::qovery::{get_qovery_app_version, EngineLocation, QoveryAgent, QoveryAppName, QoveryEngine};
|
||||
use crate::cloud_provider::scaleway::application::{ScwRegion, ScwZone};
|
||||
@@ -283,6 +282,7 @@ pub fn scw_helm_charts(
|
||||
},
|
||||
};
|
||||
|
||||
/* Example to delete an old chart
|
||||
let old_prometheus_operator = PrometheusOperatorConfigChart {
|
||||
chart_info: ChartInfo {
|
||||
name: "prometheus-operator".to_string(),
|
||||
@@ -290,7 +290,7 @@ pub fn scw_helm_charts(
|
||||
action: HelmAction::Destroy,
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
};*/
|
||||
|
||||
let kube_prometheus_stack = PrometheusOperatorConfigChart {
|
||||
chart_info: ChartInfo {
|
||||
@@ -493,7 +493,9 @@ datasources:
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "prometheus.servicemonitor.enabled".to_string(),
|
||||
value: chart_config_prerequisites.ff_metrics_history_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(),
|
||||
@@ -519,11 +521,11 @@ datasources:
|
||||
// Webhooks resources limits
|
||||
ChartSetValue {
|
||||
key: "webhook.resources.limits.cpu".to_string(),
|
||||
value: "20m".to_string(),
|
||||
value: "200m".to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "webhook.resources.requests.cpu".to_string(),
|
||||
value: "20m".to_string(),
|
||||
value: "50m".to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "webhook.resources.limits.memory".to_string(),
|
||||
@@ -856,21 +858,19 @@ datasources:
|
||||
};
|
||||
|
||||
// chart deployment order matters!!!
|
||||
let level_1: Vec<Box<dyn HelmChart>> = vec![
|
||||
Box::new(q_storage_class),
|
||||
Box::new(coredns_config),
|
||||
Box::new(old_prometheus_operator),
|
||||
];
|
||||
let level_1: Vec<Box<dyn HelmChart>> = vec![Box::new(q_storage_class), Box::new(coredns_config)];
|
||||
|
||||
let mut level_2: Vec<Box<dyn HelmChart>> = vec![];
|
||||
let level_2: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager)];
|
||||
|
||||
let mut level_3: Vec<Box<dyn HelmChart>> = vec![];
|
||||
|
||||
let mut level_4: Vec<Box<dyn HelmChart>> = vec![Box::new(external_dns)];
|
||||
let mut level_4: Vec<Box<dyn HelmChart>> = vec![];
|
||||
|
||||
let mut level_5: Vec<Box<dyn HelmChart>> = vec![Box::new(nginx_ingress), Box::new(cert_manager)];
|
||||
let mut level_5: Vec<Box<dyn HelmChart>> = vec![Box::new(external_dns)];
|
||||
|
||||
let mut level_6: Vec<Box<dyn HelmChart>> = vec![
|
||||
let mut level_6: Vec<Box<dyn HelmChart>> = vec![Box::new(nginx_ingress)];
|
||||
|
||||
let mut level_7: Vec<Box<dyn HelmChart>> = vec![
|
||||
Box::new(cert_manager_config),
|
||||
Box::new(qovery_agent),
|
||||
Box::new(shell_agent),
|
||||
@@ -879,24 +879,24 @@ datasources:
|
||||
|
||||
// // observability
|
||||
if chart_config_prerequisites.ff_metrics_history_enabled {
|
||||
level_2.push(Box::new(kube_prometheus_stack));
|
||||
level_4.push(Box::new(prometheus_adapter));
|
||||
level_4.push(Box::new(kube_state_metrics));
|
||||
level_3.push(Box::new(kube_prometheus_stack));
|
||||
level_5.push(Box::new(prometheus_adapter));
|
||||
level_5.push(Box::new(kube_state_metrics));
|
||||
}
|
||||
if chart_config_prerequisites.ff_log_history_enabled {
|
||||
level_3.push(Box::new(promtail));
|
||||
level_4.push(Box::new(loki));
|
||||
level_4.push(Box::new(promtail));
|
||||
level_5.push(Box::new(loki));
|
||||
}
|
||||
|
||||
if chart_config_prerequisites.ff_metrics_history_enabled || chart_config_prerequisites.ff_log_history_enabled {
|
||||
level_6.push(Box::new(grafana))
|
||||
level_7.push(Box::new(grafana))
|
||||
};
|
||||
|
||||
// pleco
|
||||
if !chart_config_prerequisites.disable_pleco {
|
||||
level_5.push(Box::new(pleco));
|
||||
level_6.push(Box::new(pleco));
|
||||
}
|
||||
|
||||
info!("charts configuration preparation finished");
|
||||
Ok(vec![level_1, level_2, level_3, level_4, level_5, level_6])
|
||||
Ok(vec![level_1, level_2, level_3, level_4, level_5, level_6, level_7])
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ pub mod node;
|
||||
|
||||
use crate::cloud_provider::aws::regions::AwsZones;
|
||||
use crate::cloud_provider::environment::Environment;
|
||||
use crate::cloud_provider::helm::deploy_charts_levels;
|
||||
use crate::cloud_provider::helm::{deploy_charts_levels, ChartInfo};
|
||||
use crate::cloud_provider::kubernetes::{
|
||||
is_kubernetes_upgrade_required, send_progress_on_long_task, uninstall_cert_manager, Kind, Kubernetes,
|
||||
KubernetesUpgradeStatus, ProviderOptions,
|
||||
@@ -15,8 +15,8 @@ use crate::cloud_provider::scaleway::kubernetes::helm_charts::{scw_helm_charts,
|
||||
use crate::cloud_provider::scaleway::kubernetes::node::{ScwInstancesType, ScwNodeGroup};
|
||||
use crate::cloud_provider::utilities::print_action;
|
||||
use crate::cloud_provider::{kubernetes, CloudProvider};
|
||||
use crate::cmd::helm::{to_engine_error, Helm};
|
||||
use crate::cmd::kubectl::{kubectl_exec_api_custom_metrics, kubectl_exec_get_all_namespaces, kubectl_exec_get_events};
|
||||
use crate::cmd::structs::HelmChart;
|
||||
use crate::cmd::terraform::{terraform_exec, terraform_init_validate_plan_apply, terraform_init_validate_state_list};
|
||||
use crate::deletion_utilities::{get_firsts_namespaces_to_delete, get_qovery_managed_namespaces};
|
||||
use crate::dns_provider::DnsProvider;
|
||||
@@ -1497,15 +1497,14 @@ impl<'a> Kapsule<'a> {
|
||||
);
|
||||
|
||||
// delete custom metrics api to avoid stale namespaces on deletion
|
||||
let _ = cmd::helm::helm_uninstall_list(
|
||||
let helm = Helm::new(
|
||||
&kubernetes_config_file_path,
|
||||
vec![HelmChart {
|
||||
name: "metrics-server".to_string(),
|
||||
namespace: "kube-system".to_string(),
|
||||
version: None,
|
||||
}],
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
);
|
||||
&self.cloud_provider.credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| to_engine_error(&event_details, e))?;
|
||||
let chart = ChartInfo::new_from_release_name("metrics-server", "kube-system");
|
||||
helm.uninstall(&chart, &vec![])
|
||||
.map_err(|e| to_engine_error(&event_details, e))?;
|
||||
|
||||
// required to avoid namespace stuck on deletion
|
||||
uninstall_cert_manager(
|
||||
@@ -1525,50 +1524,27 @@ impl<'a> Kapsule<'a> {
|
||||
|
||||
let qovery_namespaces = get_qovery_managed_namespaces();
|
||||
for qovery_namespace in qovery_namespaces.iter() {
|
||||
let charts_to_delete = cmd::helm::helm_list(
|
||||
&kubernetes_config_file_path,
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
Some(qovery_namespace),
|
||||
);
|
||||
match charts_to_delete {
|
||||
Ok(charts) => {
|
||||
for chart in charts {
|
||||
match cmd::helm::helm_exec_uninstall(
|
||||
&kubernetes_config_file_path,
|
||||
&chart.namespace,
|
||||
&chart.name,
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
) {
|
||||
Ok(_) => self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!("Chart `{}` deleted", chart.name)),
|
||||
),
|
||||
),
|
||||
Err(e) => {
|
||||
let message_safe = format!("Can't delete chart `{}`", chart.name);
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new(message_safe, Some(e.message())),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if !(e.message().contains("not found")) {
|
||||
let charts_to_delete = helm
|
||||
.list_release(Some(qovery_namespace), &vec![])
|
||||
.map_err(|e| to_engine_error(&event_details, e))?;
|
||||
|
||||
for chart in charts_to_delete {
|
||||
let chart_info = ChartInfo::new_from_release_name(&chart.name, &chart.namespace);
|
||||
match helm.uninstall(&chart_info, &vec![]) {
|
||||
Ok(_) => self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!("Chart `{}` deleted", chart.name)),
|
||||
),
|
||||
),
|
||||
Err(e) => {
|
||||
let message_safe = format!("Can't delete chart `{}`", chart.name);
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"Can't delete the namespace {}",
|
||||
qovery_namespace
|
||||
)),
|
||||
EventMessage::new(message_safe, Some(e.to_string())),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -1623,18 +1599,11 @@ impl<'a> Kapsule<'a> {
|
||||
),
|
||||
);
|
||||
|
||||
match cmd::helm::helm_list(
|
||||
&kubernetes_config_file_path,
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
None,
|
||||
) {
|
||||
match helm.list_release(None, &vec![]) {
|
||||
Ok(helm_charts) => {
|
||||
for chart in helm_charts {
|
||||
match cmd::helm::helm_uninstall_list(
|
||||
&kubernetes_config_file_path,
|
||||
vec![chart.clone()],
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
) {
|
||||
let chart_info = ChartInfo::new_from_release_name(&chart.name, &chart.namespace);
|
||||
match helm.uninstall(&chart_info, &vec![]) {
|
||||
Ok(_) => self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
@@ -1643,12 +1612,12 @@ impl<'a> Kapsule<'a> {
|
||||
),
|
||||
),
|
||||
Err(e) => {
|
||||
let message_safe = format!("Error deleting chart `{}` deleted", chart.name);
|
||||
let message_safe = format!("Error deleting chart `{}`: {}", chart.name, e);
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new(message_safe, e.message),
|
||||
EventMessage::new(message_safe, Some(e.to_string())),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -1661,7 +1630,7 @@ impl<'a> Kapsule<'a> {
|
||||
LogLevel::Error,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new(message_safe.to_string(), Some(e.message())),
|
||||
EventMessage::new(message_safe.to_string(), Some(e.to_string())),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use tera::Context as TeraContext;
|
||||
|
||||
use crate::cloud_provider::helm::ChartInfo;
|
||||
use crate::cloud_provider::models::{CustomDomain, CustomDomainDataTemplate, Route, RouteDataTemplate};
|
||||
use crate::cloud_provider::service::{
|
||||
default_tera_context, delete_router, deploy_stateless_service_error, send_progress_on_long_task, Action, Create,
|
||||
@@ -7,8 +8,9 @@ use crate::cloud_provider::service::{
|
||||
};
|
||||
use crate::cloud_provider::utilities::{check_cname_for, print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope};
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
@@ -293,25 +295,26 @@ impl Create for Router {
|
||||
}
|
||||
|
||||
// do exec helm upgrade and return the last deployment status
|
||||
let helm_history_row = crate::cmd::helm::helm_exec_with_upgrade_history(
|
||||
kubernetes_config_file_path.as_str(),
|
||||
environment.namespace(),
|
||||
helm_release_name.as_str(),
|
||||
self.selector(),
|
||||
workspace_dir.as_str(),
|
||||
self.start_timeout(),
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
self.service_type(),
|
||||
let helm = helm::Helm::new(
|
||||
&kubernetes_config_file_path,
|
||||
&kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
NewEngineError::new_helm_charts_upgrade_error(event_details.clone(), e).to_legacy_engine_error()
|
||||
})?;
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())?;
|
||||
let chart = ChartInfo::new_from_custom_namespace(
|
||||
helm_release_name,
|
||||
workspace_dir.clone(),
|
||||
environment.namespace().to_string(),
|
||||
600_i64,
|
||||
match self.service_type() {
|
||||
ServiceType::Database(_) => vec![format!("{}/q-values.yaml", &workspace_dir)],
|
||||
_ => vec![],
|
||||
},
|
||||
false,
|
||||
self.selector(),
|
||||
);
|
||||
|
||||
if helm_history_row.is_none() || !helm_history_row.unwrap().is_successfully_deployed() {
|
||||
return Err(self.engine_error(EngineErrorCause::Internal, "Router has failed to be deployed".into()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
helm.upgrade(&chart, &vec![])
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
|
||||
@@ -8,9 +8,12 @@ use tera::Context as TeraContext;
|
||||
|
||||
use crate::build_platform::Image;
|
||||
use crate::cloud_provider::environment::Environment;
|
||||
use crate::cloud_provider::helm::ChartInfo;
|
||||
use crate::cloud_provider::kubernetes::Kubernetes;
|
||||
use crate::cloud_provider::utilities::check_domain_for;
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd;
|
||||
use crate::cmd::helm;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl::ScalingKind::Statefulset;
|
||||
use crate::cmd::kubectl::{kubectl_exec_delete_secret, kubectl_exec_scale_replicas_by_selector, ScalingKind};
|
||||
@@ -365,30 +368,11 @@ pub fn deploy_user_stateless_service<T>(target: &DeploymentTarget, service: &T)
|
||||
where
|
||||
T: Service + Helm,
|
||||
{
|
||||
deploy_stateless_service(
|
||||
target,
|
||||
service,
|
||||
service.engine_error(
|
||||
EngineErrorCause::User(
|
||||
"Your application has failed to start. \
|
||||
Ensure you can run it without issues with `qovery run` and check its logs from the web interface or the CLI with `qovery log`. \
|
||||
This issue often occurs due to ports misconfiguration. Make sure you exposed the correct port (using EXPOSE statement in Dockerfile or via Qovery configuration).",
|
||||
),
|
||||
format!(
|
||||
"{} {} has failed to start ⤬",
|
||||
service.service_type().name(),
|
||||
service.name_with_id()
|
||||
),
|
||||
),
|
||||
)
|
||||
deploy_stateless_service(target, service)
|
||||
}
|
||||
|
||||
/// deploy a stateless service (app, router, database...) on Kubernetes
|
||||
pub fn deploy_stateless_service<T>(
|
||||
target: &DeploymentTarget,
|
||||
service: &T,
|
||||
thrown_error: EngineError,
|
||||
) -> Result<(), EngineError>
|
||||
pub fn deploy_stateless_service<T>(target: &DeploymentTarget, service: &T) -> Result<(), EngineError>
|
||||
where
|
||||
T: Service + Helm,
|
||||
{
|
||||
@@ -441,26 +425,26 @@ where
|
||||
})?;
|
||||
|
||||
// do exec helm upgrade and return the last deployment status
|
||||
let helm_history_row = crate::cmd::helm::helm_exec_with_upgrade_history(
|
||||
kubernetes_config_file_path.as_str(),
|
||||
environment.namespace(),
|
||||
helm_release_name.as_str(),
|
||||
service.selector(),
|
||||
workspace_dir.as_str(),
|
||||
service.start_timeout(),
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
service.service_type(),
|
||||
let helm = helm::Helm::new(
|
||||
&kubernetes_config_file_path,
|
||||
&kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| NewEngineError::new_helm_charts_upgrade_error(event_details.clone(), e).to_legacy_engine_error())?;
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())?;
|
||||
let chart = ChartInfo::new_from_custom_namespace(
|
||||
helm_release_name,
|
||||
workspace_dir.clone(),
|
||||
environment.namespace().to_string(),
|
||||
600_i64,
|
||||
match service.service_type() {
|
||||
ServiceType::Database(_) => vec![format!("{}/q-values.yaml", &workspace_dir)],
|
||||
_ => vec![],
|
||||
},
|
||||
false,
|
||||
service.selector(),
|
||||
);
|
||||
|
||||
// check deployment status
|
||||
if helm_history_row.is_none()
|
||||
|| !helm_history_row
|
||||
.expect("Error getting helm history row")
|
||||
.is_successfully_deployed()
|
||||
{
|
||||
return Err(thrown_error);
|
||||
}
|
||||
helm.upgrade(&chart, &vec![])
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())?;
|
||||
|
||||
crate::cmd::kubectl::kubectl_exec_is_pod_ready_with_retry(
|
||||
kubernetes_config_file_path.as_str(),
|
||||
@@ -482,48 +466,12 @@ where
|
||||
}
|
||||
|
||||
/// do specific operations on a stateless service deployment error
|
||||
pub fn deploy_stateless_service_error<T>(target: &DeploymentTarget, service: &T) -> Result<(), EngineError>
|
||||
pub fn deploy_stateless_service_error<T>(_target: &DeploymentTarget, _service: &T) -> Result<(), EngineError>
|
||||
where
|
||||
T: Service + Helm,
|
||||
{
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let helm_release_name = service.helm_release_name();
|
||||
let event_details = service.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
let kubernetes_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => return Err(e.to_legacy_engine_error()),
|
||||
};
|
||||
|
||||
let history_rows = crate::cmd::helm::helm_exec_history(
|
||||
kubernetes_config_file_path.as_str(),
|
||||
environment.namespace(),
|
||||
helm_release_name.as_str(),
|
||||
&kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
NewEngineError::new_helm_chart_history_error(
|
||||
event_details.clone(),
|
||||
helm_release_name.to_string(),
|
||||
environment.namespace().to_string(),
|
||||
e,
|
||||
)
|
||||
.to_legacy_engine_error()
|
||||
})?;
|
||||
|
||||
if history_rows.len() == 1 {
|
||||
crate::cmd::helm::helm_exec_uninstall(
|
||||
kubernetes_config_file_path.as_str(),
|
||||
environment.namespace(),
|
||||
helm_release_name.as_str(),
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
NewEngineError::new_helm_chart_uninstall_error(event_details.clone(), helm_release_name.to_string(), e)
|
||||
.to_legacy_engine_error()
|
||||
})?;
|
||||
}
|
||||
|
||||
// Nothing to do as we sait --atomic on chart release that we do
|
||||
// So helm rollback for us if a deployment fails
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -789,30 +737,26 @@ where
|
||||
})?;
|
||||
|
||||
// do exec helm upgrade and return the last deployment status
|
||||
let helm_history_row = crate::cmd::helm::helm_exec_with_upgrade_history(
|
||||
kubernetes_config_file_path.to_string(),
|
||||
environment.namespace(),
|
||||
service.helm_release_name().as_str(),
|
||||
service.selector(),
|
||||
workspace_dir.to_string(),
|
||||
service.start_timeout(),
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
service.service_type(),
|
||||
let helm = helm::Helm::new(
|
||||
&kubernetes_config_file_path,
|
||||
&kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
NewEngineError::new_helm_charts_upgrade_error(event_details.clone(), e).to_legacy_engine_error()
|
||||
})?;
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())?;
|
||||
let chart = ChartInfo::new_from_custom_namespace(
|
||||
service.helm_release_name(),
|
||||
workspace_dir.clone(),
|
||||
environment.namespace().to_string(),
|
||||
600_i64,
|
||||
match service.service_type() {
|
||||
ServiceType::Database(_) => vec![format!("{}/q-values.yaml", &workspace_dir)],
|
||||
_ => vec![],
|
||||
},
|
||||
false,
|
||||
service.selector(),
|
||||
);
|
||||
|
||||
// check deployment status
|
||||
if helm_history_row.is_none() || !helm_history_row.unwrap().is_successfully_deployed() {
|
||||
return Err(service.engine_error(
|
||||
EngineErrorCause::Internal,
|
||||
format!(
|
||||
"{} service fails to be deployed (before start)",
|
||||
service.service_type().name()
|
||||
),
|
||||
));
|
||||
}
|
||||
helm.upgrade(&chart, &vec![])
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())?;
|
||||
|
||||
// check app status
|
||||
match crate::cmd::kubectl::kubectl_exec_is_pod_ready_with_retry(
|
||||
@@ -1306,34 +1250,15 @@ pub fn helm_uninstall_release(
|
||||
.get_kubeconfig_file_path()
|
||||
.map_err(|e| e.to_legacy_engine_error())?;
|
||||
|
||||
let history_rows = crate::cmd::helm::helm_exec_history(
|
||||
kubernetes_config_file_path.as_str(),
|
||||
environment.namespace(),
|
||||
helm_release_name,
|
||||
let helm = cmd::helm::Helm::new(
|
||||
&kubernetes_config_file_path,
|
||||
&kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
NewEngineError::new_k8s_history(event_details.clone(), environment.namespace().to_string(), e)
|
||||
.to_legacy_engine_error()
|
||||
})?;
|
||||
.map_err(|e| NewEngineError::new_helm_error(event_details.clone(), e).to_legacy_engine_error())?;
|
||||
|
||||
// if there is no valid history - then delete the helm chart
|
||||
let first_valid_history_row = history_rows.iter().find(|x| x.is_successfully_deployed());
|
||||
|
||||
if first_valid_history_row.is_some() {
|
||||
crate::cmd::helm::helm_exec_uninstall(
|
||||
kubernetes_config_file_path.as_str(),
|
||||
environment.namespace(),
|
||||
helm_release_name,
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
NewEngineError::new_helm_chart_uninstall_error(event_details.clone(), helm_release_name.to_string(), e)
|
||||
.to_legacy_engine_error()
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
let chart = ChartInfo::new_from_release_name(helm_release_name, environment.namespace());
|
||||
helm.uninstall(&chart, &vec![])
|
||||
.map_err(|e| NewEngineError::new_helm_error(event_details.clone(), e).to_legacy_engine_error())
|
||||
}
|
||||
|
||||
/// This function call (start|pause|delete)_in_progress function every 10 seconds when a
|
||||
|
||||
@@ -319,16 +319,23 @@ impl fmt::Display for VersionsNumber {
|
||||
}
|
||||
}
|
||||
|
||||
fn cloudflare_dns_resolver() -> Resolver {
|
||||
fn google_dns_resolver() -> Resolver {
|
||||
let mut resolver_options = ResolverOpts::default();
|
||||
|
||||
// We want to avoid cache and using host file of the host, as some provider force caching
|
||||
// which lead to stale response
|
||||
resolver_options.cache_size = 0;
|
||||
resolver_options.use_hosts_file = false;
|
||||
resolver_options.use_hosts_file = true;
|
||||
//resolver_options.ip_strategy = LookupIpStrategy::Ipv4Only;
|
||||
//let dns = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 254));
|
||||
//let resolver = ResolverConfig::from_parts(
|
||||
// None,
|
||||
// vec![],
|
||||
// NameServerConfigGroup::from_ips_clear(&vec![dns], 53, true),
|
||||
//);
|
||||
|
||||
Resolver::new(ResolverConfig::cloudflare(), resolver_options)
|
||||
.expect("Invalid cloudflare DNS resolver configuration")
|
||||
//Resolver::new(resolver, resolver_options).unwrap()
|
||||
Resolver::new(ResolverConfig::google(), resolver_options).expect("Invalid google DNS resolver configuration")
|
||||
}
|
||||
|
||||
fn get_cname_record_value(resolver: &Resolver, cname: &str) -> Option<String> {
|
||||
@@ -352,7 +359,7 @@ pub fn check_cname_for(
|
||||
cname_to_check: &str,
|
||||
execution_id: &str,
|
||||
) -> Result<String, String> {
|
||||
let resolver = cloudflare_dns_resolver();
|
||||
let resolver = google_dns_resolver();
|
||||
let listener_helper = ListenersHelper::new(listeners);
|
||||
|
||||
let send_deployment_progress = |msg: &str| {
|
||||
@@ -420,7 +427,7 @@ pub fn check_domain_for(
|
||||
execution_id: &str,
|
||||
context_id: &str,
|
||||
) -> Result<(), EngineError> {
|
||||
let resolver = cloudflare_dns_resolver();
|
||||
let resolver = google_dns_resolver();
|
||||
|
||||
for domain in domains_to_check {
|
||||
listener_helper.deployment_in_progress(ProgressInfo::new(
|
||||
@@ -578,7 +585,7 @@ pub fn print_action(cloud_provider_name: &str, struct_name: &str, fn_name: &str,
|
||||
mod tests {
|
||||
use crate::cloud_provider::models::CpuLimits;
|
||||
use crate::cloud_provider::utilities::{
|
||||
cloudflare_dns_resolver, convert_k8s_cpu_value_to_f32, get_cname_record_value,
|
||||
convert_k8s_cpu_value_to_f32, get_cname_record_value, google_dns_resolver,
|
||||
validate_k8s_required_cpu_and_burstable, VersionsNumber,
|
||||
};
|
||||
use crate::error::StringError;
|
||||
@@ -626,7 +633,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
pub fn test_cname_resolution() {
|
||||
let resolver = cloudflare_dns_resolver();
|
||||
let resolver = google_dns_resolver();
|
||||
let cname = get_cname_record_value(&resolver, "ci-test-no-delete.qovery.io");
|
||||
|
||||
assert_eq!(cname, Some(String::from("qovery.io.")));
|
||||
|
||||
1591
src/cmd/helm.rs
1591
src/cmd/helm.rs
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@ pub mod io;
|
||||
extern crate url;
|
||||
|
||||
use crate::cloud_provider::utilities::VersionsNumber;
|
||||
use crate::cmd::helm::HelmError;
|
||||
use crate::error::{EngineError as LegacyEngineError, EngineErrorCause, EngineErrorScope};
|
||||
use crate::events::EventDetails;
|
||||
use url::Url;
|
||||
@@ -1503,6 +1504,29 @@ impl EngineError {
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error from an Helm error
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `error`: Raw error message.
|
||||
pub fn new_helm_error(event_details: EventDetails, error: HelmError) -> EngineError {
|
||||
let cmd_error = match &error {
|
||||
HelmError::CmdError(_, _, cmd_error) => Some(cmd_error.clone()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::HelmChartUninstallError,
|
||||
error.to_string(),
|
||||
error.to_string(),
|
||||
cmd_error,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error while uninstalling Helm chart.
|
||||
///
|
||||
/// Arguments:
|
||||
|
||||
23
tests/helm/simple_nginx/.helmignore
Normal file
23
tests/helm/simple_nginx/.helmignore
Normal file
@@ -0,0 +1,23 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
24
tests/helm/simple_nginx/Chart.yaml
Normal file
24
tests/helm/simple_nginx/Chart.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
apiVersion: v2
|
||||
name: nginx
|
||||
description: A Helm chart for Kubernetes
|
||||
|
||||
# A chart can be either an 'application' or a 'library' chart.
|
||||
#
|
||||
# Application charts are a collection of templates that can be packaged into versioned archives
|
||||
# to be deployed.
|
||||
#
|
||||
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
||||
# a dependency of application charts to inject those utilities and functions into the rendering
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.1.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "1.16.0"
|
||||
62
tests/helm/simple_nginx/templates/_helpers.tpl
Normal file
62
tests/helm/simple_nginx/templates/_helpers.tpl
Normal file
@@ -0,0 +1,62 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "toto.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "toto.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "toto.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "toto.labels" -}}
|
||||
helm.sh/chart: {{ include "toto.chart" . }}
|
||||
{{ include "toto.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "toto.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "toto.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "toto.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "toto.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
62
tests/helm/simple_nginx/templates/deployment.yaml
Normal file
62
tests/helm/simple_nginx/templates/deployment.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "toto.fullname" . }}
|
||||
labels:
|
||||
{{- include "toto.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "toto.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "toto.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "toto.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
readinessProbe:
|
||||
initialDelaySeconds: {{ .Values.initialDelaySeconds }}
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
28
tests/helm/simple_nginx/templates/hpa.yaml
Normal file
28
tests/helm/simple_nginx/templates/hpa.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
{{- if .Values.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "toto.fullname" . }}
|
||||
labels:
|
||||
{{- include "toto.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "toto.fullname" . }}
|
||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
61
tests/helm/simple_nginx/templates/ingress.yaml
Normal file
61
tests/helm/simple_nginx/templates/ingress.yaml
Normal file
@@ -0,0 +1,61 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "toto.fullname" . -}}
|
||||
{{- $svcPort := .Values.service.port -}}
|
||||
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
|
||||
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
|
||||
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
{{- else -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{- include "toto.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
|
||||
pathType: {{ .pathType }}
|
||||
{{- end }}
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ $fullName }}
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
{{- else }}
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $svcPort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
15
tests/helm/simple_nginx/templates/service.yaml
Normal file
15
tests/helm/simple_nginx/templates/service.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "toto.fullname" . }}
|
||||
labels:
|
||||
{{- include "toto.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "toto.selectorLabels" . | nindent 4 }}
|
||||
12
tests/helm/simple_nginx/templates/serviceaccount.yaml
Normal file
12
tests/helm/simple_nginx/templates/serviceaccount.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "toto.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "toto.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
15
tests/helm/simple_nginx/templates/tests/test-connection.yaml
Normal file
15
tests/helm/simple_nginx/templates/tests/test-connection.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "toto.fullname" . }}-test-connection"
|
||||
labels:
|
||||
{{- include "toto.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "toto.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
||||
83
tests/helm/simple_nginx/values.yaml
Normal file
83
tests/helm/simple_nginx/values.yaml
Normal file
@@ -0,0 +1,83 @@
|
||||
# Default values for toto.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
replicaCount: 1
|
||||
initialDelaySeconds: 5
|
||||
|
||||
image:
|
||||
repository: nginx
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
podAnnotations: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
className: ""
|
||||
annotations: {}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
hosts:
|
||||
- host: chart-example.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 100
|
||||
targetCPUUtilizationPercentage: 80
|
||||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
Reference in New Issue
Block a user