fix: selector to be injected to helm chart (#537)

This commit is contained in:
Benjamin
2021-12-22 14:01:29 +01:00
committed by GitHub
parent e1fa1dd660
commit f02fc4572d
25 changed files with 248 additions and 130 deletions

View File

@@ -97,6 +97,10 @@ impl crate::cloud_provider::service::Application for Application {
}
impl Helm for Application {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("application-{}-{}", self.name(), self.id()), 50)
}
@@ -275,8 +279,8 @@ impl Service for Application {
Ok(context)
}
fn selector(&self) -> String {
format!("appId={}", self.id)
fn selector(&self) -> Option<String> {
Some(format!("appId={}", self.id))
}
fn engine_error_scope(&self) -> EngineErrorScope {

View File

@@ -213,8 +213,8 @@ impl Service for MongoDB {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -229,6 +229,10 @@ impl Service for MongoDB {
impl Database for MongoDB {}
impl Helm for MongoDB {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("mongodb-{}", self.id()), 50)
}

View File

@@ -224,8 +224,8 @@ impl Service for MySQL {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -240,6 +240,10 @@ impl Service for MySQL {
impl Database for MySQL {}
impl Helm for MySQL {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("mysql-{}", self.id()), 50)
}

View File

@@ -211,8 +211,8 @@ impl Service for PostgreSQL {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -227,6 +227,10 @@ impl Service for PostgreSQL {
impl Database for PostgreSQL {}
impl Helm for PostgreSQL {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("postgresql-{}", self.id()), 50)
}

View File

@@ -224,8 +224,8 @@ impl Service for Redis {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -240,6 +240,10 @@ impl Service for Redis {
impl Database for Redis {}
impl Helm for Redis {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("redis-{}", self.id()), 50)
}

View File

@@ -1242,12 +1242,14 @@ impl HelmChart for AwsVpcCniChart {
let chart_infos = self.get_chart_info();
// Cleaning any existing crash looping pod for this helm chart
kubectl_delete_crash_looping_pods(
&kubernetes_config,
Some(chart_infos.get_namespace_string().as_str()),
Some(chart_infos.get_selector_string().as_str()),
environment_variables.clone(),
)?;
if let Some(selector) = self.get_selector() {
kubectl_delete_crash_looping_pods(
&kubernetes_config,
Some(chart_infos.get_namespace_string().as_str()),
Some(selector.as_str()),
environment_variables.clone(),
)?;
}
match self.enable_cni_managed_by_helm(kubernetes_config, envs) {
true => {

View File

@@ -217,8 +217,8 @@ impl Service for Router {
Ok(context)
}
fn selector(&self) -> String {
format!("routerId={}", self.id)
fn selector(&self) -> Option<String> {
Some(format!("routerId={}", self.id))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -243,6 +243,10 @@ impl crate::cloud_provider::service::Router for Router {
}
impl Helm for Router {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("router-{}", self.id()), 50)
}
@@ -307,6 +311,7 @@ impl Create for Router {
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(),

View File

@@ -99,6 +99,10 @@ impl crate::cloud_provider::service::Application for Application {
}
impl Helm for Application {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("application-{}-{}", self.name, self.id), 50)
}
@@ -276,8 +280,8 @@ impl Service for Application {
Ok(context)
}
fn selector(&self) -> String {
format!("appId={}", self.id)
fn selector(&self) -> Option<String> {
Some(format!("appId={}", self.id))
}
fn engine_error_scope(&self) -> EngineErrorScope {

View File

@@ -197,8 +197,8 @@ impl Service for MongoDB {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -213,6 +213,10 @@ impl Service for MongoDB {
impl Database for MongoDB {}
impl Helm for MongoDB {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("mongodb-{}", self.id()), 50)
}

View File

@@ -197,8 +197,8 @@ impl Service for MySQL {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -213,6 +213,10 @@ impl Service for MySQL {
impl Database for MySQL {}
impl Helm for MySQL {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("mysql-{}", self.id()), 50)
}

View File

@@ -199,8 +199,8 @@ impl Service for PostgreSQL {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -215,6 +215,10 @@ impl Service for PostgreSQL {
impl Database for PostgreSQL {}
impl Helm for PostgreSQL {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("postgresql-{}", self.id()), 50)
}

View File

@@ -196,8 +196,8 @@ impl Service for Redis {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -212,6 +212,10 @@ impl Service for Redis {
impl Database for Redis {}
impl Helm for Redis {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("redis-{}", self.id()), 50)
}

View File

@@ -232,8 +232,8 @@ impl Service for Router {
Ok(context)
}
fn selector(&self) -> String {
format!("routerId={}", self.id)
fn selector(&self) -> Option<String> {
Some(format!("routerId={}", self.id))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -258,6 +258,10 @@ impl crate::cloud_provider::service::Router for Router {
}
impl Helm for Router {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("router-{}", self.id()), 50)
}
@@ -326,6 +330,7 @@ impl Create for Router {
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(),

View File

@@ -82,6 +82,7 @@ pub struct ChartInfo {
pub values_files: Vec<String>,
pub yaml_files_content: Vec<ChartValuesGenerated>,
pub parse_stderr_for_error: bool,
pub k8s_selector: Option<String>,
}
impl ChartInfo {
@@ -92,6 +93,7 @@ impl ChartInfo {
timeout_in_seconds: i64,
values_files: Vec<String>,
parse_stderr_for_error: bool,
k8s_selector: Option<String>,
) -> Self {
ChartInfo {
name,
@@ -101,6 +103,7 @@ impl ChartInfo {
timeout_in_seconds,
values_files,
parse_stderr_for_error,
k8s_selector,
..Default::default()
}
}
@@ -114,10 +117,6 @@ impl ChartInfo {
_ => self.namespace.to_string(),
}
}
pub fn get_selector_string(&self) -> String {
format!("app={}", self.name.to_lowercase())
}
}
impl Default for ChartInfo {
@@ -138,6 +137,7 @@ impl Default for ChartInfo {
values_files: Vec::new(),
yaml_files_content: vec![],
parse_stderr_for_error: true,
k8s_selector: None,
}
}
}
@@ -162,6 +162,11 @@ pub trait HelmChart: Send {
Ok(None)
}
fn get_selector(&self) -> Option<String> {
let infos = self.get_chart_info();
infos.k8s_selector.clone()
}
fn get_chart_info(&self) -> &ChartInfo;
fn namespace(&self) -> String {
@@ -177,12 +182,14 @@ pub trait HelmChart: Send {
let chart_infos = self.get_chart_info();
// Cleaning any existing crash looping pod for this helm chart
kubectl_delete_crash_looping_pods(
&kubernetes_config,
Some(chart_infos.get_namespace_string().as_str()),
Some(chart_infos.get_selector_string().as_str()),
envs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect(),
)?;
if let Some(selector) = self.get_selector() {
kubectl_delete_crash_looping_pods(
&kubernetes_config,
Some(chart_infos.get_namespace_string().as_str()),
Some(selector.as_str()),
envs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect(),
)?;
}
Ok(payload)
}
@@ -402,12 +409,14 @@ impl HelmChart for CoreDNSConfigChart {
let chart_infos = self.get_chart_info();
// Cleaning any existing crash looping pod for this helm chart
kubectl_delete_crash_looping_pods(
&kubernetes_config,
Some(chart_infos.get_namespace_string().as_str()),
Some(chart_infos.get_selector_string().as_str()),
environment_variables.clone(),
)?;
if let Some(selector) = self.get_selector() {
kubectl_delete_crash_looping_pods(
&kubernetes_config,
Some(chart_infos.get_namespace_string().as_str()),
Some(selector.as_str()),
environment_variables.clone(),
)?;
}
// calculate current configmap checksum
let current_configmap_hash = match kubectl_exec_get_configmap(
@@ -815,11 +824,11 @@ pub fn get_chart_for_shell_agent(
},
ChartSetValue {
key: "environmentVariables.RUST_BACKTRACE".to_string(),
value: "full".to_string()
value: "full".to_string(),
},
ChartSetValue {
key: "environmentVariables.RUST_LOG".to_string(),
value: "DEBUG".to_string()
value: "DEBUG".to_string(),
},
ChartSetValue {
key: "environmentVariables.GRPC_SERVER".to_string(),

View File

@@ -219,8 +219,8 @@ pub trait Kubernetes: Listen {
e.message,
))
}
Ok(config_path) => match kubectl_get_crash_looping_pods::<dyn AsRef<Path>>(
Box::new(&config_path.0),
Ok(config_path) => match kubectl_get_crash_looping_pods(
&config_path.0,
namespace,
selector,
restarted_min_count,
@@ -228,21 +228,18 @@ pub trait Kubernetes: Listen {
) {
Ok(pods) => {
for pod in pods {
match kubectl_exec_delete_pod::<dyn AsRef<Path>>(
Box::new(&config_path.0),
if let Err(e) = kubectl_exec_delete_pod(
&config_path.0,
pod.metadata.namespace.as_str(),
pod.metadata.name.as_str(),
envs.clone(),
) {
Ok(..) => {}
Err(e) => {
return Err(EngineError::new(
EngineErrorCause::Internal,
self.engine_error_scope(),
self.context().execution_id(),
e.message,
))
}
return Err(EngineError::new(
EngineErrorCause::Internal,
self.engine_error_scope(),
self.context().execution_id(),
e.message,
));
}
}
}

View File

@@ -100,6 +100,10 @@ impl crate::cloud_provider::service::Application for Application {
}
impl Helm for Application {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("application-{}-{}", self.name(), self.id()), 50)
}
@@ -294,8 +298,8 @@ impl Service for Application {
Ok(context)
}
fn selector(&self) -> String {
format!("appId={}", self.id)
fn selector(&self) -> Option<String> {
Some(format!("appId={}", self.id))
}
fn engine_error_scope(&self) -> EngineErrorScope {

View File

@@ -198,8 +198,8 @@ impl Service for MongoDB {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -214,6 +214,10 @@ impl Service for MongoDB {
impl Database for MongoDB {}
impl Helm for MongoDB {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("mongodb-{}", self.id()), 50)
}

View File

@@ -235,8 +235,8 @@ impl Service for MySQL {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -251,6 +251,10 @@ impl Service for MySQL {
impl Database for MySQL {}
impl Helm for MySQL {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("mysql-{}", self.id()), 50)
}

View File

@@ -244,8 +244,8 @@ impl Service for PostgreSQL {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -260,6 +260,10 @@ impl Service for PostgreSQL {
impl Database for PostgreSQL {}
impl Helm for PostgreSQL {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("postgresql-{}", self.id()), 50)
}

View File

@@ -197,8 +197,8 @@ impl Service for Redis {
Ok(context)
}
fn selector(&self) -> String {
format!("app={}", self.sanitized_name())
fn selector(&self) -> Option<String> {
Some(format!("app={}", self.sanitized_name()))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -213,6 +213,10 @@ impl Service for Redis {
impl Database for Redis {}
impl Helm for Redis {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("redis-{}", self.id()), 50)
}

View File

@@ -181,8 +181,8 @@ impl Service for Router {
Ok(context)
}
fn selector(&self) -> String {
format!("routerId={}", self.id)
fn selector(&self) -> Option<String> {
Some(format!("routerId={}", self.id))
}
fn engine_error_scope(&self) -> EngineErrorScope {
@@ -207,6 +207,10 @@ impl crate::cloud_provider::service::Router for Router {
}
impl Helm for Router {
fn helm_selector(&self) -> Option<String> {
self.selector()
}
fn helm_release_name(&self) -> String {
crate::string::cut(format!("router-{}", self.id()), 50)
}
@@ -272,6 +276,7 @@ impl Create for Router {
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(),

View File

@@ -70,7 +70,7 @@ pub trait Service {
}
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError>;
// used to retrieve logs by using Kubernetes labels (selector)
fn selector(&self) -> String;
fn selector(&self) -> Option<String>;
fn debug_logs(&self, deployment_target: &DeploymentTarget) -> Vec<String> {
debug_logs(self, deployment_target)
}
@@ -204,6 +204,7 @@ pub trait Terraform {
}
pub trait Helm {
fn helm_selector(&self) -> Option<String>;
fn helm_release_name(&self) -> String;
fn helm_chart_dir(&self) -> String;
fn helm_chart_values_dir(&self) -> String;
@@ -396,6 +397,7 @@ where
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(),
@@ -414,7 +416,7 @@ where
crate::cmd::kubectl::kubectl_exec_is_pod_ready_with_retry(
kubernetes_config_file_path.as_str(),
environment.namespace(),
service.selector().as_str(),
service.selector().unwrap_or("".to_string()).as_str(),
kubernetes.cloud_provider().credentials_environment_variables(),
),
)?;
@@ -500,7 +502,7 @@ pub fn scale_down_application(
kubernetes.cloud_provider().credentials_environment_variables(),
environment.namespace(),
scaling_kind,
service.selector().as_str(),
service.selector().unwrap_or("".to_string()).as_str(),
replicas_count as u32,
);
@@ -529,7 +531,11 @@ where
let helm_release_name = service.helm_release_name();
if is_error {
let _ = get_stateless_resource_information(kubernetes, environment, service.selector().as_str())?;
let _ = get_stateless_resource_information(
kubernetes,
environment,
service.selector().unwrap_or("".to_string()).as_str(),
)?;
}
// clean the resource
@@ -658,6 +664,7 @@ where
kubernetes_config_file_path.as_str(),
environment.namespace(),
service.helm_release_name().as_str(),
service.selector(),
workspace_dir.as_str(),
service.start_timeout(),
kubernetes.cloud_provider().credentials_environment_variables(),
@@ -680,7 +687,7 @@ where
match crate::cmd::kubectl::kubectl_exec_is_pod_ready_with_retry(
kubernetes_config_file_path.as_str(),
environment.namespace(),
service.selector().as_str(),
service.selector().unwrap_or("".to_string()).as_str(),
kubernetes.cloud_provider().credentials_environment_variables(),
) {
Ok(Some(true)) => {}
@@ -979,7 +986,7 @@ pub fn get_stateless_resource_information_for_user<T>(
where
T: Service + ?Sized,
{
let selector = service.selector();
let selector = service.selector().unwrap_or("".to_string());
let kubernetes_config_file_path = kubernetes.config_file_path()?;
let mut result = Vec::with_capacity(50);
@@ -994,7 +1001,7 @@ where
kubernetes.cloud_provider().credentials_environment_variables(),
),
)
.unwrap_or_else(|_| vec![format!("Unable to retrieve logs for pod: {}", selector)]);
.unwrap_or_else(|_| vec![format!("Unable to retrieve logs for pod with selector: {:?}", selector,)]);
let _ = result.extend(logs);

View File

@@ -40,6 +40,7 @@ pub fn helm_exec_with_upgrade_history<P>(
kubernetes_config: P,
namespace: &str,
release_name: &str,
selector: Option<String>,
chart_root_dir: P,
timeout: Timeout<u32>,
envs: Vec<(&str, &str)>,
@@ -72,6 +73,7 @@ where
_ => vec![],
},
false,
selector,
),
};

View File

@@ -743,6 +743,38 @@ where
kubectl_exec::<P, KubernetesList<KubernetesPod>>(cmd_args, kubernetes_config, envs)
}
/// kubectl_exec_get_pod_by_name: allows to retrieve a pod by its name
///
/// # Arguments
///
/// * `kubernetes_config` - kubernetes config path
/// * `namespace` - kubernetes namespace
/// * `pod_name` - pod's name
/// * `envs` - environment variables required for kubernetes connection
pub fn kubectl_exec_get_pod_by_name<P>(
kubernetes_config: P,
namespace: Option<&str>,
pod_name: &str,
envs: Vec<(&str, &str)>,
) -> Result<KubernetesPod, SimpleError>
where
P: AsRef<Path>,
{
let mut cmd_args = vec!["get", "pod", "-o", "json"];
match namespace {
Some(n) => {
cmd_args.push("-n");
cmd_args.push(n);
}
None => cmd_args.push("--all-namespaces"),
}
cmd_args.push(pod_name);
kubectl_exec::<P, KubernetesPod>(cmd_args, kubernetes_config, envs)
}
pub fn kubectl_exec_get_configmap<P>(
kubernetes_config: P,
namespace: &str,
@@ -1044,14 +1076,14 @@ where
P: AsRef<Path>,
{
let crash_looping_pods =
match kubectl_get_crash_looping_pods(Box::new(&kubernetes_config), namespace, selector, None, envs.clone()) {
match kubectl_get_crash_looping_pods(&kubernetes_config, namespace, selector, None, envs.clone()) {
Ok(pods) => pods,
Err(e) => return Err(e),
};
for crash_looping_pod in crash_looping_pods.iter() {
if let Err(e) = kubectl_exec_delete_pod(
Box::new(&kubernetes_config),
&kubernetes_config,
crash_looping_pod.metadata.namespace.as_str(),
crash_looping_pod.metadata.name.as_str(),
envs.clone(),
@@ -1072,8 +1104,8 @@ where
/// * `selector`: selector to look for, if None, will look for anything.
/// * `restarted_min_count`: minimum restart counts to be considered as crash looping. If None, default is 5.
/// * `envs`: environment variables to be passed to kubectl.
pub fn kubectl_get_crash_looping_pods<P: ?Sized>(
kubernetes_config: Box<P>,
pub fn kubectl_get_crash_looping_pods<P>(
kubernetes_config: P,
namespace: Option<&str>,
selector: Option<&str>,
restarted_min_count: Option<usize>,
@@ -1083,29 +1115,30 @@ where
P: AsRef<Path>,
{
let restarted_min = restarted_min_count.unwrap_or(5usize);
let pods = kubectl_exec_get_pods(kubernetes_config.as_ref(), namespace, selector, envs)?;
let pods = kubectl_exec_get_pods(kubernetes_config, namespace, selector, envs)?;
// Pod needs to have at least one container having backoff status (check 1)
// AND at least a container with minimum restarts (asked in inputs) (check 2)
Ok(pods
let crash_looping_pods = pods
.items
.into_iter()
.filter(|pod| {
pod.status.container_statuses.as_ref().is_some()
&& pod
.status
.conditions
.iter()
.any(|c| c.reason == KubernetesPodStatusReason::BackOff) // check 1
&& pod
.status
.container_statuses
.as_ref()
.expect("Cannot get container statuses")
.iter()
.any(|e| e.restart_count >= restarted_min) // check 2
.into_iter()
.any(|e| {
e.state.waiting.as_ref().is_some()
&& e.state.waiting.as_ref().expect("cannot get container state").reason == KubernetesPodStatusReason::CrashLoopBackOff // check 1
&& e.restart_count >= restarted_min // check 2
})
})
.collect::<Vec<KubernetesPod>>())
.collect::<Vec<KubernetesPod>>();
Ok(crash_looping_pods)
}
/// kubectl_exec_delete_pod: allow to delete a k8s pod if exists.
@@ -1116,8 +1149,8 @@ where
/// * `pod_namespace`: pod's namespace.
/// * `pod_name`: pod's name.
/// * `envs`: environment variables to be passed to kubectl.
pub fn kubectl_exec_delete_pod<P: ?Sized>(
kubernetes_config: Box<P>,
pub fn kubectl_exec_delete_pod<P>(
kubernetes_config: P,
pod_namespace: &str,
pod_name: &str,
envs: Vec<(&str, &str)>,
@@ -1125,29 +1158,17 @@ pub fn kubectl_exec_delete_pod<P: ?Sized>(
where
P: AsRef<Path>,
{
let pod_to_be_deleted = match kubectl_exec_get_pods(
kubernetes_config.as_ref(),
Some(pod_namespace),
Some(pod_name),
envs.clone(),
) {
Ok(pods) => {
if pods.items.is_empty() {
return Err(SimpleError::new(
SimpleErrorKind::Other,
Some(format!(
"Cannot delete pod `{}` in namespace `{}`, pod is not found.",
pod_name, pod_namespace
)),
));
}
let pod_to_be_deleted =
match kubectl_exec_get_pod_by_name(&kubernetes_config, Some(pod_namespace), pod_name, envs.clone()) {
Ok(pod) => pod,
Err(e) => return Err(e),
};
pods.items[0].clone()
}
Err(e) => return Err(e),
};
let mut complete_envs = Vec::with_capacity(envs.len() + 1);
complete_envs.push((KUBECONFIG, kubernetes_config.as_ref().to_str().unwrap()));
complete_envs.extend(envs);
kubectl_exec(
match kubectl_exec_with_output(
vec![
"delete",
"pod",
@@ -1155,11 +1176,13 @@ where
"-n",
pod_to_be_deleted.metadata.namespace.as_str(),
],
kubernetes_config.as_ref(),
envs,
)?;
Ok(pod_to_be_deleted)
complete_envs,
|_| {},
|_| {},
) {
Ok(_) => Ok(pod_to_be_deleted),
Err(e) => Err(e),
}
}
fn kubectl_exec<P, T>(args: Vec<&str>, kubernetes_config: P, envs: Vec<(&str, &str)>) -> Result<T, SimpleError>

View File

@@ -131,7 +131,7 @@ pub enum KubernetesPodStatusReason {
Failed,
Killing,
Preempting,
BackOff,
CrashLoopBackOff,
ExceededGracePeriod,
}
@@ -149,7 +149,7 @@ impl From<String> for KubernetesPodStatusReason {
"failed" => KubernetesPodStatusReason::Failed,
"killing" => KubernetesPodStatusReason::Killing,
"preempting" => KubernetesPodStatusReason::Preempting,
"backoff" => KubernetesPodStatusReason::BackOff,
"crashloopbackoff" => KubernetesPodStatusReason::CrashLoopBackOff,
"exceededgraceperiod" => KubernetesPodStatusReason::ExceededGracePeriod,
_ => Unknown(match s.as_str() {
"" => None,
@@ -182,14 +182,15 @@ pub enum KubernetesPodStatusPhase {
#[derive(Deserialize, Clone, Eq, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct KubernetesPodContainerStatus {
pub last_state: Option<KubernetesPodContainerStatusLastState>,
pub last_state: Option<KubernetesPodContainerStatusState>,
pub state: KubernetesPodContainerStatusState,
pub ready: bool,
pub restart_count: usize,
}
#[derive(Deserialize, Clone, Eq, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct KubernetesPodContainerStatusLastState {
pub struct KubernetesPodContainerStatusState {
pub terminated: Option<ContainerStatusTerminated>,
pub waiting: Option<ContainerStatusWaiting>,
}
@@ -198,7 +199,8 @@ pub struct KubernetesPodContainerStatusLastState {
#[serde(rename_all = "camelCase")]
pub struct ContainerStatusWaiting {
pub message: Option<String>,
pub reason: String,
#[serde(default)]
pub reason: KubernetesPodStatusReason,
}
#[derive(Deserialize, Clone, Eq, PartialEq, Debug)]
@@ -206,7 +208,8 @@ pub struct ContainerStatusWaiting {
pub struct ContainerStatusTerminated {
pub exit_code: i16,
pub message: Option<String>,
pub reason: String,
#[serde(default)]
pub reason: KubernetesPodStatusReason,
}
#[derive(Deserialize, Clone, Eq, PartialEq)]
@@ -1199,7 +1202,7 @@ mod tests {
"lastProbeTime": null,
"lastTransitionTime": "2021-03-15T15:41:56Z",
"message": "0/5 nodes are available: 5 Insufficient memory.",
"reason": "BackOff",
"reason": "CrashLoopBackOff",
"status": "False",
"type": "PodScheduled"
}
@@ -1222,7 +1225,7 @@ mod tests {
assert_eq!(pod_status.items[0].status.conditions[0].status, "False");
assert_eq!(
pod_status.items[0].status.conditions[0].reason,
KubernetesPodStatusReason::BackOff
KubernetesPodStatusReason::CrashLoopBackOff
);
let payload = r#"{