feat: bump new Pleco version to support kubernetes delete

This commit is contained in:
Pierre Mavro
2020-12-04 14:30:17 +01:00
committed by Pierre Mavro
parent a78747ef08
commit a749dd86b9
13 changed files with 187 additions and 21 deletions

View File

@@ -13,6 +13,11 @@ resource "helm_release" "pleco" {
value = timestamp()
}
set {
name = "environmentVariables.DISABLE_DRY_RUN"
value = "true"
}
set {
name = "environmentVariables.AWS_ACCESS_KEY_ID"
value = "{{ aws_access_key }}"

View File

@@ -1,9 +1,9 @@
apiVersion: v2
appVersion: 0.2.1
appVersion: 0.3.0
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.2.1
version: 0.3.0

View File

@@ -38,9 +38,20 @@ spec:
- {{ .Values.environmentVariables.LOG_LEVEL | default "info" }}
- --check-interval
- "{{ .Values.environmentVariables.CHECK_INTERVAL | default 120 }}"
{{ if .Values.environmentVariables.DRY_RUN }}
{{ if not .Values.environmentVariables.DISABLE_DRY_RUN}}
- --dry-run
{{ end }}
- --kube-conn
- {{ .Values.enabledFeatures.kubernetes }}
{{ if eq .Values.enabledFeatures.rds true}}
- --enable-rds
{{ end }}
{{ if eq .Values.enabledFeatures.elasticache true}}
- --enable-elasticache
{{ end }}
{{ if eq .Values.enabledFeatures.documentdb true}}
- --enable-documentdb
{{ end }}
env:
{{ range $key, $value := .Values.environmentVariables -}}
- name: "{{ $key }}"

View File

@@ -3,15 +3,23 @@ replicaCount: 1
image:
repository: qoveryrd/pleco
pullPolicy: IfNotPresent
plecoImageTag: "v0.2.1"
plecoImageTag: "v0.3.0"
environmentVariables:
CHECK_INTERVAL: "120"
DRY_RUN: "true"
DISABLE_DRY_RUN: "false"
LOG_LEVEL: "info"
# AWS_ACCESS_KEY_ID: ""
# AWS_SECRET_ACCESS_KEY: ""
# AWS_DEFAULT_REGION: ""
# KUBECONFIG: ""
enabledFeatures:
# Choose between in/out/off
kubernetes: "in"
rds: true
documentdb: true
elasticache: true
imagePullSecrets: []
nameOverride: ""

View File

@@ -55,7 +55,7 @@ charts:
version: 12.0.1
dest: services
- name: pleco
version: 0.2.1
version: 0.3.0
repo_name: pleco
repos:

View File

@@ -16,6 +16,7 @@ use crate::error::{
cast_simple_error_to_engine_error, EngineError, EngineErrorCause,
};
use crate::models::Context;
use crate::cmd::structs::LabelsContent;
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct Application {
@@ -131,6 +132,13 @@ impl Application {
context.insert("clone", &false);
context.insert("start_timeout_in_seconds", &self.start_timeout_in_seconds);
if self.context.resource_expiration_in_seconds().is_some() {
context.insert(
"resource_expiration_in_seconds",
&self.context.resource_expiration_in_seconds(),
)
}
context
}
@@ -277,6 +285,27 @@ impl Create for Application {
),
)?;
// define labels to add to namespace
let namespace_labels = match self.context.resource_expiration_in_seconds() {
Some(v) => Some(vec![(LabelsContent{
name: "ttl".to_string(),
value: format!{"{}", self.context.resource_expiration_in_seconds().unwrap()},
})]),
None => None,
};
// create a namespace with labels if do not exists
let _ = cast_simple_error_to_engine_error(
self.engine_error_scope(),
self.context.execution_id(),
crate::cmd::kubectl::kubectl_exec_create_namespace(
kubernetes_config_file_path.as_str(),
environment.namespace(),
namespace_labels,
aws_credentials_envs.clone(),
),
)?;
// do exec helm upgrade and return the last deployment status
let helm_history_row = cast_simple_error_to_engine_error(
self.engine_error_scope(),

View File

@@ -98,7 +98,7 @@ impl MongoDB {
.downcast_ref::<AWS>()
.unwrap();
utilities::create_namespace(&environment.namespace(), kube_config.as_str(), aws);
utilities::create_namespace_without_labels(&environment.namespace(), kube_config.as_str(), aws);
}
Err(e) => error!(
"Failed to generate the kubernetes config file path: {:?}",

View File

@@ -95,7 +95,7 @@ impl MySQL {
.downcast_ref::<AWS>()
.unwrap();
utilities::create_namespace(&environment.namespace(), kube_config.as_str(), aws);
utilities::create_namespace_without_labels(&environment.namespace(), kube_config.as_str(), aws);
}
Err(e) => error!(
"Failed to generate the kubernetes config file path: {:?}",

View File

@@ -95,7 +95,7 @@ impl PostgreSQL {
.downcast_ref::<AWS>()
.unwrap();
utilities::create_namespace(&environment.namespace(), kube_config.as_str(), aws);
utilities::create_namespace_without_labels(&environment.namespace(), kube_config.as_str(), aws);
}
Err(e) => error!(
"Failed to generate the kubernetes config file path: {:?}",

View File

@@ -102,7 +102,7 @@ impl Redis {
.downcast_ref::<AWS>()
.unwrap();
utilities::create_namespace(&environment.namespace(), kube_config.as_str(), aws);
utilities::create_namespace_without_labels(&environment.namespace(), kube_config.as_str(), aws);
}
Err(e) => error!(
"Failed to generate the kubernetes config file path: {:?}",

View File

@@ -29,12 +29,12 @@ pub fn get_kubernetes_config_path(
)
}
pub fn create_namespace(namespace: &str, kube_config: &str, aws: &AWS) {
pub fn create_namespace_without_labels(namespace: &str, kube_config: &str, aws: &AWS) {
let aws_credentials_envs = vec![
(AWS_ACCESS_KEY_ID, aws.access_key_id.as_str()),
(AWS_SECRET_ACCESS_KEY, aws.secret_access_key.as_str()),
];
kubectl_exec_create_namespace(kube_config, namespace, aws_credentials_envs);
kubectl_exec_create_namespace(kube_config, namespace,None, aws_credentials_envs);
}
pub fn delete_terraform_tfstate_secret(

View File

@@ -4,10 +4,7 @@ use std::path::Path;
use retry::delay::Fibonacci;
use retry::OperationResult;
use crate::cmd::structs::{
Item, KubernetesJob, KubernetesList, KubernetesNode, KubernetesPod, KubernetesPodStatusPhase,
KubernetesService,
};
use crate::cmd::structs::{Item, KubernetesJob, KubernetesList, KubernetesNode, KubernetesPod, KubernetesPodStatusPhase, KubernetesService, LabelsContent};
use crate::cmd::utilities::exec_with_envs_and_output;
use crate::error::{SimpleError, SimpleErrorKind};
use crate::constants::KUBECONFIG;
@@ -347,20 +344,131 @@ where
Ok(Some(false))
}
pub fn kubectl_exec_create_namespace<P>(
pub fn kubectl_exec_is_namespace_present<P>(
kubernetes_config: P,
namespace: &str,
envs: Vec<(&str, &str)>,
) -> Result<(), SimpleError>
where
P: AsRef<Path>,
) -> bool
where
P: AsRef<Path>,
{
let mut _envs = Vec::with_capacity(envs.len() + 1);
_envs.push((KUBECONFIG, kubernetes_config.as_ref().to_str().unwrap()));
_envs.extend(envs);
let mut output_vec: Vec<String> = Vec::new();
let result = kubectl_exec_with_output(
vec!["get", "namespace", namespace],
_envs,
|out| match out {
Ok(line) => output_vec.push(line),
Err(err) => error!("{:?}", err),
},
|out| match out {
Ok(line) => error!("{}", line),
Err(err) => error!("{:?}", err),
},
);
match result {
Ok(_) => true,
Err(_) => false,
}
}
pub fn kubectl_exec_create_namespace<P>(
kubernetes_config: P,
namespace: &str,
labels: Option<Vec<LabelsContent>>,
envs: Vec<(&str, &str)>,
) -> Result<(), SimpleError>
where
P: AsRef<Path>,
{
// don't create the namespace if already exists and not not return error in this case
if !kubectl_exec_is_namespace_present(
kubernetes_config.as_ref(),
namespace.clone(),
envs.clone(),
) {
// create namespace
let mut _envs = Vec::with_capacity(envs.len() + 1);
_envs.push((KUBECONFIG, kubernetes_config.as_ref().to_str().unwrap()));
_envs.extend(envs.clone());
let _ = kubectl_exec_with_output(
vec!["create", "namespace", namespace],
_envs,
|out| match out {
Ok(line) => info!("{}", line),
Err(err) => error!("{:?}", err),
},
|out| match out {
Ok(line) => error!("{}", line),
Err(err) => error!("{:?}", err),
},
)?;
}
// additional labels
if labels.is_some() {
match kubectl_add_labels_to_namespace(
kubernetes_config,
namespace,
labels.unwrap(),
envs,
) {
Ok(_) => {},
Err(e) => return Err(e),
}
};
Ok(())
}
pub fn kubectl_add_labels_to_namespace<P>(
kubernetes_config: P,
namespace: &str,
labels: Vec<LabelsContent>,
envs: Vec<(&str, &str)>,
) -> Result<(), SimpleError>
where
P: AsRef<Path>,
{
if labels.iter().count() > 0 {
return Err(SimpleError::new(
SimpleErrorKind::Other,
Some("No labels were defined, can't set them"),
));
};
if !kubectl_exec_is_namespace_present(
kubernetes_config.as_ref(),
namespace.clone(),
envs.clone(),
) {
return Err(SimpleError::new(
SimpleErrorKind::Other,
Some(format!{"Can't set labels on namespace {} because it doesn't exists", namespace}),
));
}
let mut command_args = Vec::new();
let mut labels_string = Vec::new();
command_args.extend(vec!["label", "namespace", namespace, "--overwrite"]);
for label in labels.iter() {
labels_string.push(format!{"{}={}", label.name, label.value});
};
let labels_str = labels_string.iter().map(|x| x.as_ref()).collect::<Vec<&str>>();
command_args.extend(labels_str);
let mut _envs = Vec::with_capacity(envs.len() + 1);
_envs.push((KUBECONFIG, kubernetes_config.as_ref().to_str().unwrap()));
_envs.extend(envs.clone());
let _ = kubectl_exec_with_output(
vec!["create", "namespace", namespace],
command_args,
_envs,
|out| match out {
Ok(line) => info!("{}", line),

View File

@@ -18,6 +18,11 @@ pub struct Labels {
pub name: String,
}
pub struct LabelsContent {
pub name: String,
pub value: String,
}
#[derive(Default, Debug, Clone, PartialEq, serde_derive::Serialize, serde_derive::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Spec {