mirror of
https://github.com/jlengrand/engine.git
synced 2026-03-10 08:11:21 +00:00
feat: migrate env logging to new method
Ticket: ENG-1112
This commit is contained in:
committed by
Benjamin
parent
eb561b8dad
commit
4be43c3bec
@@ -6,10 +6,12 @@ use git2::{Cred, CredentialType};
|
||||
use sysinfo::{Disk, DiskExt, SystemExt};
|
||||
|
||||
use crate::build_platform::{docker, Build, BuildPlatform, BuildResult, CacheResult, Credentials, Image, Kind};
|
||||
use crate::cmd::command::{CommandError, QoveryCommand};
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope, SimpleError};
|
||||
use crate::cmd::command::QoveryCommand;
|
||||
use crate::errors::{CommandError, EngineError, Tag};
|
||||
use crate::events::{EngineEvent, EventDetails, EventMessage, ToTransmitter, Transmitter};
|
||||
use crate::fs::workspace_directory;
|
||||
use crate::git;
|
||||
use crate::logger::{LogLevel, Logger};
|
||||
use crate::models::{
|
||||
Context, Listen, Listener, Listeners, ListenersHelper, ProgressInfo, ProgressLevel, ProgressScope,
|
||||
};
|
||||
@@ -30,15 +32,17 @@ pub struct LocalDocker {
|
||||
id: String,
|
||||
name: String,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl LocalDocker {
|
||||
pub fn new(context: Context, id: &str, name: &str) -> Self {
|
||||
pub fn new(context: Context, id: &str, name: &str, logger: Box<dyn Logger>) -> Self {
|
||||
LocalDocker {
|
||||
context,
|
||||
id: id.to_string(),
|
||||
name: name.to_string(),
|
||||
listeners: vec![],
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,9 +68,14 @@ impl LocalDocker {
|
||||
match fs::read(dockerfile_path) {
|
||||
Ok(bytes) => Ok(bytes),
|
||||
Err(err) => {
|
||||
let error_msg = format!("Can't read Dockerfile '{}'", dockerfile_path);
|
||||
error!("{}, error: {:?}", error_msg, err);
|
||||
Err(self.engine_error(EngineErrorCause::Internal, error_msg))
|
||||
let engine_error = EngineError::new_docker_cannot_read_dockerfile(
|
||||
self.get_event_details(),
|
||||
dockerfile_path.to_string(),
|
||||
CommandError::new(err.to_string(), None),
|
||||
);
|
||||
self.logger
|
||||
.log(LogLevel::Error, EngineEvent::Error(engine_error.clone(), None));
|
||||
Err(engine_error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,9 +111,14 @@ impl LocalDocker {
|
||||
let env_var_args = match docker::match_used_env_var_args(env_var_args, dockerfile_content) {
|
||||
Ok(env_var_args) => env_var_args,
|
||||
Err(err) => {
|
||||
let error_msg = format!("Can't extract env vars from Dockerfile '{}'", dockerfile_complete_path);
|
||||
error!("{}, error: {:?}", error_msg, err);
|
||||
return Err(self.engine_error(EngineErrorCause::Internal, error_msg));
|
||||
let engine_error = EngineError::new_docker_cannot_extract_env_vars_from_dockerfile(
|
||||
self.get_event_details(),
|
||||
dockerfile_complete_path.to_string(),
|
||||
CommandError::new(err.to_string(), None),
|
||||
);
|
||||
self.logger
|
||||
.log(LogLevel::Error, EngineEvent::Error(engine_error.clone(), None));
|
||||
return Err(engine_error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,7 +144,10 @@ impl LocalDocker {
|
||||
let exit_status = cmd.exec_with_abort(
|
||||
Duration::minutes(BUILD_DURATION_TIMEOUT_MIN),
|
||||
|line| {
|
||||
info!("{}", line);
|
||||
self.logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(self.get_event_details(), EventMessage::new_from_safe(line.to_string())),
|
||||
);
|
||||
|
||||
lh.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Application {
|
||||
@@ -142,7 +159,10 @@ impl LocalDocker {
|
||||
));
|
||||
},
|
||||
|line| {
|
||||
error!("{}", line);
|
||||
self.logger.log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(self.get_event_details(), EventMessage::new_from_safe(line.to_string())),
|
||||
);
|
||||
|
||||
lh.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Application {
|
||||
@@ -158,18 +178,10 @@ impl LocalDocker {
|
||||
|
||||
match exit_status {
|
||||
Ok(_) => Ok(BuildResult { build }),
|
||||
Err(CommandError::Killed(msg)) => Err(
|
||||
self.engine_error(EngineErrorCause::Canceled, msg)
|
||||
),
|
||||
Err(err) => Err(self.engine_error(
|
||||
EngineErrorCause::User(
|
||||
"It looks like there is something wrong in your Dockerfile. Try building the application locally with `docker build --no-cache`.",
|
||||
),
|
||||
format!(
|
||||
"error while building container image {}. Error: {:?}",
|
||||
self.name_with_id(),
|
||||
err
|
||||
),
|
||||
Err(err) => Err(EngineError::new_docker_cannot_build_container_image(
|
||||
self.get_event_details(),
|
||||
self.name_with_id(),
|
||||
CommandError::new(format!("{:?}", err), None),
|
||||
)),
|
||||
}
|
||||
}
|
||||
@@ -187,7 +199,8 @@ impl LocalDocker {
|
||||
|
||||
let args = self.context.docker_build_options();
|
||||
|
||||
let mut exit_status: Result<(), CommandError> = Ok(());
|
||||
let mut exit_status: Result<(), CommandError> =
|
||||
Err(CommandError::new_from_safe_message("No builder names".to_string()));
|
||||
|
||||
for builder_name in BUILDPACKS_BUILDERS.iter() {
|
||||
let mut buildpacks_args = if !use_build_cache {
|
||||
@@ -250,12 +263,13 @@ impl LocalDocker {
|
||||
self.context.execution_id(),
|
||||
));
|
||||
|
||||
let err = EngineError::new(
|
||||
EngineErrorCause::Internal,
|
||||
EngineErrorScope::Engine,
|
||||
self.context.execution_id().to_string(),
|
||||
Some(msg),
|
||||
let err = EngineError::new_buildpack_invalid_language_format(
|
||||
self.get_event_details(),
|
||||
buildpacks_language.to_string(),
|
||||
);
|
||||
|
||||
self.logger.log(LogLevel::Error, EngineEvent::Error(err.clone(), None));
|
||||
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
@@ -273,34 +287,45 @@ impl LocalDocker {
|
||||
|
||||
// buildpacks build
|
||||
let mut cmd = QoveryCommand::new("pack", &buildpacks_args, &self.get_docker_host_envs());
|
||||
exit_status = cmd.exec_with_abort(
|
||||
Duration::minutes(BUILD_DURATION_TIMEOUT_MIN),
|
||||
|line| {
|
||||
info!("{}", line);
|
||||
exit_status = cmd
|
||||
.exec_with_abort(
|
||||
Duration::minutes(BUILD_DURATION_TIMEOUT_MIN),
|
||||
|line| {
|
||||
self.logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(self.get_event_details(), EventMessage::new_from_safe(line.to_string())),
|
||||
);
|
||||
|
||||
lh.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Application {
|
||||
id: build.image.application_id.clone(),
|
||||
},
|
||||
ProgressLevel::Info,
|
||||
Some(line),
|
||||
self.context.execution_id(),
|
||||
));
|
||||
},
|
||||
|line| {
|
||||
error!("{}", line);
|
||||
lh.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Application {
|
||||
id: build.image.application_id.clone(),
|
||||
},
|
||||
ProgressLevel::Info,
|
||||
Some(line),
|
||||
self.context.execution_id(),
|
||||
));
|
||||
},
|
||||
|line| {
|
||||
self.logger.log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
self.get_event_details(),
|
||||
EventMessage::new_from_safe(line.to_string()),
|
||||
),
|
||||
);
|
||||
|
||||
lh.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Application {
|
||||
id: build.image.application_id.clone(),
|
||||
},
|
||||
ProgressLevel::Warn,
|
||||
Some(line),
|
||||
self.context.execution_id(),
|
||||
));
|
||||
},
|
||||
is_task_canceled,
|
||||
);
|
||||
lh.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Application {
|
||||
id: build.image.application_id.clone(),
|
||||
},
|
||||
ProgressLevel::Warn,
|
||||
Some(line),
|
||||
self.context.execution_id(),
|
||||
));
|
||||
},
|
||||
is_task_canceled,
|
||||
)
|
||||
.map_err(|err| CommandError::new(format!("{:?}", err), None));
|
||||
|
||||
if exit_status.is_ok() {
|
||||
// quit now if the builder successfully build the app
|
||||
@@ -310,21 +335,18 @@ impl LocalDocker {
|
||||
|
||||
match exit_status {
|
||||
Ok(_) => Ok(BuildResult { build }),
|
||||
Err(CommandError::Killed(msg)) => Err(self.engine_error(EngineErrorCause::Canceled, msg)),
|
||||
Err(err) => {
|
||||
warn!("{:?}", err);
|
||||
let error = EngineError::new_buildpack_cannot_build_container_image(
|
||||
self.get_event_details(),
|
||||
self.name_with_id(),
|
||||
BUILDPACKS_BUILDERS.iter().map(|b| b.to_string()).collect(),
|
||||
CommandError::new(format!("{:?}", err), None),
|
||||
);
|
||||
|
||||
Err(self.engine_error(
|
||||
EngineErrorCause::User(
|
||||
"None builders supports Your application can't be built without providing a Dockerfile",
|
||||
),
|
||||
format!(
|
||||
"Qovery can't build your container image {} with one of the following builders: {}. \
|
||||
Please do provide a valid Dockerfile to build your application or contact the support.",
|
||||
self.name_with_id(),
|
||||
BUILDPACKS_BUILDERS.join(", ")
|
||||
),
|
||||
))
|
||||
self.logger
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -335,7 +357,12 @@ impl LocalDocker {
|
||||
self.context.execution_id(),
|
||||
format!("build/{}", build.image.name.as_str()),
|
||||
)
|
||||
.map_err(|err| self.engine_error(EngineErrorCause::Internal, err.to_string()))
|
||||
.map_err(|err| {
|
||||
EngineError::new_cannot_get_workspace_directory(
|
||||
self.get_event_details(),
|
||||
CommandError::new(err.to_string(), None),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,11 +385,17 @@ impl BuildPlatform for LocalDocker {
|
||||
|
||||
fn is_valid(&self) -> Result<(), EngineError> {
|
||||
if !crate::cmd::command::does_binary_exist("docker") {
|
||||
return Err(self.engine_error(EngineErrorCause::Internal, String::from("docker binary not found")));
|
||||
return Err(EngineError::new_missing_required_binary(
|
||||
self.get_event_details(),
|
||||
"docker".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if !crate::cmd::command::does_binary_exist("pack") {
|
||||
return Err(self.engine_error(EngineErrorCause::Internal, String::from("pack binary not found")));
|
||||
return Err(EngineError::new_missing_required_binary(
|
||||
self.get_event_details(),
|
||||
"pack".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -374,9 +407,9 @@ impl BuildPlatform for LocalDocker {
|
||||
// Check if a local cache layers for the container image exists.
|
||||
let repository_root_path = self.get_repository_build_root_path(&build)?;
|
||||
|
||||
let parent_build = build
|
||||
.to_previous_build(repository_root_path)
|
||||
.map_err(|err| self.engine_error(EngineErrorCause::Internal, err.to_string()))?;
|
||||
let parent_build = build.to_previous_build(repository_root_path).map_err(|err| {
|
||||
EngineError::new_builder_get_build_error(self.get_event_details(), build.image.commit_id.to_string(), err)
|
||||
})?;
|
||||
|
||||
let parent_build = match parent_build {
|
||||
Some(parent_build) => parent_build,
|
||||
@@ -402,20 +435,32 @@ impl BuildPlatform for LocalDocker {
|
||||
force_build: bool,
|
||||
is_task_canceled: &dyn Fn() -> bool,
|
||||
) -> Result<BuildResult, EngineError> {
|
||||
info!("LocalDocker.build() called for {}", self.name());
|
||||
let event_details = self.get_event_details();
|
||||
|
||||
self.logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe("LocalDocker.build() called".to_string()),
|
||||
),
|
||||
);
|
||||
|
||||
if is_task_canceled() {
|
||||
return Err(self.engine_error(
|
||||
EngineErrorCause::Canceled,
|
||||
"Notified to cancel current task".to_string(),
|
||||
));
|
||||
return Err(EngineError::new_task_cancellation_requested(event_details.clone()));
|
||||
}
|
||||
|
||||
let listeners_helper = ListenersHelper::new(&self.listeners);
|
||||
|
||||
if !force_build && self.image_does_exist(&build.image)? {
|
||||
info!(
|
||||
"image {:?} found on repository, container build is not required",
|
||||
build.image
|
||||
self.logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"Image `{}` found on repository, container build is not required",
|
||||
build.image.name_with_tag()
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
return Ok(BuildResult { build });
|
||||
@@ -423,9 +468,15 @@ impl BuildPlatform for LocalDocker {
|
||||
|
||||
let repository_root_path = self.get_repository_build_root_path(&build)?;
|
||||
|
||||
info!(
|
||||
"cloning repository: {} to {}",
|
||||
build.git_repository.url, repository_root_path
|
||||
self.logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"Cloning repository: {} to {}",
|
||||
build.git_repository.url, repository_root_path
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
let get_credentials = |user: &str| {
|
||||
@@ -456,10 +507,7 @@ impl BuildPlatform for LocalDocker {
|
||||
|
||||
// git clone
|
||||
if is_task_canceled() {
|
||||
return Err(self.engine_error(
|
||||
EngineErrorCause::Canceled,
|
||||
"Notified to cancel current task".to_string(),
|
||||
));
|
||||
return Err(EngineError::new_task_cancellation_requested(event_details.clone()));
|
||||
}
|
||||
if let Err(clone_error) = git::clone_at_commit(
|
||||
&build.git_repository.url,
|
||||
@@ -467,12 +515,16 @@ impl BuildPlatform for LocalDocker {
|
||||
&repository_root_path,
|
||||
&get_credentials,
|
||||
) {
|
||||
let message = format!(
|
||||
"Error while cloning repository {}. Error: {:?}",
|
||||
&build.git_repository.url, clone_error
|
||||
let error = EngineError::new_builder_clone_repository_error(
|
||||
self.get_event_details(),
|
||||
build.git_repository.url.to_string(),
|
||||
CommandError::new(clone_error.to_string(), None),
|
||||
);
|
||||
error!("{}", message);
|
||||
return Err(self.engine_error(EngineErrorCause::Internal, message));
|
||||
|
||||
self.logger
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
let mut disable_build_cache = false;
|
||||
@@ -491,7 +543,15 @@ impl BuildPlatform for LocalDocker {
|
||||
// ensure docker_path is a mounted volume, otherwise ignore because it's not what Qovery does in production
|
||||
// ex: this cause regular cleanup on CI, leading to random tests errors
|
||||
match env::var_os("CI") {
|
||||
Some(_) => info!("CI environment variable found, no docker prune will be made"),
|
||||
Some(_) => self.logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(
|
||||
"CI environment variable found, no docker prune will be made".to_string(),
|
||||
),
|
||||
),
|
||||
),
|
||||
None => {
|
||||
// ensure there is enough disk space left before building a new image
|
||||
let docker_path_string = "/var/lib/docker";
|
||||
@@ -503,9 +563,20 @@ impl BuildPlatform for LocalDocker {
|
||||
|
||||
for disk in system.get_disks() {
|
||||
if disk.get_mount_point() == docker_path {
|
||||
match check_docker_space_usage_and_clean(disk, self.get_docker_host_envs()) {
|
||||
Ok(msg) => info!("{:?}", msg),
|
||||
Err(e) => error!("{:?}", e.message),
|
||||
let event_details = self.get_event_details();
|
||||
if let Err(e) = check_docker_space_usage_and_clean(
|
||||
disk,
|
||||
self.get_docker_host_envs(),
|
||||
event_details.clone(),
|
||||
&*self.logger(),
|
||||
) {
|
||||
self.logger.log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new(e.message_raw(), e.message_safe()),
|
||||
),
|
||||
);
|
||||
}
|
||||
break;
|
||||
};
|
||||
@@ -530,7 +601,6 @@ impl BuildPlatform for LocalDocker {
|
||||
|
||||
// If the dockerfile does not exist, abort
|
||||
if !Path::new(dockerfile_absolute_path.as_str()).exists() {
|
||||
warn!("Dockerfile not found under {}", dockerfile_absolute_path);
|
||||
listeners_helper.error(ProgressInfo::new(
|
||||
ProgressScope::Application {
|
||||
id: build.image.application_id.clone(),
|
||||
@@ -543,14 +613,13 @@ impl BuildPlatform for LocalDocker {
|
||||
self.context.execution_id(),
|
||||
));
|
||||
|
||||
return Err(self.engine_error(
|
||||
EngineErrorCause::User("Dockerfile not found at location"),
|
||||
format!(
|
||||
"Your Dockerfile is not present at the specified location {}/{}",
|
||||
build.git_repository.root_path.as_str(),
|
||||
build.git_repository.dockerfile_path.unwrap_or_default().as_str()
|
||||
),
|
||||
));
|
||||
let error =
|
||||
EngineError::new_docker_cannot_find_dockerfile(self.get_event_details(), dockerfile_absolute_path);
|
||||
|
||||
self.logger
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
self.build_image_with_docker(
|
||||
@@ -576,14 +645,14 @@ impl BuildPlatform for LocalDocker {
|
||||
|
||||
let msg = match &result {
|
||||
Ok(_) => format!("✅ Container {} is built", self.name_with_id()),
|
||||
Err(engine_err) if engine_err.is_cancel() => {
|
||||
Err(engine_err) if engine_err.tag() == &Tag::TaskCancellationRequested => {
|
||||
format!("🚫 Container {} build has been canceled", self.name_with_id())
|
||||
}
|
||||
Err(engine_err) => {
|
||||
format!(
|
||||
"❌ Container {} failed to be build: {}",
|
||||
self.name_with_id(),
|
||||
engine_err.message.as_ref().map(|x| x.as_str()).unwrap_or_default()
|
||||
engine_err.message()
|
||||
)
|
||||
}
|
||||
};
|
||||
@@ -591,15 +660,27 @@ impl BuildPlatform for LocalDocker {
|
||||
listeners_helper.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Application { id: app_id },
|
||||
ProgressLevel::Info,
|
||||
Some(msg),
|
||||
Some(msg.to_string()),
|
||||
self.context.execution_id(),
|
||||
));
|
||||
|
||||
self.logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(event_details.clone(), EventMessage::new_from_safe(msg.to_string())),
|
||||
);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn build_error(&self, build: Build) -> Result<BuildResult, EngineError> {
|
||||
warn!("LocalDocker.build_error() called for {}", self.name());
|
||||
let event_details = self.get_event_details();
|
||||
self.logger.log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!("LocalDocker.build_error() called for {}", self.name())),
|
||||
),
|
||||
);
|
||||
|
||||
let listener_helper = ListenersHelper::new(&self.listeners);
|
||||
|
||||
@@ -615,8 +696,16 @@ impl BuildPlatform for LocalDocker {
|
||||
self.context.execution_id(),
|
||||
));
|
||||
|
||||
let err = EngineError::new_not_implemented_error(event_details);
|
||||
|
||||
self.logger.log(LogLevel::Error, EngineEvent::Error(err.clone(), None));
|
||||
|
||||
// FIXME
|
||||
Err(self.engine_error(EngineErrorCause::Internal, message))
|
||||
Err(err)
|
||||
}
|
||||
|
||||
fn logger(&self) -> Box<dyn Logger> {
|
||||
self.logger.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,38 +719,54 @@ impl Listen for LocalDocker {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTransmitter for LocalDocker {
|
||||
fn to_transmitter(&self) -> Transmitter {
|
||||
Transmitter::BuildPlatform(self.id().to_string(), self.name().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_docker_space_usage_and_clean(
|
||||
docker_path_size_info: &Disk,
|
||||
envs: Vec<(&str, &str)>,
|
||||
) -> Result<String, SimpleError> {
|
||||
event_details: EventDetails,
|
||||
logger: &dyn Logger,
|
||||
) -> Result<(), CommandError> {
|
||||
let docker_max_disk_percentage_usage_before_purge = 60; // arbitrary percentage that should make the job anytime
|
||||
let available_space = docker_path_size_info.get_available_space();
|
||||
let docker_percentage_remaining = available_space * 100 / docker_path_size_info.get_total_space();
|
||||
|
||||
if docker_percentage_remaining < docker_max_disk_percentage_usage_before_purge || available_space == 0 {
|
||||
warn!(
|
||||
"Docker disk remaining ({}%) is lower than {}%, requesting cleaning (purge)",
|
||||
docker_percentage_remaining, docker_max_disk_percentage_usage_before_purge
|
||||
logger.log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"Docker disk remaining ({}%) is lower than {}%, requesting cleaning (purge)",
|
||||
docker_percentage_remaining, docker_max_disk_percentage_usage_before_purge
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
return match docker_prune_images(envs) {
|
||||
Err(e) => {
|
||||
error!("error while purging docker images: {:?}", e.message);
|
||||
Err(e)
|
||||
}
|
||||
_ => Ok("docker images have been purged".to_string()),
|
||||
};
|
||||
return docker_prune_images(envs);
|
||||
};
|
||||
|
||||
Ok(format!(
|
||||
"no need to purge old docker images, only {}% ({}/{}) disk used",
|
||||
100 - docker_percentage_remaining,
|
||||
docker_path_size_info.get_available_space(),
|
||||
docker_path_size_info.get_total_space(),
|
||||
))
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"No need to purge old docker images, only {}% ({}/{}) disk used",
|
||||
100 - docker_percentage_remaining,
|
||||
docker_path_size_info.get_available_space(),
|
||||
docker_path_size_info.get_total_space(),
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn docker_prune_images(envs: Vec<(&str, &str)>) -> Result<(), SimpleError> {
|
||||
fn docker_prune_images(envs: Vec<(&str, &str)>) -> Result<(), CommandError> {
|
||||
let all_prunes_commands = vec![
|
||||
vec!["container", "prune", "-f"],
|
||||
vec!["image", "prune", "-a", "-f"],
|
||||
@@ -669,20 +774,19 @@ fn docker_prune_images(envs: Vec<(&str, &str)>) -> Result<(), SimpleError> {
|
||||
vec!["volume", "prune", "-f"],
|
||||
];
|
||||
|
||||
let mut errored_commands = vec![];
|
||||
for prune in all_prunes_commands {
|
||||
let mut cmd = QoveryCommand::new("docker", &prune, &envs);
|
||||
match cmd.exec_with_timeout(
|
||||
Duration::minutes(BUILD_DURATION_TIMEOUT_MIN),
|
||||
|line| {
|
||||
debug!("{}", line);
|
||||
},
|
||||
|line| {
|
||||
debug!("{}", line);
|
||||
},
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(e) => error!("error while puring {}. {:?}", prune[0], e),
|
||||
};
|
||||
if let Err(e) = cmd.exec_with_timeout(Duration::minutes(BUILD_DURATION_TIMEOUT_MIN), |_| {}, |_| {}) {
|
||||
errored_commands.push(format!("{} {:?}", prune[0], e));
|
||||
}
|
||||
}
|
||||
|
||||
if errored_commands.len() > 0 {
|
||||
return Err(CommandError::new(
|
||||
errored_commands.join("/ "),
|
||||
Some("Error while trying to prune images.".to_string()),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope};
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter};
|
||||
use crate::git;
|
||||
use crate::models::{Context, Listen};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::{Context, Listen, QoveryIdentifier};
|
||||
use crate::utilities::get_image_tag;
|
||||
use git2::{Cred, CredentialType, Error};
|
||||
use git2::{Cred, CredentialType};
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
use std::path::Path;
|
||||
|
||||
pub mod docker;
|
||||
pub mod local_docker;
|
||||
|
||||
pub trait BuildPlatform: Listen {
|
||||
pub trait BuildPlatform: ToTransmitter + Listen {
|
||||
fn context(&self) -> &Context;
|
||||
fn kind(&self) -> Kind;
|
||||
fn id(&self) -> &str;
|
||||
@@ -29,15 +31,17 @@ pub trait BuildPlatform: Listen {
|
||||
is_task_canceled: &dyn Fn() -> bool,
|
||||
) -> Result<BuildResult, EngineError>;
|
||||
fn build_error(&self, build: Build) -> Result<BuildResult, EngineError>;
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::BuildPlatform(self.id().to_string(), self.name().to_string())
|
||||
}
|
||||
fn engine_error(&self, cause: EngineErrorCause, message: String) -> EngineError {
|
||||
EngineError::new(
|
||||
cause,
|
||||
self.engine_error_scope(),
|
||||
self.context().execution_id(),
|
||||
Some(message),
|
||||
fn logger(&self) -> Box<dyn Logger>;
|
||||
fn get_event_details(&self) -> EventDetails {
|
||||
let context = self.context();
|
||||
EventDetails::new(
|
||||
None,
|
||||
QoveryIdentifier::from(context.organization_id().to_string()),
|
||||
QoveryIdentifier::from(context.cluster_id().to_string()),
|
||||
QoveryIdentifier::from(context.execution_id().to_string()),
|
||||
None,
|
||||
Stage::Environment(EnvironmentStep::Build),
|
||||
self.to_transmitter(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -49,7 +53,7 @@ pub struct Build {
|
||||
}
|
||||
|
||||
impl Build {
|
||||
pub fn to_previous_build<P>(&self, clone_repo_into_dir: P) -> Result<Option<Build>, Error>
|
||||
pub fn to_previous_build<P>(&self, clone_repo_into_dir: P) -> Result<Option<Build>, CommandError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
@@ -64,7 +68,8 @@ impl Build {
|
||||
Cred::userpass_plaintext(creds.login.as_str(), creds.password.as_str()).unwrap(),
|
||||
)],
|
||||
},
|
||||
)?;
|
||||
)
|
||||
.map_err(|err| CommandError::new(err.to_string(), Some("Cannot get parent commit ID.".to_string())))?;
|
||||
|
||||
let parent_commit_id = match parent_commit_id {
|
||||
None => return Ok(None),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use tera::Context as TeraContext;
|
||||
|
||||
use crate::build_platform::Image;
|
||||
use crate::cloud_provider::kubernetes::validate_k8s_required_cpu_and_burstable;
|
||||
use crate::cloud_provider::models::{
|
||||
EnvironmentVariable, EnvironmentVariableDataTemplate, Storage, StorageDataTemplate,
|
||||
};
|
||||
@@ -9,13 +10,13 @@ use crate::cloud_provider::service::{
|
||||
scale_down_application, send_progress_on_long_task, Action, Application as CApplication, Create, Delete, Helm,
|
||||
Pause, Service, ServiceType, StatelessService,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{print_action, sanitize_name, validate_k8s_required_cpu_and_burstable};
|
||||
use crate::cloud_provider::utilities::{print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl::ScalingKind::{Deployment, Statefulset};
|
||||
use crate::error::EngineErrorCause::Internal;
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EngineEvent, EnvironmentStep, EventMessage, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::{LogLevel, Logger};
|
||||
use crate::models::{Context, Listen, Listener, Listeners, ListenersHelper, Port};
|
||||
use ::function_name::named;
|
||||
|
||||
@@ -35,6 +36,7 @@ pub struct Application {
|
||||
storage: Vec<Storage<StorageType>>,
|
||||
environment_variables: Vec<EnvironmentVariable>,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
@@ -54,6 +56,7 @@ impl Application {
|
||||
storage: Vec<Storage<StorageType>>,
|
||||
environment_variables: Vec<EnvironmentVariable>,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Application {
|
||||
context,
|
||||
@@ -71,6 +74,7 @@ impl Application {
|
||||
storage,
|
||||
environment_variables,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +196,7 @@ impl Service for Application {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let mut context = default_tera_context(self, target.kubernetes, target.environment);
|
||||
let commit_id = self.image().commit_id.as_str();
|
||||
|
||||
@@ -201,10 +206,18 @@ impl Service for Application {
|
||||
Some(registry_url) => context.insert("image_name_with_tag", registry_url.as_str()),
|
||||
None => {
|
||||
let image_name_with_tag = self.image().name_with_tag();
|
||||
warn!(
|
||||
"there is no registry url, use image name with tag with the default container registry: {}",
|
||||
image_name_with_tag.as_str()
|
||||
|
||||
self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"there is no registry url, use image name with tag with the default container registry: {}",
|
||||
image_name_with_tag.as_str()
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
context.insert("image_name_with_tag", image_name_with_tag.as_str());
|
||||
}
|
||||
}
|
||||
@@ -237,17 +250,20 @@ impl Service for Application {
|
||||
&self.id,
|
||||
self.total_cpus(),
|
||||
self.cpu_burst(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
) {
|
||||
Ok(l) => l,
|
||||
Err(e) => {
|
||||
return Err(EngineError::new(
|
||||
Internal,
|
||||
EngineErrorScope::Application(self.id().to_string(), self.name().to_string()),
|
||||
self.context.execution_id(),
|
||||
Some(e.to_string()),
|
||||
return Err(EngineError::new_k8s_validate_required_cpu_and_burstable_error(
|
||||
event_details.clone(),
|
||||
self.total_cpus(),
|
||||
self.cpu_burst(),
|
||||
e,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
context.insert("cpu_burst", &cpu_limits.cpu_limit);
|
||||
|
||||
let storage = self
|
||||
@@ -286,23 +302,26 @@ impl Service for Application {
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("appId={}", self.id))
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Application(self.id().to_string(), self.name().to_string())
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("appId={}", self.id))
|
||||
}
|
||||
}
|
||||
|
||||
impl Create for Application {
|
||||
#[named]
|
||||
fn on_create(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
deploy_user_stateless_service(target, self)
|
||||
@@ -315,11 +334,14 @@ impl Create for Application {
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
@@ -331,11 +353,14 @@ impl Create for Application {
|
||||
impl Pause for Application {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -354,11 +379,14 @@ impl Pause for Application {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -374,6 +402,8 @@ impl Delete for Application {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
@@ -393,6 +423,8 @@ impl Delete for Application {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
|
||||
@@ -6,7 +6,7 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{
|
||||
generate_supported_version, get_self_hosted_mongodb_version, get_supported_version_to_use, print_action,
|
||||
@@ -14,8 +14,9 @@ use crate::cloud_provider::utilities::{
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorScope, StringError};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
@@ -33,6 +34,7 @@ pub struct MongoDB {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl MongoDB {
|
||||
@@ -49,6 +51,7 @@ impl MongoDB {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
MongoDB {
|
||||
context,
|
||||
@@ -63,11 +66,21 @@ impl MongoDB {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self, is_managed_services: bool) -> Result<String, EngineError> {
|
||||
check_service_version(get_mongodb_version(self.version(), is_managed_services), self)
|
||||
fn matching_correct_version(
|
||||
&self,
|
||||
is_managed_services: bool,
|
||||
event_details: EventDetails,
|
||||
) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
get_mongodb_version(self.version(), is_managed_services),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn cloud_provider_name(&self) -> &str {
|
||||
@@ -155,17 +168,14 @@ impl Service for MongoDB {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, target.kubernetes, target.environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -176,7 +186,9 @@ impl Service for MongoDB {
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
|
||||
let version = self.matching_correct_version(self.is_managed_service())?;
|
||||
let version = self
|
||||
.matching_correct_version(self.is_managed_service(), event_details.clone())?
|
||||
.matched_version();
|
||||
context.insert("version", &version);
|
||||
|
||||
for (k, v) in kubernetes.cloud_provider().tera_context_environment_variables() {
|
||||
@@ -221,16 +233,12 @@ impl Service for MongoDB {
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,24 +295,35 @@ impl Create for MongoDB {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
deploy_stateful_service(target, self, event_details.clone())
|
||||
deploy_stateful_service(target, self, event_details.clone(), &*self.logger)
|
||||
})
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
self.check_domains(self.listeners.clone(), vec![self.fqdn.as_str()])
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
self.check_domains(
|
||||
self.listeners.clone(),
|
||||
vec![self.fqdn.as_str()],
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -313,11 +332,14 @@ impl Create for MongoDB {
|
||||
impl Pause for MongoDB {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -331,11 +353,14 @@ impl Pause for MongoDB {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -351,10 +376,12 @@ impl Delete for MongoDB {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
delete_stateful_service(target, self, event_details.clone())
|
||||
delete_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -364,11 +391,14 @@ impl Delete for MongoDB {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -384,7 +414,7 @@ impl Listen for MongoDB {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mongodb_version(requested_version: String, is_managed_service: bool) -> Result<String, StringError> {
|
||||
fn get_mongodb_version(requested_version: String, is_managed_service: bool) -> Result<String, CommandError> {
|
||||
if is_managed_service {
|
||||
get_managed_mongodb_version(requested_version)
|
||||
} else {
|
||||
@@ -392,7 +422,7 @@ fn get_mongodb_version(requested_version: String, is_managed_service: bool) -> R
|
||||
}
|
||||
}
|
||||
|
||||
fn get_managed_mongodb_version(requested_version: String) -> Result<String, StringError> {
|
||||
fn get_managed_mongodb_version(requested_version: String) -> Result<String, CommandError> {
|
||||
let mut supported_mongodb_versions = HashMap::new();
|
||||
|
||||
// v3.6.0
|
||||
@@ -410,6 +440,7 @@ fn get_managed_mongodb_version(requested_version: String) -> Result<String, Stri
|
||||
mod tests_mongodb {
|
||||
use crate::cloud_provider::aws::databases::mongodb::{get_mongodb_version, MongoDB};
|
||||
use crate::cloud_provider::service::{Action, DatabaseOptions, Service};
|
||||
use crate::logger::StdIoLogger;
|
||||
use crate::models::{Context, DatabaseMode};
|
||||
|
||||
#[test]
|
||||
@@ -418,14 +449,20 @@ mod tests_mongodb {
|
||||
assert_eq!(get_mongodb_version("4".to_string(), true).unwrap(), "4.0.0");
|
||||
assert_eq!(get_mongodb_version("4.0".to_string(), true).unwrap(), "4.0.0");
|
||||
assert_eq!(
|
||||
get_mongodb_version("4.4".to_string(), true).unwrap_err().as_str(),
|
||||
get_mongodb_version("4.4".to_string(), true)
|
||||
.unwrap_err()
|
||||
.message()
|
||||
.as_str(),
|
||||
"DocumentDB 4.4 version is not supported"
|
||||
);
|
||||
// self-hosted version
|
||||
assert_eq!(get_mongodb_version("4".to_string(), false).unwrap(), "4.4.4");
|
||||
assert_eq!(get_mongodb_version("4.2".to_string(), false).unwrap(), "4.2.12");
|
||||
assert_eq!(
|
||||
get_mongodb_version("3.4".to_string(), false).unwrap_err().as_str(),
|
||||
get_mongodb_version("3.4".to_string(), false)
|
||||
.unwrap_err()
|
||||
.message()
|
||||
.as_str(),
|
||||
"MongoDB 3.4 version is not supported"
|
||||
);
|
||||
}
|
||||
@@ -470,6 +507,7 @@ mod tests_mongodb {
|
||||
publicly_accessible: false,
|
||||
},
|
||||
vec![],
|
||||
Box::new(StdIoLogger::new()),
|
||||
);
|
||||
assert_eq!(database.sanitized_name(), db_expected_name);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::cloud_provider::aws::databases::utilities::{aws_final_snapshot_name,
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{
|
||||
generate_supported_version, get_self_hosted_mysql_version, get_supported_version_to_use, managed_db_name_sanitizer,
|
||||
@@ -15,8 +15,9 @@ use crate::cloud_provider::utilities::{
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope, StringError};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, DatabaseKind, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
@@ -34,6 +35,7 @@ pub struct MySQL {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl MySQL {
|
||||
@@ -50,6 +52,7 @@ impl MySQL {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Self {
|
||||
context,
|
||||
@@ -64,11 +67,21 @@ impl MySQL {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self, is_managed_services: bool) -> Result<String, EngineError> {
|
||||
check_service_version(get_mysql_version(self.version(), is_managed_services), self)
|
||||
fn matching_correct_version(
|
||||
&self,
|
||||
is_managed_services: bool,
|
||||
event_details: EventDetails,
|
||||
) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
get_mysql_version(self.version(), is_managed_services),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn cloud_provider_name(&self) -> &str {
|
||||
@@ -161,17 +174,13 @@ impl Service for MySQL {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -182,21 +191,23 @@ impl Service for MySQL {
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
|
||||
let version = &self.matching_correct_version(self.is_managed_service())?;
|
||||
context.insert("version", &version);
|
||||
let version = &self.matching_correct_version(self.is_managed_service(), event_details.clone())?;
|
||||
context.insert("version", &version.matched_version());
|
||||
|
||||
if self.is_managed_service() {
|
||||
let parameter_group_family = match get_parameter_group_from_version(&version, DatabaseKind::Mysql) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(EngineError {
|
||||
cause: EngineErrorCause::Internal,
|
||||
scope: EngineErrorScope::Engine,
|
||||
execution_id: (&self.context.execution_id()).to_string(),
|
||||
message: Some(e),
|
||||
})
|
||||
}
|
||||
};
|
||||
let parameter_group_family =
|
||||
match get_parameter_group_from_version(version.matched_version(), DatabaseKind::Mysql) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(EngineError::new_terraform_unsupported_context_parameter_value(
|
||||
event_details.clone(),
|
||||
"MySQL".to_string(),
|
||||
"parameter_group_family".to_string(),
|
||||
version.matched_version().to_string(),
|
||||
Some(e),
|
||||
))
|
||||
}
|
||||
};
|
||||
context.insert("parameter_group_family", ¶meter_group_family);
|
||||
};
|
||||
|
||||
@@ -242,16 +253,12 @@ impl Service for MySQL {
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,24 +305,35 @@ impl Create for MySQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
deploy_stateful_service(target, self, event_details.clone())
|
||||
deploy_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
self.check_domains(self.listeners.clone(), vec![self.fqdn.as_str()])
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
self.check_domains(
|
||||
self.listeners.clone(),
|
||||
vec![self.fqdn.as_str()],
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -325,11 +343,14 @@ impl Create for MySQL {
|
||||
impl Pause for MySQL {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -343,11 +364,14 @@ impl Pause for MySQL {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -362,10 +386,12 @@ impl Delete for MySQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
delete_stateful_service(target, self, event_details.clone())
|
||||
delete_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -375,11 +401,14 @@ impl Delete for MySQL {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -395,7 +424,7 @@ impl Listen for MySQL {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mysql_version(requested_version: String, is_managed_service: bool) -> Result<String, StringError> {
|
||||
fn get_mysql_version(requested_version: String, is_managed_service: bool) -> Result<String, CommandError> {
|
||||
if is_managed_service {
|
||||
get_managed_mysql_version(requested_version)
|
||||
} else {
|
||||
@@ -403,7 +432,7 @@ fn get_mysql_version(requested_version: String, is_managed_service: bool) -> Res
|
||||
}
|
||||
}
|
||||
|
||||
fn get_managed_mysql_version(requested_version: String) -> Result<String, StringError> {
|
||||
fn get_managed_mysql_version(requested_version: String) -> Result<String, CommandError> {
|
||||
let mut supported_mysql_versions = HashMap::new();
|
||||
// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_MySQL.html#MySQL.Concepts.VersionMgmt
|
||||
|
||||
@@ -432,6 +461,7 @@ fn get_managed_mysql_version(requested_version: String) -> Result<String, String
|
||||
mod tests_mysql {
|
||||
use crate::cloud_provider::aws::databases::mysql::{get_mysql_version, MySQL};
|
||||
use crate::cloud_provider::service::{Action, DatabaseOptions, Service};
|
||||
use crate::logger::StdIoLogger;
|
||||
use crate::models::{Context, DatabaseMode};
|
||||
|
||||
#[test]
|
||||
@@ -441,7 +471,10 @@ mod tests_mysql {
|
||||
assert_eq!(get_mysql_version("8.0".to_string(), true).unwrap(), "8.0.26");
|
||||
assert_eq!(get_mysql_version("8.0.16".to_string(), true).unwrap(), "8.0.16");
|
||||
assert_eq!(
|
||||
get_mysql_version("8.0.18".to_string(), true).unwrap_err().as_str(),
|
||||
get_mysql_version("8.0.18".to_string(), true)
|
||||
.unwrap_err()
|
||||
.message()
|
||||
.as_str(),
|
||||
"RDS MySQL 8.0.18 version is not supported"
|
||||
);
|
||||
// self-hosted version
|
||||
@@ -449,7 +482,10 @@ mod tests_mysql {
|
||||
assert_eq!(get_mysql_version("5.7".to_string(), false).unwrap(), "5.7.34");
|
||||
assert_eq!(get_mysql_version("5.7.31".to_string(), false).unwrap(), "5.7.31");
|
||||
assert_eq!(
|
||||
get_mysql_version("1.0".to_string(), false).unwrap_err().as_str(),
|
||||
get_mysql_version("1.0".to_string(), false)
|
||||
.unwrap_err()
|
||||
.message()
|
||||
.as_str(),
|
||||
"MySQL 1.0 version is not supported"
|
||||
);
|
||||
}
|
||||
@@ -494,6 +530,7 @@ mod tests_mysql {
|
||||
publicly_accessible: false,
|
||||
},
|
||||
vec![],
|
||||
Box::new(StdIoLogger::new()),
|
||||
);
|
||||
assert_eq!(database.sanitized_name(), db_expected_name);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{
|
||||
generate_supported_version, get_self_hosted_postgres_version, get_supported_version_to_use,
|
||||
@@ -15,8 +15,9 @@ use crate::cloud_provider::utilities::{
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorScope, StringError};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
@@ -34,6 +35,7 @@ pub struct PostgreSQL {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl PostgreSQL {
|
||||
@@ -50,6 +52,7 @@ impl PostgreSQL {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
PostgreSQL {
|
||||
context,
|
||||
@@ -64,11 +67,21 @@ impl PostgreSQL {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self, is_managed_services: bool) -> Result<String, EngineError> {
|
||||
check_service_version(get_postgres_version(self.version(), is_managed_services), self)
|
||||
fn matching_correct_version(
|
||||
&self,
|
||||
is_managed_services: bool,
|
||||
event_details: EventDetails,
|
||||
) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
get_postgres_version(self.version(), is_managed_services),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn cloud_provider_name(&self) -> &str {
|
||||
@@ -161,17 +174,13 @@ impl Service for PostgreSQL {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -182,7 +191,9 @@ impl Service for PostgreSQL {
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
|
||||
let version = self.matching_correct_version(self.is_managed_service())?;
|
||||
let version = self
|
||||
.matching_correct_version(self.is_managed_service(), event_details.clone())?
|
||||
.matched_version();
|
||||
context.insert("version", &version);
|
||||
|
||||
for (k, v) in kubernetes.cloud_provider().tera_context_environment_variables() {
|
||||
@@ -229,16 +240,12 @@ impl Service for PostgreSQL {
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,24 +292,35 @@ impl Create for PostgreSQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
deploy_stateful_service(target, self, event_details.clone())
|
||||
deploy_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
self.check_domains(self.listeners.clone(), vec![self.fqdn.as_str()])
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
self.check_domains(
|
||||
self.listeners.clone(),
|
||||
vec![self.fqdn.as_str()],
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -312,11 +330,14 @@ impl Create for PostgreSQL {
|
||||
impl Pause for PostgreSQL {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -330,11 +351,14 @@ impl Pause for PostgreSQL {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -350,10 +374,12 @@ impl Delete for PostgreSQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
delete_stateful_service(target, self, event_details.clone())
|
||||
delete_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -363,11 +389,14 @@ impl Delete for PostgreSQL {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -384,7 +413,7 @@ impl Listen for PostgreSQL {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_postgres_version(requested_version: String, is_managed_service: bool) -> Result<String, StringError> {
|
||||
fn get_postgres_version(requested_version: String, is_managed_service: bool) -> Result<String, CommandError> {
|
||||
if is_managed_service {
|
||||
get_managed_postgres_version(requested_version)
|
||||
} else {
|
||||
@@ -392,7 +421,7 @@ fn get_postgres_version(requested_version: String, is_managed_service: bool) ->
|
||||
}
|
||||
}
|
||||
|
||||
fn get_managed_postgres_version(requested_version: String) -> Result<String, StringError> {
|
||||
fn get_managed_postgres_version(requested_version: String) -> Result<String, CommandError> {
|
||||
let mut supported_postgres_versions = HashMap::new();
|
||||
|
||||
// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts
|
||||
@@ -423,6 +452,7 @@ fn get_managed_postgres_version(requested_version: String) -> Result<String, Str
|
||||
mod tests_postgres {
|
||||
use crate::cloud_provider::aws::databases::postgresql::{get_postgres_version, PostgreSQL};
|
||||
use crate::cloud_provider::service::{Action, DatabaseOptions, Service};
|
||||
use crate::logger::StdIoLogger;
|
||||
use crate::models::{Context, DatabaseMode};
|
||||
|
||||
#[test]
|
||||
@@ -431,11 +461,17 @@ mod tests_postgres {
|
||||
assert_eq!(get_postgres_version("12".to_string(), true).unwrap(), "12.8");
|
||||
assert_eq!(get_postgres_version("12.3".to_string(), true).unwrap(), "12.3");
|
||||
assert_eq!(
|
||||
get_postgres_version("12.3.0".to_string(), true).unwrap_err().as_str(),
|
||||
get_postgres_version("12.3.0".to_string(), true)
|
||||
.unwrap_err()
|
||||
.message()
|
||||
.as_str(),
|
||||
"Postgresql 12.3.0 version is not supported"
|
||||
);
|
||||
assert_eq!(
|
||||
get_postgres_version("11.3".to_string(), true).unwrap_err().as_str(),
|
||||
get_postgres_version("11.3".to_string(), true)
|
||||
.unwrap_err()
|
||||
.message()
|
||||
.as_str(),
|
||||
"Postgresql 11.3 version is not supported"
|
||||
);
|
||||
// self-hosted version
|
||||
@@ -443,7 +479,10 @@ mod tests_postgres {
|
||||
assert_eq!(get_postgres_version("12.8".to_string(), false).unwrap(), "12.8.0");
|
||||
assert_eq!(get_postgres_version("12.3.0".to_string(), false).unwrap(), "12.3.0");
|
||||
assert_eq!(
|
||||
get_postgres_version("1.0".to_string(), false).unwrap_err().as_str(),
|
||||
get_postgres_version("1.0".to_string(), false)
|
||||
.unwrap_err()
|
||||
.message()
|
||||
.as_str(),
|
||||
"Postgresql 1.0 version is not supported"
|
||||
);
|
||||
}
|
||||
@@ -488,6 +527,7 @@ mod tests_postgres {
|
||||
publicly_accessible: false,
|
||||
},
|
||||
vec![],
|
||||
Box::new(StdIoLogger::new()),
|
||||
);
|
||||
assert_eq!(database.sanitized_name(), db_expected_name);
|
||||
}
|
||||
|
||||
@@ -6,14 +6,15 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{get_self_hosted_redis_version, get_supported_version_to_use, print_action};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope, StringError};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
@@ -31,6 +32,7 @@ pub struct Redis {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl Redis {
|
||||
@@ -47,6 +49,7 @@ impl Redis {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Self {
|
||||
context,
|
||||
@@ -61,11 +64,21 @@ impl Redis {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self, is_managed_services: bool) -> Result<String, EngineError> {
|
||||
check_service_version(get_redis_version(self.version(), is_managed_services), self)
|
||||
fn matching_correct_version(
|
||||
&self,
|
||||
is_managed_services: bool,
|
||||
event_details: EventDetails,
|
||||
) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
get_redis_version(self.version(), is_managed_services),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn cloud_provider_name(&self) -> &str {
|
||||
@@ -164,17 +177,14 @@ impl Service for Redis {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -183,23 +193,29 @@ impl Service for Redis {
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
);
|
||||
|
||||
let version = self.matching_correct_version(self.is_managed_service())?;
|
||||
let version = self
|
||||
.matching_correct_version(self.is_managed_service(), event_details.clone())?
|
||||
.matched_version()
|
||||
.to_string();
|
||||
|
||||
let parameter_group_name = if version.starts_with("5.") {
|
||||
"default.redis5.0"
|
||||
} else if version.starts_with("6.") {
|
||||
"default.redis6.x"
|
||||
} else {
|
||||
return Err(self.engine_error(
|
||||
EngineErrorCause::Internal,
|
||||
"Elasticache parameter group name unknown".to_string(),
|
||||
return Err(EngineError::new_terraform_unsupported_context_parameter_value(
|
||||
event_details.clone(),
|
||||
"Elasicache".to_string(),
|
||||
"database_elasticache_parameter_group_name".to_string(),
|
||||
format!("default.redis{}", version),
|
||||
None,
|
||||
));
|
||||
};
|
||||
|
||||
context.insert("database_elasticache_parameter_group_name", parameter_group_name);
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
context.insert("version", &version);
|
||||
context.insert("version", version.as_str());
|
||||
|
||||
for (k, v) in kubernetes.cloud_provider().tera_context_environment_variables() {
|
||||
context.insert(k, v);
|
||||
@@ -241,16 +257,12 @@ impl Service for Redis {
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,24 +309,35 @@ impl Create for Redis {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
deploy_stateful_service(target, self, event_details.clone())
|
||||
deploy_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
self.check_domains(self.listeners.clone(), vec![self.fqdn.as_str()])
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
self.check_domains(
|
||||
self.listeners.clone(),
|
||||
vec![self.fqdn.as_str()],
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -323,11 +346,14 @@ impl Create for Redis {
|
||||
impl Pause for Redis {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -341,11 +367,14 @@ impl Pause for Redis {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -361,10 +390,12 @@ impl Delete for Redis {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
delete_stateful_service(target, self, event_details.clone())
|
||||
delete_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -374,11 +405,14 @@ impl Delete for Redis {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -394,7 +428,7 @@ impl Listen for Redis {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_redis_version(requested_version: String, is_managed_service: bool) -> Result<String, StringError> {
|
||||
fn get_redis_version(requested_version: String, is_managed_service: bool) -> Result<String, CommandError> {
|
||||
if is_managed_service {
|
||||
get_managed_redis_version(requested_version)
|
||||
} else {
|
||||
@@ -402,7 +436,7 @@ fn get_redis_version(requested_version: String, is_managed_service: bool) -> Res
|
||||
}
|
||||
}
|
||||
|
||||
fn get_managed_redis_version(requested_version: String) -> Result<String, StringError> {
|
||||
fn get_managed_redis_version(requested_version: String) -> Result<String, CommandError> {
|
||||
let mut supported_redis_versions = HashMap::with_capacity(2);
|
||||
// https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/supported-engine-versions.html
|
||||
|
||||
@@ -416,6 +450,7 @@ fn get_managed_redis_version(requested_version: String) -> Result<String, String
|
||||
mod tests {
|
||||
use crate::cloud_provider::aws::databases::redis::{get_redis_version, Redis};
|
||||
use crate::cloud_provider::service::{Action, DatabaseOptions, Service};
|
||||
use crate::logger::StdIoLogger;
|
||||
use crate::models::{Context, DatabaseMode};
|
||||
|
||||
#[test]
|
||||
@@ -424,7 +459,10 @@ mod tests {
|
||||
assert_eq!(get_redis_version("6".to_string(), true).unwrap(), "6.x");
|
||||
assert_eq!(get_redis_version("5".to_string(), true).unwrap(), "5.0.6");
|
||||
assert_eq!(
|
||||
get_redis_version("1.0".to_string(), true).unwrap_err().as_str(),
|
||||
get_redis_version("1.0".to_string(), true)
|
||||
.unwrap_err()
|
||||
.message()
|
||||
.as_str(),
|
||||
"Elasticache 1.0 version is not supported"
|
||||
);
|
||||
|
||||
@@ -432,7 +470,10 @@ mod tests {
|
||||
assert_eq!(get_redis_version("6".to_string(), false).unwrap(), "6.0.9");
|
||||
assert_eq!(get_redis_version("6.0".to_string(), false).unwrap(), "6.0.9");
|
||||
assert_eq!(
|
||||
get_redis_version("1.0".to_string(), false).unwrap_err().as_str(),
|
||||
get_redis_version("1.0".to_string(), false)
|
||||
.unwrap_err()
|
||||
.message()
|
||||
.as_str(),
|
||||
"Redis 1.0 version is not supported"
|
||||
);
|
||||
}
|
||||
@@ -477,6 +518,7 @@ mod tests {
|
||||
publicly_accessible: false,
|
||||
},
|
||||
vec![],
|
||||
Box::new(StdIoLogger::new()),
|
||||
);
|
||||
assert_eq!(database.sanitized_name(), db_expected_name);
|
||||
}
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
use crate::cloud_provider::utilities::VersionsNumber;
|
||||
use crate::error::StringError;
|
||||
use crate::errors::CommandError;
|
||||
use crate::models::DatabaseKind;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn get_parameter_group_from_version(version: &str, database_kind: DatabaseKind) -> Result<String, StringError> {
|
||||
let version_number = match VersionsNumber::from_str(version) {
|
||||
Ok(v) => {
|
||||
if v.minor.is_none() {
|
||||
return Err(format!(
|
||||
"Can't determine the minor version, to select parameter group for {:?} version {}",
|
||||
database_kind, version
|
||||
));
|
||||
};
|
||||
v
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
pub fn get_parameter_group_from_version(
|
||||
version: VersionsNumber,
|
||||
database_kind: DatabaseKind,
|
||||
) -> Result<String, CommandError> {
|
||||
if version.minor.is_none() {
|
||||
return Err(CommandError::new_from_safe_message(format!(
|
||||
"Can't determine the minor version, to select parameter group for {:?} version {}",
|
||||
database_kind, version
|
||||
)));
|
||||
};
|
||||
|
||||
match database_kind {
|
||||
DatabaseKind::Mysql => Ok(format!(
|
||||
"mysql{}.{}",
|
||||
version_number.major,
|
||||
version_number.minor.unwrap()
|
||||
)),
|
||||
DatabaseKind::Mysql => Ok(format!("mysql{}.{}", version.major, version.minor.unwrap())),
|
||||
_ => Ok("".to_string()),
|
||||
}
|
||||
}
|
||||
@@ -35,19 +27,30 @@ pub fn aws_final_snapshot_name(database_name: &str) -> String {
|
||||
#[cfg(test)]
|
||||
mod tests_aws_databases_parameters {
|
||||
use crate::cloud_provider::aws::databases::utilities::get_parameter_group_from_version;
|
||||
use crate::cloud_provider::utilities::VersionsNumber;
|
||||
use crate::models::DatabaseKind;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn check_rds_mysql_parameter_groups() {
|
||||
let mysql_parameter_group = get_parameter_group_from_version("5.7.0", DatabaseKind::Mysql);
|
||||
let mysql_parameter_group = get_parameter_group_from_version(
|
||||
VersionsNumber::from_str("5.7.0").expect("error while trying to get version from str"),
|
||||
DatabaseKind::Mysql,
|
||||
);
|
||||
assert_eq!(mysql_parameter_group.unwrap(), "mysql5.7");
|
||||
|
||||
let mysql_parameter_group = get_parameter_group_from_version("8.0", DatabaseKind::Mysql);
|
||||
let mysql_parameter_group = get_parameter_group_from_version(
|
||||
VersionsNumber::from_str("8.0").expect("error while trying to get version from str"),
|
||||
DatabaseKind::Mysql,
|
||||
);
|
||||
assert_eq!(mysql_parameter_group.unwrap(), "mysql8.0");
|
||||
|
||||
let mysql_parameter_group = get_parameter_group_from_version("8", DatabaseKind::Mysql);
|
||||
let mysql_parameter_group = get_parameter_group_from_version(
|
||||
VersionsNumber::from_str("8").expect("error while trying to get version from str"),
|
||||
DatabaseKind::Mysql,
|
||||
);
|
||||
assert_eq!(
|
||||
mysql_parameter_group.unwrap_err(),
|
||||
mysql_parameter_group.unwrap_err().message(),
|
||||
"Can't determine the minor version, to select parameter group for Mysql version 8"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ impl<'a> EKS<'a> {
|
||||
e,
|
||||
);
|
||||
|
||||
logger.log(LogLevel::Error, EngineEvent::Error(err.clone()));
|
||||
logger.log(LogLevel::Error, EngineEvent::Error(err.clone(), None));
|
||||
|
||||
return Err(err);
|
||||
}
|
||||
@@ -465,10 +465,13 @@ impl<'a> EKS<'a> {
|
||||
Some(secret_id) => context.insert("vault_secret_id", secret_id.to_str().unwrap()),
|
||||
None => self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Error(EngineError::new_missing_required_env_variable(
|
||||
event_details.clone(),
|
||||
"VAULT_SECRET_ID".to_string(),
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_missing_required_env_variable(
|
||||
event_details.clone(),
|
||||
"VAULT_SECRET_ID".to_string(),
|
||||
),
|
||||
None,
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -618,7 +621,7 @@ impl<'a> EKS<'a> {
|
||||
)
|
||||
}
|
||||
Err(e) => {
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e));
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e, None));
|
||||
self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deploying(
|
||||
@@ -653,11 +656,10 @@ impl<'a> EKS<'a> {
|
||||
),
|
||||
Err(e) => self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Error(EngineError::new_cannot_get_or_create_iam_role(
|
||||
event_details.clone(),
|
||||
role.role_name,
|
||||
e,
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_cannot_get_or_create_iam_role(event_details.clone(), role.role_name, e),
|
||||
None,
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -736,10 +738,10 @@ impl<'a> EKS<'a> {
|
||||
}
|
||||
Err(e) => self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Error(EngineError::new_terraform_state_does_not_exist(
|
||||
event_details.clone(),
|
||||
e,
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_terraform_state_does_not_exist(event_details.clone(), e),
|
||||
None,
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
@@ -941,7 +943,8 @@ impl<'a> EKS<'a> {
|
||||
}
|
||||
Err(e) => {
|
||||
let error = EngineError::new_terraform_state_does_not_exist(event_details.clone(), e);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
};
|
||||
@@ -1149,10 +1152,10 @@ impl<'a> EKS<'a> {
|
||||
// An issue occurred during the apply before destroy of Terraform, it may be expected if you're resuming a destroy
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Error(EngineError::new_terraform_error_while_executing_pipeline(
|
||||
event_details.clone(),
|
||||
e,
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_terraform_error_while_executing_pipeline(event_details.clone(), e),
|
||||
None,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1509,22 +1512,28 @@ impl<'a> Kubernetes for EKS<'a> {
|
||||
|
||||
#[named]
|
||||
fn on_create(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Create));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.create())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Create));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.create_error())
|
||||
}
|
||||
@@ -1688,7 +1697,7 @@ impl<'a> Kubernetes for EKS<'a> {
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
Stage::Infrastructure(InfrastructureStep::Upgrade),
|
||||
) {
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e.clone()));
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e.clone(), None));
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
@@ -1798,88 +1807,112 @@ impl<'a> Kubernetes for EKS<'a> {
|
||||
|
||||
#[named]
|
||||
fn on_upgrade(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Upgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.upgrade())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_upgrade_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Upgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.upgrade_error())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_downgrade(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Downgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.downgrade())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_downgrade_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Downgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.downgrade_error())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_pause(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Pause, || self.pause())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Pause, || self.pause_error())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_delete(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Delete, || self.delete())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Delete, || self.delete_error())
|
||||
}
|
||||
@@ -1892,8 +1925,10 @@ impl<'a> Kubernetes for EKS<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::deploy_environment(self, environment, event_details)
|
||||
kubernetes::deploy_environment(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
@@ -1904,8 +1939,10 @@ impl<'a> Kubernetes for EKS<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::deploy_environment_error(self, environment, event_details)
|
||||
kubernetes::deploy_environment_error(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
@@ -1916,17 +1953,22 @@ impl<'a> Kubernetes for EKS<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::pause_environment(self, environment, event_details)
|
||||
kubernetes::pause_environment(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn pause_environment_error(&self, _environment: &Environment) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -1939,17 +1981,22 @@ impl<'a> Kubernetes for EKS<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::delete_environment(self, environment, event_details)
|
||||
kubernetes::delete_environment(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn delete_environment_error(&self, _environment: &Environment) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@ use rusoto_credential::StaticProvider;
|
||||
use rusoto_sts::{GetCallerIdentityRequest, Sts, StsClient};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::cloud_provider::{CloudProvider, EngineError, Kind, TerraformStateCredentials};
|
||||
use crate::cloud_provider::{CloudProvider, Kind, TerraformStateCredentials};
|
||||
use crate::constants::{AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY};
|
||||
use crate::error::EngineErrorCause;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EventDetails, GeneralStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::models::{Context, Listen, Listener, Listeners, QoveryIdentifier};
|
||||
use crate::runtime::block_on;
|
||||
|
||||
pub mod application;
|
||||
@@ -108,18 +109,15 @@ impl CloudProvider for AWS {
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::General(GeneralStep::RetrieveClusterConfig));
|
||||
let client = StsClient::new_with_client(self.client(), Region::default());
|
||||
let s = block_on(client.get_caller_identity(GetCallerIdentityRequest::default()));
|
||||
|
||||
match s {
|
||||
Ok(_x) => Ok(()),
|
||||
Err(_) => {
|
||||
return Err(self.engine_error(
|
||||
EngineErrorCause::User(
|
||||
"Your AWS account seems to be no longer valid (bad Credentials). \
|
||||
Please contact your Organization administrator to fix or change the Credentials.",
|
||||
),
|
||||
format!("failed to login to AWS {}", self.name_with_id()),
|
||||
return Err(EngineError::new_client_invalid_cloud_provider_credentials(
|
||||
event_details,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -150,6 +148,19 @@ impl CloudProvider for AWS {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn get_event_details(&self, stage: Stage) -> EventDetails {
|
||||
let context = self.context();
|
||||
EventDetails::new(
|
||||
None,
|
||||
QoveryIdentifier::from(context.organization_id().to_string()),
|
||||
QoveryIdentifier::from(context.cluster_id().to_string()),
|
||||
QoveryIdentifier::from(context.execution_id().to_string()),
|
||||
None,
|
||||
stage,
|
||||
self.to_transmitter(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Listen for AWS {
|
||||
@@ -161,3 +172,9 @@ impl Listen for AWS {
|
||||
self.listeners.push(listener);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTransmitter for AWS {
|
||||
fn to_transmitter(&self) -> Transmitter {
|
||||
Transmitter::CloudProvider(self.id.to_string(), self.name.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ use crate::cloud_provider::utilities::{check_cname_for, print_action, sanitize_n
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
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::errors::EngineError;
|
||||
use crate::events::{EngineEvent, EnvironmentStep, EventMessage, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::{LogLevel, Logger};
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
|
||||
@@ -26,6 +26,7 @@ pub struct Router {
|
||||
sticky_sessions_enabled: bool,
|
||||
routes: Vec<Route>,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl Router {
|
||||
@@ -39,6 +40,7 @@ impl Router {
|
||||
routes: Vec<Route>,
|
||||
sticky_sessions_enabled: bool,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Router {
|
||||
context,
|
||||
@@ -50,6 +52,7 @@ impl Router {
|
||||
sticky_sessions_enabled,
|
||||
routes,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +127,7 @@ impl Service for Router {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
@@ -177,10 +181,7 @@ impl Service for Router {
|
||||
context.insert("nginx_limit_cpu", "200m");
|
||||
context.insert("nginx_limit_memory", "128Mi");
|
||||
|
||||
let kubernetes_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => return Err(e.to_legacy_engine_error()),
|
||||
};
|
||||
let kubernetes_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
|
||||
// Default domain
|
||||
match crate::cmd::kubectl::kubectl_exec_get_external_ingress_hostname(
|
||||
@@ -192,12 +193,28 @@ impl Service for Router {
|
||||
Ok(external_ingress_hostname_default) => match external_ingress_hostname_default {
|
||||
Some(hostname) => context.insert("external_ingress_hostname_default", hostname.as_str()),
|
||||
None => {
|
||||
warn!("unable to get external_ingress_hostname_default - what's wrong? This must never happened");
|
||||
// TODO(benjaminch): Handle better this one via a proper error eventually
|
||||
self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(
|
||||
"Error while trying to get Load Balancer hostname from Kubernetes cluster".to_string(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// FIXME really?
|
||||
warn!("can't fetch kubernetes config file - what's wrong? This must never happened");
|
||||
// TODO(benjaminch): Handle better this one via a proper error eventually
|
||||
self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe("Can't fetch external ingress hostname.".to_string()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,12 +241,12 @@ impl Service for Router {
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("routerId={}", self.id))
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Router(self.id().to_string(), self.name().to_string())
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("routerId={}", self.id))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,22 +309,21 @@ impl ToTransmitter for Router {
|
||||
impl Create for Router {
|
||||
#[named]
|
||||
fn on_create(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let workspace_dir = self.workspace_directory();
|
||||
let helm_release_name = self.helm_release_name();
|
||||
|
||||
let kubernetes_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(p) => p,
|
||||
Err(e) => return Err(e.to_legacy_engine_error()),
|
||||
};
|
||||
let kubernetes_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
|
||||
// respect order - getting the context here and not before is mandatory
|
||||
// the nginx-ingress must be available to get the external dns target if necessary
|
||||
@@ -317,13 +333,12 @@ impl Create for Router {
|
||||
if let Err(e) =
|
||||
crate::template::generate_and_copy_all_files_into_dir(from_dir.as_str(), workspace_dir.as_str(), context)
|
||||
{
|
||||
return Err(NewEngineError::new_cannot_copy_files_from_one_directory_to_another(
|
||||
return Err(EngineError::new_cannot_copy_files_from_one_directory_to_another(
|
||||
event_details.clone(),
|
||||
from_dir.to_string(),
|
||||
workspace_dir.to_string(),
|
||||
e,
|
||||
)
|
||||
.to_legacy_engine_error());
|
||||
));
|
||||
}
|
||||
|
||||
// do exec helm upgrade and return the last deployment status
|
||||
@@ -331,7 +346,8 @@ impl Create for Router {
|
||||
&kubernetes_config_file_path,
|
||||
&kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| to_engine_error(&event_details, e).to_legacy_engine_error())?;
|
||||
.map_err(|e| to_engine_error(&event_details, e))?;
|
||||
|
||||
let chart = ChartInfo::new_from_custom_namespace(
|
||||
helm_release_name,
|
||||
workspace_dir.clone(),
|
||||
@@ -346,12 +362,14 @@ impl Create for Router {
|
||||
);
|
||||
|
||||
helm.upgrade(&chart, &vec![])
|
||||
.map_err(|e| NewEngineError::new_helm_error(event_details.clone(), e).to_legacy_engine_error())
|
||||
.map_err(|e| EngineError::new_helm_error(event_details.clone(), e))
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
|
||||
// check non custom domains
|
||||
self.check_domains()?;
|
||||
self.check_domains(event_details.clone(), self.logger())?;
|
||||
|
||||
// Wait/Check that custom domain is a CNAME targeting qovery
|
||||
for domain_to_check in self.custom_domains.iter() {
|
||||
@@ -365,9 +383,19 @@ impl Create for Router {
|
||||
continue
|
||||
}
|
||||
Ok(err) | Err(err) => {
|
||||
warn!(
|
||||
"Invalid CNAME for {}. Might not be an issue if user is using a CDN: {}",
|
||||
domain_to_check.domain, err
|
||||
// TODO(benjaminch): Handle better this one via a proper error eventually
|
||||
self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new(
|
||||
format!(
|
||||
"Invalid CNAME for {}. Might not be an issue if user is using a CDN.",
|
||||
domain_to_check.domain,
|
||||
),
|
||||
Some(err.to_string()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -378,11 +406,14 @@ impl Create for Router {
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
@@ -392,8 +423,17 @@ impl Create for Router {
|
||||
}
|
||||
|
||||
impl Pause for Router {
|
||||
#[named]
|
||||
fn on_pause(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
info!("AWS.router.on_pause() called for {}, doing nothing", self.name());
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -403,11 +443,14 @@ impl Pause for Router {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -422,6 +465,8 @@ impl Delete for Router {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
delete_router(target, self, false, event_details)
|
||||
}
|
||||
@@ -438,6 +483,8 @@ impl Delete for Router {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
delete_router(target, self, true, event_details)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use tera::Context as TeraContext;
|
||||
|
||||
use crate::build_platform::Image;
|
||||
use crate::cloud_provider::kubernetes::validate_k8s_required_cpu_and_burstable;
|
||||
use crate::cloud_provider::models::{
|
||||
EnvironmentVariable, EnvironmentVariableDataTemplate, Storage, StorageDataTemplate,
|
||||
};
|
||||
@@ -9,14 +10,13 @@ use crate::cloud_provider::service::{
|
||||
scale_down_application, send_progress_on_long_task, Action, Create, Delete, Helm, Pause, Service, ServiceType,
|
||||
StatelessService,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{print_action, sanitize_name, validate_k8s_required_cpu_and_burstable};
|
||||
use crate::cloud_provider::utilities::{print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl::ScalingKind::{Deployment, Statefulset};
|
||||
use crate::error::EngineErrorCause::Internal;
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::errors::CommandError;
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::events::{EngineEvent, EnvironmentStep, EventMessage, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::{LogLevel, Logger};
|
||||
use crate::models::{Context, Listen, Listener, Listeners, ListenersHelper, Port};
|
||||
use ::function_name::named;
|
||||
use std::fmt;
|
||||
@@ -38,6 +38,7 @@ pub struct Application {
|
||||
storage: Vec<Storage<StorageType>>,
|
||||
environment_variables: Vec<EnvironmentVariable>,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
@@ -57,6 +58,7 @@ impl Application {
|
||||
storage: Vec<Storage<StorageType>>,
|
||||
environment_variables: Vec<EnvironmentVariable>,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Application {
|
||||
context,
|
||||
@@ -74,6 +76,7 @@ impl Application {
|
||||
storage,
|
||||
environment_variables,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +198,7 @@ impl Service for Application {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
@@ -206,10 +210,18 @@ impl Service for Application {
|
||||
Some(registry_url) => context.insert("image_name_with_tag", registry_url.as_str()),
|
||||
None => {
|
||||
let image_name_with_tag = self.image.name_with_tag();
|
||||
warn!(
|
||||
"there is no registry url, use image name with tag with the default container registry: {}",
|
||||
image_name_with_tag.as_str()
|
||||
|
||||
self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"there is no registry url, use image name with tag with the default container registry: {}",
|
||||
image_name_with_tag.as_str()
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
context.insert("image_name_with_tag", image_name_with_tag.as_str());
|
||||
}
|
||||
}
|
||||
@@ -220,14 +232,16 @@ impl Service for Application {
|
||||
&self.id,
|
||||
self.total_cpus(),
|
||||
self.cpu_burst(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
) {
|
||||
Ok(l) => l,
|
||||
Err(e) => {
|
||||
return Err(EngineError::new(
|
||||
Internal,
|
||||
EngineErrorScope::Application(self.id().to_string(), self.name().to_string()),
|
||||
self.context.execution_id(),
|
||||
Some(e.to_string()),
|
||||
return Err(EngineError::new_k8s_validate_required_cpu_and_burstable_error(
|
||||
event_details.clone(),
|
||||
self.total_cpus(),
|
||||
self.cpu_burst(),
|
||||
e,
|
||||
));
|
||||
}
|
||||
};
|
||||
@@ -288,23 +302,26 @@ impl Service for Application {
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("appId={}", self.id))
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Application(self.id().to_string(), self.name().to_string())
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("appId={}", self.id))
|
||||
}
|
||||
}
|
||||
|
||||
impl Create for Application {
|
||||
#[named]
|
||||
fn on_create(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
@@ -318,11 +335,14 @@ impl Create for Application {
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
@@ -334,11 +354,14 @@ impl Create for Application {
|
||||
impl Pause for Application {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -357,11 +380,14 @@ impl Pause for Application {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -377,6 +403,8 @@ impl Delete for Application {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
@@ -396,6 +424,8 @@ impl Delete for Application {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
|
||||
@@ -3,14 +3,15 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{get_self_hosted_mongodb_version, print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
@@ -28,6 +29,7 @@ pub struct MongoDB {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl MongoDB {
|
||||
@@ -44,6 +46,7 @@ impl MongoDB {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
MongoDB {
|
||||
context,
|
||||
@@ -58,11 +61,17 @@ impl MongoDB {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self) -> Result<String, EngineError> {
|
||||
check_service_version(get_self_hosted_mongodb_version(self.version().clone()), self)
|
||||
fn matching_correct_version(&self, event_details: EventDetails) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
get_self_hosted_mongodb_version(self.version().clone()),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn cloud_provider_name(&self) -> &str {
|
||||
@@ -152,17 +161,13 @@ impl Service for MongoDB {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -173,7 +178,7 @@ impl Service for MongoDB {
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
|
||||
let version = self.matching_correct_version()?;
|
||||
let version = self.matching_correct_version(event_details.clone())?.matched_version();
|
||||
context.insert("version", &version);
|
||||
|
||||
for (k, v) in kubernetes.cloud_provider().tera_context_environment_variables() {
|
||||
@@ -218,12 +223,8 @@ impl Service for MongoDB {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,10 +271,12 @@ impl Create for MongoDB {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
deploy_stateful_service(target, self, event_details.clone())
|
||||
deploy_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -283,11 +286,14 @@ impl Create for MongoDB {
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -297,11 +303,14 @@ impl Create for MongoDB {
|
||||
impl Pause for MongoDB {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -315,11 +324,14 @@ impl Pause for MongoDB {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -335,10 +347,12 @@ impl Delete for MongoDB {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
delete_stateful_service(target, self, event_details.clone())
|
||||
delete_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -348,11 +362,14 @@ impl Delete for MongoDB {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -3,14 +3,15 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{get_self_hosted_mysql_version, print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
@@ -28,6 +29,7 @@ pub struct MySQL {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl MySQL {
|
||||
@@ -44,6 +46,7 @@ impl MySQL {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Self {
|
||||
context,
|
||||
@@ -58,11 +61,17 @@ impl MySQL {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self) -> Result<String, EngineError> {
|
||||
check_service_version(get_self_hosted_mysql_version(self.version()), self)
|
||||
fn matching_correct_version(&self, event_details: EventDetails) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
get_self_hosted_mysql_version(self.version()),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn cloud_provider_name(&self) -> &str {
|
||||
@@ -152,17 +161,13 @@ impl Service for MySQL {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -173,7 +178,7 @@ impl Service for MySQL {
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
|
||||
let version = &self.matching_correct_version()?;
|
||||
let version = &self.matching_correct_version(event_details.clone())?.matched_version();
|
||||
context.insert("version", &version);
|
||||
|
||||
for (k, v) in kubernetes.cloud_provider().tera_context_environment_variables() {
|
||||
@@ -214,16 +219,12 @@ impl Service for MySQL {
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,12 +271,14 @@ impl Create for MySQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(
|
||||
self,
|
||||
crate::cloud_provider::service::Action::Create,
|
||||
Box::new(|| deploy_stateful_service(target, self, event_details.clone())),
|
||||
Box::new(|| deploy_stateful_service(target, self, event_details.clone(), self.logger())),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -286,11 +289,14 @@ impl Create for MySQL {
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -300,11 +306,14 @@ impl Create for MySQL {
|
||||
impl Pause for MySQL {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -318,11 +327,14 @@ impl Pause for MySQL {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -338,12 +350,14 @@ impl Delete for MySQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(
|
||||
self,
|
||||
crate::cloud_provider::service::Action::Delete,
|
||||
Box::new(|| delete_stateful_service(target, self, event_details.clone())),
|
||||
Box::new(|| delete_stateful_service(target, self, event_details.clone(), self.logger())),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -353,11 +367,14 @@ impl Delete for MySQL {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3,14 +3,15 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{get_self_hosted_postgres_version, print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
@@ -28,6 +29,7 @@ pub struct PostgreSQL {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl PostgreSQL {
|
||||
@@ -44,6 +46,7 @@ impl PostgreSQL {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
PostgreSQL {
|
||||
context,
|
||||
@@ -58,11 +61,17 @@ impl PostgreSQL {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self) -> Result<String, EngineError> {
|
||||
check_service_version(get_self_hosted_postgres_version(self.version()), self)
|
||||
fn matching_correct_version(&self, event_details: EventDetails) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
get_self_hosted_postgres_version(self.version()),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn cloud_provider_name(&self) -> &str {
|
||||
@@ -152,17 +161,13 @@ impl Service for PostgreSQL {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -173,7 +178,7 @@ impl Service for PostgreSQL {
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
|
||||
let version = self.matching_correct_version()?;
|
||||
let version = self.matching_correct_version(event_details.clone())?.matched_version();
|
||||
context.insert("version", &version);
|
||||
|
||||
for (k, v) in kubernetes.cloud_provider().tera_context_environment_variables() {
|
||||
@@ -220,12 +225,8 @@ impl Service for PostgreSQL {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,12 +273,14 @@ impl Create for PostgreSQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(
|
||||
self,
|
||||
crate::cloud_provider::service::Action::Create,
|
||||
Box::new(|| deploy_stateful_service(target, self, event_details.clone())),
|
||||
Box::new(|| deploy_stateful_service(target, self, event_details.clone(), self.logger())),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -287,11 +290,14 @@ impl Create for PostgreSQL {
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -301,11 +307,14 @@ impl Create for PostgreSQL {
|
||||
impl Pause for PostgreSQL {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -319,11 +328,14 @@ impl Pause for PostgreSQL {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -339,12 +351,14 @@ impl Delete for PostgreSQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(
|
||||
self,
|
||||
crate::cloud_provider::service::Action::Delete,
|
||||
Box::new(|| delete_stateful_service(target, self, event_details.clone())),
|
||||
Box::new(|| delete_stateful_service(target, self, event_details.clone(), self.logger())),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -354,11 +368,14 @@ impl Delete for PostgreSQL {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -3,14 +3,15 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{get_self_hosted_redis_version, print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
@@ -28,6 +29,7 @@ pub struct Redis {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl Redis {
|
||||
@@ -44,6 +46,7 @@ impl Redis {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Self {
|
||||
context,
|
||||
@@ -58,11 +61,17 @@ impl Redis {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self) -> Result<String, EngineError> {
|
||||
check_service_version(get_self_hosted_redis_version(self.version()), self)
|
||||
fn matching_correct_version(&self, event_details: EventDetails) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
get_self_hosted_redis_version(self.version()),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn cloud_provider_name(&self) -> &str {
|
||||
@@ -152,17 +161,13 @@ impl Service for Redis {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -171,7 +176,7 @@ impl Service for Redis {
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
);
|
||||
|
||||
let version = self.matching_correct_version()?;
|
||||
let version = self.matching_correct_version(event_details.clone())?.matched_version();
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
context.insert("version", &version);
|
||||
@@ -217,12 +222,8 @@ impl Service for Redis {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,12 +270,14 @@ impl Create for Redis {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(
|
||||
self,
|
||||
crate::cloud_provider::service::Action::Create,
|
||||
Box::new(|| deploy_stateful_service(target, self, event_details.clone())),
|
||||
Box::new(|| deploy_stateful_service(target, self, event_details.clone(), self.logger())),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -285,11 +288,14 @@ impl Create for Redis {
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -298,11 +304,14 @@ impl Create for Redis {
|
||||
impl Pause for Redis {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -316,11 +325,14 @@ impl Pause for Redis {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -335,12 +347,14 @@ impl Delete for Redis {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(
|
||||
self,
|
||||
crate::cloud_provider::service::Action::Pause,
|
||||
Box::new(|| delete_stateful_service(target, self, event_details.clone())),
|
||||
Box::new(|| delete_stateful_service(target, self, event_details.clone(), self.logger())),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -350,11 +364,14 @@ impl Delete for Redis {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -63,12 +63,10 @@ fn get_do_kubernetes_latest_slug_version(
|
||||
doks_versions: &Vec<KubernetesVersion>,
|
||||
wished_version: &str,
|
||||
) -> Result<Option<String>, CommandError> {
|
||||
let wished_k8s_version =
|
||||
VersionsNumber::from_str(wished_version).map_err(|e| CommandError::new_from_safe_message(e.to_string()))?;
|
||||
let wished_k8s_version = VersionsNumber::from_str(wished_version)?;
|
||||
|
||||
for kubernetes_doks_version in doks_versions {
|
||||
let current_k8s_version = VersionsNumber::from_str(kubernetes_doks_version.kubernetes_version.as_str())
|
||||
.map_err(|e| CommandError::new_from_safe_message(e.to_string()))?;
|
||||
let current_k8s_version = VersionsNumber::from_str(kubernetes_doks_version.kubernetes_version.as_str())?;
|
||||
if current_k8s_version.major == wished_k8s_version.major
|
||||
&& current_k8s_version.minor == wished_k8s_version.minor
|
||||
{
|
||||
|
||||
@@ -133,7 +133,7 @@ impl<'a> DOKS<'a> {
|
||||
e,
|
||||
);
|
||||
|
||||
logger.log(LogLevel::Error, EngineEvent::Error(err.clone()));
|
||||
logger.log(LogLevel::Error, EngineEvent::Error(err.clone(), None));
|
||||
|
||||
return Err(err);
|
||||
}
|
||||
@@ -368,10 +368,13 @@ impl<'a> DOKS<'a> {
|
||||
Some(secret_id) => context.insert("vault_secret_id", secret_id.to_str().unwrap()),
|
||||
None => self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Error(EngineError::new_missing_required_env_variable(
|
||||
event_details.clone(),
|
||||
"VAULT_SECRET_ID".to_string(),
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_missing_required_env_variable(
|
||||
event_details.clone(),
|
||||
"VAULT_SECRET_ID".to_string(),
|
||||
),
|
||||
None,
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -399,7 +402,9 @@ impl<'a> DOKS<'a> {
|
||||
None => Err(EngineError::new_unsupported_version_error(
|
||||
event_details.clone(),
|
||||
self.kind().to_string(),
|
||||
VersionsNumber::from_str(&self.version).expect("cannot parse version"),
|
||||
VersionsNumber::from_str(&self.version)
|
||||
.expect("cannot parse version")
|
||||
.to_string(),
|
||||
)),
|
||||
Some(v) => Ok(v),
|
||||
},
|
||||
@@ -503,7 +508,7 @@ impl<'a> DOKS<'a> {
|
||||
)
|
||||
}
|
||||
Err(e) => {
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e));
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e, None));
|
||||
self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deploying(
|
||||
@@ -598,10 +603,10 @@ impl<'a> DOKS<'a> {
|
||||
}
|
||||
Err(e) => self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Error(EngineError::new_terraform_state_does_not_exist(
|
||||
event_details.clone(),
|
||||
e,
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_terraform_state_does_not_exist(event_details.clone(), e),
|
||||
None,
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
@@ -619,7 +624,8 @@ impl<'a> DOKS<'a> {
|
||||
self.kubeconfig_bucket_name(),
|
||||
CommandError::new(e.message.unwrap_or("No error message".to_string()), None),
|
||||
);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
@@ -630,7 +636,8 @@ impl<'a> DOKS<'a> {
|
||||
self.logs_bucket_name(),
|
||||
CommandError::new(e.message.unwrap_or("No error message".to_string()), None),
|
||||
);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
@@ -661,7 +668,8 @@ impl<'a> DOKS<'a> {
|
||||
kubeconfig_name.to_string(),
|
||||
CommandError::new(e.message.unwrap_or("No error message".to_string()), None),
|
||||
);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
@@ -782,11 +790,7 @@ impl<'a> DOKS<'a> {
|
||||
return Err(EngineError::new_k8s_loadbalancer_configuration_issue(
|
||||
event_details.clone(),
|
||||
CommandError::new(
|
||||
format!(
|
||||
"{}, error: {}.",
|
||||
safe_message.to_string(),
|
||||
e.message.unwrap_or("No error message".to_string())
|
||||
),
|
||||
format!("{}, error: {}.", safe_message.to_string(), e.message(),),
|
||||
Some(safe_message.to_string()),
|
||||
),
|
||||
));
|
||||
@@ -995,10 +999,10 @@ impl<'a> DOKS<'a> {
|
||||
// An issue occurred during the apply before destroy of Terraform, it may be expected if you're resuming a destroy
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Error(EngineError::new_terraform_error_while_executing_pipeline(
|
||||
event_details.clone(),
|
||||
e,
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_terraform_error_while_executing_pipeline(event_details.clone(), e),
|
||||
None,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1355,22 +1359,28 @@ impl<'a> Kubernetes for DOKS<'a> {
|
||||
|
||||
#[named]
|
||||
fn on_create(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Create));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.create())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Create));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.create_error())
|
||||
}
|
||||
@@ -1407,7 +1417,7 @@ impl<'a> Kubernetes for DOKS<'a> {
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
event_details.stage().clone(),
|
||||
) {
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e.clone()));
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e.clone(), None));
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
@@ -1436,7 +1446,9 @@ impl<'a> Kubernetes for DOKS<'a> {
|
||||
return Err(EngineError::new_unsupported_version_error(
|
||||
event_details.clone(),
|
||||
self.kind().to_string(),
|
||||
VersionsNumber::from_str(&self.version).expect("cannot parse version"),
|
||||
VersionsNumber::from_str(&self.version)
|
||||
.expect("cannot parse version")
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
Some(v) => v,
|
||||
@@ -1528,88 +1540,112 @@ impl<'a> Kubernetes for DOKS<'a> {
|
||||
|
||||
#[named]
|
||||
fn on_upgrade(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Upgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.upgrade())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_upgrade_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Upgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.upgrade_error())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_downgrade(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Downgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.downgrade())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_downgrade_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Downgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.downgrade_error())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_pause(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Pause, || self.pause())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Pause, || self.pause_error())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_delete(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Delete, || self.delete())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Delete, || self.delete_error())
|
||||
}
|
||||
@@ -1622,8 +1658,10 @@ impl<'a> Kubernetes for DOKS<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::deploy_environment(self, environment, event_details)
|
||||
kubernetes::deploy_environment(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
@@ -1634,8 +1672,10 @@ impl<'a> Kubernetes for DOKS<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::deploy_environment_error(self, environment, event_details)
|
||||
kubernetes::deploy_environment_error(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
@@ -1646,17 +1686,22 @@ impl<'a> Kubernetes for DOKS<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::pause_environment(self, environment, event_details)
|
||||
kubernetes::pause_environment(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn pause_environment_error(&self, _environment: &Environment) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -1669,17 +1714,22 @@ impl<'a> Kubernetes for DOKS<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::delete_environment(self, environment, event_details)
|
||||
kubernetes::delete_environment(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn delete_environment_error(&self, _environment: &Environment) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ use uuid::Uuid;
|
||||
|
||||
use crate::cloud_provider::{CloudProvider, Kind, TerraformStateCredentials};
|
||||
use crate::constants::DIGITAL_OCEAN_TOKEN;
|
||||
use crate::error::{EngineError, EngineErrorCause};
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EventDetails, GeneralStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::models::{Context, Listen, Listener, Listeners, QoveryIdentifier};
|
||||
|
||||
pub mod application;
|
||||
pub mod databases;
|
||||
@@ -100,16 +101,13 @@ impl CloudProvider for DO {
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::General(GeneralStep::RetrieveClusterConfig));
|
||||
let client = DigitalOcean::new(&self.token);
|
||||
match client {
|
||||
Ok(_x) => Ok(()),
|
||||
Err(_) => {
|
||||
return Err(self.engine_error(
|
||||
EngineErrorCause::User(
|
||||
"Your DigitalOcean account seems to be no longer valid (bad Credentials). \
|
||||
Please contact your Organization administrator to fix or change the Credentials.",
|
||||
),
|
||||
format!("failed to login to Digital Ocean {}", self.name_with_id()),
|
||||
return Err(EngineError::new_client_invalid_cloud_provider_credentials(
|
||||
event_details,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -134,6 +132,19 @@ impl CloudProvider for DO {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn get_event_details(&self, stage: Stage) -> EventDetails {
|
||||
let context = self.context();
|
||||
EventDetails::new(
|
||||
None,
|
||||
QoveryIdentifier::from(context.organization_id().to_string()),
|
||||
QoveryIdentifier::from(context.cluster_id().to_string()),
|
||||
QoveryIdentifier::from(context.execution_id().to_string()),
|
||||
None,
|
||||
stage,
|
||||
self.to_transmitter(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Listen for DO {
|
||||
@@ -145,3 +156,9 @@ impl Listen for DO {
|
||||
self.listeners.push(listener);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTransmitter for DO {
|
||||
fn to_transmitter(&self) -> Transmitter {
|
||||
Transmitter::CloudProvider(self.id.to_string(), self.name.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,35 +3,34 @@ extern crate serde_json;
|
||||
use reqwest::StatusCode;
|
||||
|
||||
use crate::cloud_provider::digitalocean::models::load_balancers::LoadBalancer;
|
||||
use crate::error::{SimpleError, SimpleErrorKind};
|
||||
use crate::errors::CommandError;
|
||||
use crate::utilities::get_header_with_bearer;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub const DO_LOAD_BALANCER_API_PATH: &str = "https://api.digitalocean.com/v2/load_balancers";
|
||||
|
||||
pub fn get_ip_from_do_load_balancer_api_output(json_content: &str) -> Result<Ipv4Addr, SimpleError> {
|
||||
pub fn get_ip_from_do_load_balancer_api_output(json_content: &str) -> Result<Ipv4Addr, CommandError> {
|
||||
let res_load_balancer = serde_json::from_str::<LoadBalancer>(json_content);
|
||||
|
||||
match res_load_balancer {
|
||||
Ok(lb) => match Ipv4Addr::from_str(&lb.load_balancer.ip) {
|
||||
Ok(ip) => Ok(ip),
|
||||
Err(e) => Err(SimpleError::new(
|
||||
SimpleErrorKind::Other,
|
||||
Err(e) => Err(CommandError::new(
|
||||
e.to_string(),
|
||||
Some(format!(
|
||||
"Info returned from DO API is not a valid IP, received '{:?}' instead. {:?}",
|
||||
&lb.load_balancer.ip, e
|
||||
"Info returned from DO API is not a valid IP, received '{:?}' instead.",
|
||||
&lb.load_balancer.ip,
|
||||
)),
|
||||
)),
|
||||
},
|
||||
Err(_) => Err(SimpleError::new(
|
||||
SimpleErrorKind::Other,
|
||||
Some("Error While trying to deserialize json received from Digital Ocean Load Balancer API".to_string()),
|
||||
Err(_) => Err(CommandError::new_from_safe_message(
|
||||
"Error While trying to deserialize json received from Digital Ocean Load Balancer API".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_get_load_balancer_ip(token: &str, load_balancer_id: &str) -> Result<Ipv4Addr, SimpleError> {
|
||||
pub fn do_get_load_balancer_ip(token: &str, load_balancer_id: &str) -> Result<Ipv4Addr, CommandError> {
|
||||
let headers = get_header_with_bearer(token);
|
||||
let url = format!("{}/{}", DO_LOAD_BALANCER_API_PATH, load_balancer_id);
|
||||
let res = reqwest::blocking::Client::new().get(&url).headers(headers).send();
|
||||
@@ -42,17 +41,16 @@ pub fn do_get_load_balancer_ip(token: &str, load_balancer_id: &str) -> Result<Ip
|
||||
let content = response.text().unwrap();
|
||||
get_ip_from_do_load_balancer_api_output(content.as_str())
|
||||
}
|
||||
_ => Err(SimpleError::new(
|
||||
SimpleErrorKind::Other,
|
||||
_ => Err(CommandError::new(
|
||||
format!("{:?}", response),
|
||||
Some(
|
||||
format!("Unknown status code received from Digital Ocean Kubernetes API while retrieving load balancer information. {:?}", response),
|
||||
"Unknown status code received from Digital Ocean Kubernetes API while retrieving load balancer information.".to_string(),
|
||||
),
|
||||
)),
|
||||
},
|
||||
Err(_) => {
|
||||
Err(SimpleError::new(
|
||||
SimpleErrorKind::Other,
|
||||
Some("Unable to get a response from Digital Ocean Load Balancer API"),
|
||||
Err(CommandError::new_from_safe_message(
|
||||
"Unable to get a response from Digital Ocean Load Balancer API".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,15 +4,15 @@ 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,
|
||||
Delete, Helm, Pause, Service, ServiceType, StatelessService,
|
||||
Delete, Helm, Pause, Router as RRouter, Service, ServiceType, StatelessService,
|
||||
};
|
||||
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;
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EngineEvent, EnvironmentStep, EventMessage, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::{LogLevel, Logger};
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
|
||||
@@ -26,6 +26,7 @@ pub struct Router {
|
||||
sticky_sessions_enabled: bool,
|
||||
routes: Vec<Route>,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl Router {
|
||||
@@ -39,6 +40,7 @@ impl Router {
|
||||
routes: Vec<Route>,
|
||||
sticky_sessions_enabled: bool,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Router {
|
||||
context,
|
||||
@@ -50,6 +52,7 @@ impl Router {
|
||||
sticky_sessions_enabled,
|
||||
routes,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +127,7 @@ impl Service for Router {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
@@ -187,34 +191,44 @@ impl Service for Router {
|
||||
context.insert("nginx_requests_memory", "128Mi");
|
||||
context.insert("nginx_limit_cpu", "200m");
|
||||
context.insert("nginx_limit_memory", "128Mi");
|
||||
let kubernetes_config_file_path = kubernetes.get_kubeconfig_file_path();
|
||||
|
||||
match kubernetes_config_file_path {
|
||||
Ok(kubernetes_config_file_path_string) => {
|
||||
// Default domain
|
||||
let external_ingress_hostname_default = crate::cmd::kubectl::kubectl_exec_get_external_ingress_hostname(
|
||||
kubernetes_config_file_path_string.as_str(),
|
||||
"nginx-ingress",
|
||||
"nginx-ingress-ingress-nginx-controller",
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
);
|
||||
let kubernetes_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
|
||||
match external_ingress_hostname_default {
|
||||
Ok(external_ingress_hostname_default) => match external_ingress_hostname_default {
|
||||
Some(hostname) => context.insert("external_ingress_hostname_default", hostname.as_str()),
|
||||
None => {
|
||||
return Err(self.engine_error(
|
||||
EngineErrorCause::Internal,
|
||||
"Error while trying to get Load Balancer hostname from Kubernetes cluster".into(),
|
||||
));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
error!("can't fetch external ingress hostname");
|
||||
}
|
||||
// Default domain
|
||||
let external_ingress_hostname_default = crate::cmd::kubectl::kubectl_exec_get_external_ingress_hostname(
|
||||
kubernetes_config_file_path,
|
||||
"nginx-ingress",
|
||||
"nginx-ingress-ingress-nginx-controller",
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
);
|
||||
|
||||
match external_ingress_hostname_default {
|
||||
Ok(external_ingress_hostname_default) => match external_ingress_hostname_default {
|
||||
Some(hostname) => context.insert("external_ingress_hostname_default", hostname.as_str()),
|
||||
None => {
|
||||
// TODO(benjaminch): Handle better this one via a proper error eventually
|
||||
self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(
|
||||
"Error while trying to get Load Balancer hostname from Kubernetes cluster".to_string(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// FIXME really?
|
||||
// TODO(benjaminch): Handle better this one via a proper error eventually
|
||||
self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe("Can't fetch external ingress hostname.".to_string()),
|
||||
),
|
||||
);
|
||||
}
|
||||
Err(_) => error!("can't fetch kubernetes config file - what's wrong? This must never happened"),
|
||||
}
|
||||
|
||||
let router_default_domain_hash = crate::crypto::to_sha1_truncate_16(self.default_domain.as_str());
|
||||
@@ -244,8 +258,8 @@ impl Service for Router {
|
||||
Some(format!("routerId={}", self.id))
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Router(self.id().to_string(), self.name().to_string())
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,23 +325,22 @@ impl ToTransmitter for Router {
|
||||
impl Create for Router {
|
||||
#[named]
|
||||
fn on_create(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
|
||||
let workspace_dir = self.workspace_directory();
|
||||
let helm_release_name = self.helm_release_name();
|
||||
|
||||
let kubernetes_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(p) => p,
|
||||
Err(e) => return Err(e.to_legacy_engine_error()),
|
||||
};
|
||||
let kubernetes_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
|
||||
// respect order - getting the context here and not before is mandatory
|
||||
// the nginx-ingress must be available to get the external dns target if necessary
|
||||
@@ -337,13 +350,12 @@ impl Create for Router {
|
||||
if let Err(e) =
|
||||
crate::template::generate_and_copy_all_files_into_dir(from_dir.as_str(), workspace_dir.as_str(), context)
|
||||
{
|
||||
return Err(NewEngineError::new_cannot_copy_files_from_one_directory_to_another(
|
||||
return Err(EngineError::new_cannot_copy_files_from_one_directory_to_another(
|
||||
event_details.clone(),
|
||||
from_dir.to_string(),
|
||||
workspace_dir.to_string(),
|
||||
e,
|
||||
)
|
||||
.to_legacy_engine_error());
|
||||
));
|
||||
}
|
||||
|
||||
// do exec helm upgrade and return the last deployment status
|
||||
@@ -351,7 +363,7 @@ impl Create for Router {
|
||||
&kubernetes_config_file_path,
|
||||
&kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())?;
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e))?;
|
||||
let chart = ChartInfo::new_from_custom_namespace(
|
||||
helm_release_name,
|
||||
workspace_dir.clone(),
|
||||
@@ -366,14 +378,14 @@ impl Create for Router {
|
||||
);
|
||||
|
||||
helm.upgrade(&chart, &vec![])
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e))
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
use crate::cloud_provider::service::Router;
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
|
||||
// check non custom domains
|
||||
self.check_domains()?;
|
||||
self.check_domains(event_details.clone(), self.logger())?;
|
||||
|
||||
// Wait/Check that custom domain is a CNAME targeting qovery
|
||||
for domain_to_check in self.custom_domains.iter() {
|
||||
@@ -387,9 +399,19 @@ impl Create for Router {
|
||||
continue;
|
||||
}
|
||||
Ok(err) | Err(err) => {
|
||||
warn!(
|
||||
"Invalid CNAME for {}. Might not be an issue if user is using a CDN: {}",
|
||||
domain_to_check.domain, err
|
||||
// TODO(benjaminch): Handle better this one via a proper error eventually
|
||||
self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new(
|
||||
format!(
|
||||
"Invalid CNAME for {}. Might not be an issue if user is using a CDN.",
|
||||
domain_to_check.domain,
|
||||
),
|
||||
Some(err.to_string()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -400,11 +422,14 @@ impl Create for Router {
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
@@ -416,11 +441,14 @@ impl Create for Router {
|
||||
impl Pause for Router {
|
||||
#[named]
|
||||
fn on_pause(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -431,11 +459,14 @@ impl Pause for Router {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -450,6 +481,8 @@ impl Delete for Router {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
delete_router(target, self, false, event_details)
|
||||
}
|
||||
@@ -466,6 +499,8 @@ impl Delete for Router {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
delete_router(target, self, true, event_details)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::cloud_provider::service::{Action, StatefulService, StatelessService};
|
||||
use crate::error::EngineError;
|
||||
use crate::errors::EngineError;
|
||||
use crate::unit_conversion::cpu_string_to_float;
|
||||
|
||||
pub struct Environment {
|
||||
|
||||
@@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::cloud_provider::aws::regions::AwsZones;
|
||||
use crate::cloud_provider::environment::Environment;
|
||||
use crate::cloud_provider::models::NodeGroups;
|
||||
use crate::cloud_provider::models::{CpuLimits, NodeGroups};
|
||||
use crate::cloud_provider::service::CheckAction;
|
||||
use crate::cloud_provider::utilities::VersionsNumber;
|
||||
use crate::cloud_provider::{service, CloudProvider, DeploymentTarget};
|
||||
@@ -96,8 +96,20 @@ pub trait Kubernetes: Listen {
|
||||
if Path::new(&local_kubeconfig_generated).exists() {
|
||||
match File::open(&local_kubeconfig_generated) {
|
||||
Ok(_) => Some(local_kubeconfig_generated),
|
||||
Err(_) => {
|
||||
debug!("couldn't open {} file", &local_kubeconfig_generated);
|
||||
Err(err) => {
|
||||
self.logger().log(
|
||||
LogLevel::Debug,
|
||||
EngineEvent::Debug(
|
||||
self.get_event_details(stage.clone()),
|
||||
EventMessage::new(
|
||||
err.to_string(),
|
||||
Some(
|
||||
format!("Error, couldn't open {} file", &local_kubeconfig_generated,)
|
||||
.to_string(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -124,7 +136,7 @@ pub trait Kubernetes: Listen {
|
||||
Ok((path, file)) => (path, file),
|
||||
Err(err) => {
|
||||
let error = EngineError::new_cannot_retrieve_cluster_config_file(
|
||||
self.get_event_details(stage),
|
||||
self.get_event_details(stage.clone()),
|
||||
CommandError::new_from_safe_message(
|
||||
format!(
|
||||
"Error getting file from store, error: {}",
|
||||
@@ -133,7 +145,8 @@ pub trait Kubernetes: Listen {
|
||||
.to_string(),
|
||||
),
|
||||
);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
@@ -144,12 +157,13 @@ pub trait Kubernetes: Listen {
|
||||
Ok(metadata) => metadata,
|
||||
Err(err) => {
|
||||
let error = EngineError::new_cannot_retrieve_cluster_config_file(
|
||||
self.get_event_details(stage),
|
||||
self.get_event_details(stage.clone()),
|
||||
CommandError::new_from_safe_message(
|
||||
format!("Error getting file metadata, error: {}", err.to_string(),).to_string(),
|
||||
),
|
||||
);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
};
|
||||
@@ -158,13 +172,14 @@ pub trait Kubernetes: Listen {
|
||||
permissions.set_mode(0o400);
|
||||
if let Err(err) = std::fs::set_permissions(string_path.as_str(), permissions) {
|
||||
let error = EngineError::new_cannot_retrieve_cluster_config_file(
|
||||
self.get_event_details(stage),
|
||||
self.get_event_details(stage.clone()),
|
||||
CommandError::new_from_safe_message(format!(
|
||||
"Error setting file permissions, error: {}",
|
||||
err.to_string(),
|
||||
)),
|
||||
);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
@@ -193,7 +208,8 @@ pub trait Kubernetes: Listen {
|
||||
),
|
||||
);
|
||||
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
|
||||
return Err(error);
|
||||
}
|
||||
@@ -273,6 +289,7 @@ pub trait Kubernetes: Listen {
|
||||
Ok((path, _)) => path,
|
||||
Err(e) => return Err(CommandError::new(e.message(), None)),
|
||||
};
|
||||
|
||||
send_progress_on_long_task(self, Action::Create, || {
|
||||
check_workers_status(&kubeconfig, self.cloud_provider().credentials_environment_variables())
|
||||
})
|
||||
@@ -403,6 +420,7 @@ pub fn deploy_environment(
|
||||
kubernetes: &dyn Kubernetes,
|
||||
environment: &Environment,
|
||||
event_details: EventDetails,
|
||||
logger: &dyn Logger,
|
||||
) -> Result<(), EngineError> {
|
||||
let listeners_helper = ListenersHelper::new(kubernetes.listeners());
|
||||
|
||||
@@ -421,11 +439,6 @@ pub fn deploy_environment(
|
||||
},
|
||||
};
|
||||
|
||||
// Resources check before deploy
|
||||
// TODO(ENG-1066): we should check if env can be deployed or not based on required resources and available ones.
|
||||
// This check is not trivial since auto-scaler comes to play and resources distribution on nodes might not behave necesarly the way we think.
|
||||
// do not deploy if there is not enough resources
|
||||
|
||||
// create all stateful services (database)
|
||||
for service in &environment.stateful_services {
|
||||
let _ = service::check_kubernetes_service_error(
|
||||
@@ -433,6 +446,7 @@ pub fn deploy_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateful_deployment_target,
|
||||
&listeners_helper,
|
||||
"deployment",
|
||||
@@ -445,6 +459,7 @@ pub fn deploy_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateful_deployment_target,
|
||||
&listeners_helper,
|
||||
"check deployment",
|
||||
@@ -468,6 +483,7 @@ pub fn deploy_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateless_deployment_target,
|
||||
&listeners_helper,
|
||||
"deployment",
|
||||
@@ -485,6 +501,7 @@ pub fn deploy_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger.clone(),
|
||||
&stateless_deployment_target,
|
||||
&listeners_helper,
|
||||
"check deployment",
|
||||
@@ -501,6 +518,7 @@ pub fn deploy_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateless_deployment_target,
|
||||
&listeners_helper,
|
||||
"check deployment",
|
||||
@@ -516,6 +534,7 @@ pub fn deploy_environment_error(
|
||||
kubernetes: &dyn Kubernetes,
|
||||
environment: &Environment,
|
||||
event_details: EventDetails,
|
||||
logger: &dyn Logger,
|
||||
) -> Result<(), EngineError> {
|
||||
let listeners_helper = ListenersHelper::new(kubernetes.listeners());
|
||||
|
||||
@@ -540,6 +559,7 @@ pub fn deploy_environment_error(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateful_deployment_target,
|
||||
&listeners_helper,
|
||||
"revert deployment",
|
||||
@@ -563,6 +583,7 @@ pub fn deploy_environment_error(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateless_deployment_target,
|
||||
&listeners_helper,
|
||||
"revert deployment",
|
||||
@@ -578,6 +599,7 @@ pub fn pause_environment(
|
||||
kubernetes: &dyn Kubernetes,
|
||||
environment: &Environment,
|
||||
event_details: EventDetails,
|
||||
logger: &dyn Logger,
|
||||
) -> Result<(), EngineError> {
|
||||
let listeners_helper = ListenersHelper::new(kubernetes.listeners());
|
||||
|
||||
@@ -599,6 +621,7 @@ pub fn pause_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateless_deployment_target,
|
||||
&listeners_helper,
|
||||
"pause",
|
||||
@@ -616,6 +639,7 @@ pub fn pause_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateful_deployment_target,
|
||||
&listeners_helper,
|
||||
"pause",
|
||||
@@ -632,6 +656,7 @@ pub fn pause_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateless_deployment_target,
|
||||
&listeners_helper,
|
||||
"check pause",
|
||||
@@ -649,6 +674,7 @@ pub fn pause_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateful_deployment_target,
|
||||
&listeners_helper,
|
||||
"check pause",
|
||||
@@ -664,6 +690,7 @@ pub fn delete_environment(
|
||||
kubernetes: &dyn Kubernetes,
|
||||
environment: &Environment,
|
||||
event_details: EventDetails,
|
||||
logger: &dyn Logger,
|
||||
) -> Result<(), EngineError> {
|
||||
let listeners_helper = ListenersHelper::new(kubernetes.listeners());
|
||||
|
||||
@@ -685,6 +712,7 @@ pub fn delete_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateless_deployment_target,
|
||||
&listeners_helper,
|
||||
"delete",
|
||||
@@ -702,6 +730,7 @@ pub fn delete_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateful_deployment_target,
|
||||
&listeners_helper,
|
||||
"delete",
|
||||
@@ -718,6 +747,7 @@ pub fn delete_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateless_deployment_target,
|
||||
&listeners_helper,
|
||||
"delete check",
|
||||
@@ -735,6 +765,7 @@ pub fn delete_environment(
|
||||
kubernetes,
|
||||
service,
|
||||
event_details.clone(),
|
||||
logger,
|
||||
&stateful_deployment_target,
|
||||
&listeners_helper,
|
||||
"delete check",
|
||||
@@ -780,8 +811,12 @@ where
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new(
|
||||
format!("Encountering issues while trying to get objects kind {}.", object,),
|
||||
Some(e.message()),
|
||||
format!(
|
||||
"Encountering issues while trying to get objects kind {}: {:?}",
|
||||
object,
|
||||
e.message()
|
||||
),
|
||||
None,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -798,10 +833,7 @@ where
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Deleting(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"Failed to delete all {} objects, retrying...",
|
||||
object,
|
||||
)),
|
||||
EventMessage::new(format!("Failed to delete all {} objects, retrying...", object,), None),
|
||||
),
|
||||
);
|
||||
OperationResult::Retry(e)
|
||||
@@ -1043,7 +1075,7 @@ fn check_kubernetes_upgrade_status(
|
||||
return Err(EngineError::new_cannot_determine_k8s_requested_upgrade_version(
|
||||
event_details.clone(),
|
||||
requested_version.to_string(),
|
||||
Some(CommandError::new_from_safe_message(e)),
|
||||
Some(e),
|
||||
));
|
||||
}
|
||||
};
|
||||
@@ -1256,35 +1288,222 @@ impl NodeGroups {
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO(benjaminch): to be refactored with similar function in services.rs
|
||||
/// This function call (start|pause|delete)_in_progress function every 10 seconds when a
|
||||
/// long blocking task is running.
|
||||
pub fn send_progress_on_long_task<K, R, F>(kubernetes: &K, action: Action, long_task: F) -> R
|
||||
where
|
||||
K: Kubernetes + Listen,
|
||||
F: Fn() -> R,
|
||||
{
|
||||
let waiting_message = match action {
|
||||
Action::Create => Some(format!(
|
||||
"Infrastructure '{}' deployment is in progress...",
|
||||
kubernetes.name_with_id()
|
||||
)),
|
||||
Action::Pause => Some(format!(
|
||||
"Infrastructure '{}' pause is in progress...",
|
||||
kubernetes.name_with_id()
|
||||
)),
|
||||
Action::Delete => Some(format!(
|
||||
"Infrastructure '{}' deletion is in progress...",
|
||||
kubernetes.name_with_id()
|
||||
)),
|
||||
Action::Nothing => None,
|
||||
};
|
||||
|
||||
send_progress_on_long_task_with_message(kubernetes, waiting_message, action, long_task)
|
||||
}
|
||||
|
||||
/// TODO(benjaminch): to be refactored with similar function in services.rs
|
||||
/// This function call (start|pause|delete)_in_progress function every 10 seconds when a
|
||||
/// long blocking task is running.
|
||||
pub fn send_progress_on_long_task_with_message<K, R, F>(
|
||||
kubernetes: &K,
|
||||
waiting_message: Option<String>,
|
||||
action: Action,
|
||||
long_task: F,
|
||||
) -> R
|
||||
where
|
||||
K: Kubernetes + Listen,
|
||||
F: Fn() -> R,
|
||||
{
|
||||
let listeners = std::clone::Clone::clone(kubernetes.listeners());
|
||||
let logger = kubernetes.logger().clone_dyn();
|
||||
let event_details = kubernetes
|
||||
.get_event_details(Stage::Infrastructure(InfrastructureStep::Create))
|
||||
.clone();
|
||||
|
||||
let progress_info = ProgressInfo::new(
|
||||
ProgressScope::Infrastructure {
|
||||
execution_id: kubernetes.context().execution_id().to_string(),
|
||||
},
|
||||
Info,
|
||||
waiting_message.clone(),
|
||||
kubernetes.context().execution_id(),
|
||||
);
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
// monitor thread to notify user while the blocking task is executed
|
||||
let _ = std::thread::Builder::new()
|
||||
.name("task-monitor".to_string())
|
||||
.spawn(move || {
|
||||
// stop the thread when the blocking task is done
|
||||
let listeners_helper = ListenersHelper::new(&listeners);
|
||||
let action = action;
|
||||
let progress_info = progress_info;
|
||||
let waiting_message = waiting_message.unwrap_or("no message ...".to_string());
|
||||
|
||||
loop {
|
||||
// do notify users here
|
||||
let progress_info = std::clone::Clone::clone(&progress_info);
|
||||
let event_details = std::clone::Clone::clone(&event_details);
|
||||
let event_message = EventMessage::new_from_safe(waiting_message.to_string());
|
||||
|
||||
match action {
|
||||
Action::Create => {
|
||||
listeners_helper.deployment_in_progress(progress_info);
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deploying(
|
||||
EventDetails::clone_changing_stage(
|
||||
event_details,
|
||||
Stage::Infrastructure(InfrastructureStep::Create),
|
||||
),
|
||||
event_message,
|
||||
),
|
||||
);
|
||||
}
|
||||
Action::Pause => {
|
||||
listeners_helper.pause_in_progress(progress_info);
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Pausing(
|
||||
EventDetails::clone_changing_stage(
|
||||
event_details,
|
||||
Stage::Infrastructure(InfrastructureStep::Pause),
|
||||
),
|
||||
event_message,
|
||||
),
|
||||
);
|
||||
}
|
||||
Action::Delete => {
|
||||
listeners_helper.delete_in_progress(progress_info);
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
EventDetails::clone_changing_stage(
|
||||
event_details,
|
||||
Stage::Infrastructure(InfrastructureStep::Delete),
|
||||
),
|
||||
event_message,
|
||||
),
|
||||
);
|
||||
}
|
||||
Action::Nothing => {} // should not happens
|
||||
};
|
||||
|
||||
thread::sleep(Duration::from_secs(10));
|
||||
|
||||
// watch for thread termination
|
||||
match rx.try_recv() {
|
||||
Ok(_) | Err(TryRecvError::Disconnected) => break,
|
||||
Err(TryRecvError::Empty) => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let blocking_task_result = long_task();
|
||||
let _ = tx.send(());
|
||||
|
||||
blocking_task_result
|
||||
}
|
||||
|
||||
pub fn validate_k8s_required_cpu_and_burstable(
|
||||
listener_helper: &ListenersHelper,
|
||||
execution_id: &str,
|
||||
context_id: &str,
|
||||
total_cpu: String,
|
||||
cpu_burst: String,
|
||||
event_details: EventDetails,
|
||||
logger: &dyn Logger,
|
||||
) -> Result<CpuLimits, CommandError> {
|
||||
let total_cpu_float = convert_k8s_cpu_value_to_f32(total_cpu.clone())?;
|
||||
let cpu_burst_float = convert_k8s_cpu_value_to_f32(cpu_burst.clone())?;
|
||||
let mut set_cpu_burst = cpu_burst.clone();
|
||||
|
||||
if cpu_burst_float < total_cpu_float {
|
||||
let message = format!(
|
||||
"CPU burst value '{}' was lower than the desired total of CPUs {}, using burstable value.",
|
||||
cpu_burst, total_cpu,
|
||||
);
|
||||
|
||||
listener_helper.error(ProgressInfo::new(
|
||||
ProgressScope::Environment {
|
||||
id: execution_id.to_string(),
|
||||
},
|
||||
ProgressLevel::Warn,
|
||||
Some(message.to_string()),
|
||||
context_id,
|
||||
));
|
||||
|
||||
logger.log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(event_details, EventMessage::new_from_safe(message)),
|
||||
);
|
||||
|
||||
set_cpu_burst = total_cpu.clone();
|
||||
}
|
||||
|
||||
Ok(CpuLimits {
|
||||
cpu_limit: set_cpu_burst,
|
||||
cpu_request: total_cpu,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn convert_k8s_cpu_value_to_f32(value: String) -> Result<f32, CommandError> {
|
||||
if value.ends_with('m') {
|
||||
let mut value_number_string = value;
|
||||
value_number_string.pop();
|
||||
return match value_number_string.parse::<f32>() {
|
||||
Ok(n) => {
|
||||
Ok(n * 0.001) // return in milli cpu the value
|
||||
}
|
||||
Err(e) => Err(CommandError::new(
|
||||
e.to_string(),
|
||||
Some(format!(
|
||||
"Error while trying to parse `{}` to float 32.",
|
||||
value_number_string.as_str()
|
||||
)),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
match value.parse::<f32>() {
|
||||
Ok(n) => Ok(n),
|
||||
Err(e) => Err(CommandError::new(
|
||||
e.to_string(),
|
||||
Some(format!("Error while trying to parse `{}` to float 32.", value.as_str())),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::cloud_provider::Kind::Aws;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::cloud_provider::kubernetes::{
|
||||
check_kubernetes_upgrade_status, compare_kubernetes_cluster_versions_for_upgrade, KubernetesNodesType,
|
||||
check_kubernetes_upgrade_status, compare_kubernetes_cluster_versions_for_upgrade, convert_k8s_cpu_value_to_f32,
|
||||
validate_k8s_required_cpu_and_burstable, KubernetesNodesType,
|
||||
};
|
||||
use crate::cloud_provider::models::CpuLimits;
|
||||
use crate::cloud_provider::utilities::VersionsNumber;
|
||||
use crate::cmd::structs::{KubernetesList, KubernetesNode, KubernetesVersion};
|
||||
use crate::events::{EngineEvent, EventDetails, InfrastructureStep, Stage, Transmitter};
|
||||
use crate::logger::{LogLevel, Logger};
|
||||
use crate::models::QoveryIdentifier;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FakeLogger {}
|
||||
|
||||
impl FakeLogger {
|
||||
pub fn new() -> Self {
|
||||
FakeLogger {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Logger for FakeLogger {
|
||||
fn log(&self, _log_level: LogLevel, _event: EngineEvent) {}
|
||||
|
||||
fn clone_dyn(&self) -> Box<dyn Logger> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
use crate::events::{EventDetails, InfrastructureStep, Stage, Transmitter};
|
||||
use crate::logger::StdIoLogger;
|
||||
use crate::models::{ListenersHelper, QoveryIdentifier};
|
||||
|
||||
#[test]
|
||||
pub fn check_kubernetes_upgrade_method() {
|
||||
@@ -1299,7 +1518,7 @@ mod tests {
|
||||
Stage::Infrastructure(InfrastructureStep::Upgrade),
|
||||
Transmitter::Kubernetes(QoveryIdentifier::new_random().to_string(), "test".to_string()),
|
||||
);
|
||||
let logger = FakeLogger::new();
|
||||
let logger = StdIoLogger::new();
|
||||
|
||||
// test full cluster upgrade (masters + workers)
|
||||
let result = check_kubernetes_upgrade_status(
|
||||
@@ -1851,136 +2070,72 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO(benjaminch): to be refactored with similar function in services.rs
|
||||
/// This function call (start|pause|delete)_in_progress function every 10 seconds when a
|
||||
/// long blocking task is running.
|
||||
pub fn send_progress_on_long_task<K, R, F>(kubernetes: &K, action: Action, long_task: F) -> R
|
||||
where
|
||||
K: Kubernetes + Listen,
|
||||
F: Fn() -> R,
|
||||
{
|
||||
let waiting_message = match action {
|
||||
Action::Create => Some(format!(
|
||||
"Infrastructure '{}' deployment is in progress...",
|
||||
kubernetes.name_with_id()
|
||||
)),
|
||||
Action::Pause => Some(format!(
|
||||
"Infrastructure '{}' pause is in progress...",
|
||||
kubernetes.name_with_id()
|
||||
)),
|
||||
Action::Delete => Some(format!(
|
||||
"Infrastructure '{}' deletion is in progress...",
|
||||
kubernetes.name_with_id()
|
||||
)),
|
||||
Action::Nothing => None,
|
||||
};
|
||||
#[test]
|
||||
pub fn test_k8s_milli_cpu_convert() {
|
||||
let milli_cpu = "250m".to_string();
|
||||
let int_cpu = "2".to_string();
|
||||
|
||||
send_progress_on_long_task_with_message(kubernetes, waiting_message, action, long_task)
|
||||
}
|
||||
assert_eq!(convert_k8s_cpu_value_to_f32(milli_cpu).unwrap(), 0.25 as f32);
|
||||
assert_eq!(convert_k8s_cpu_value_to_f32(int_cpu).unwrap(), 2 as f32);
|
||||
}
|
||||
|
||||
/// TODO(benjaminch): to be refactored with similar function in services.rs
|
||||
/// This function call (start|pause|delete)_in_progress function every 10 seconds when a
|
||||
/// long blocking task is running.
|
||||
pub fn send_progress_on_long_task_with_message<K, R, F>(
|
||||
kubernetes: &K,
|
||||
waiting_message: Option<String>,
|
||||
action: Action,
|
||||
long_task: F,
|
||||
) -> R
|
||||
where
|
||||
K: Kubernetes + Listen,
|
||||
F: Fn() -> R,
|
||||
{
|
||||
let listeners = std::clone::Clone::clone(kubernetes.listeners());
|
||||
let logger = kubernetes.logger().clone_dyn();
|
||||
let event_details = kubernetes
|
||||
.get_event_details(Stage::Infrastructure(InfrastructureStep::Create))
|
||||
.clone(); // TODO(benjaminch): change the way event details is built, it's very dirty to make it mut and change the stage :(
|
||||
#[test]
|
||||
pub fn test_cpu_set() {
|
||||
let v = vec![];
|
||||
let listener_helper = ListenersHelper::new(&v);
|
||||
let logger = StdIoLogger::new();
|
||||
let execution_id = "execution_id";
|
||||
let context_id = "context_id";
|
||||
let organization_id = "organization_id";
|
||||
let cluster_id = "cluster_id";
|
||||
|
||||
let progress_info = ProgressInfo::new(
|
||||
ProgressScope::Infrastructure {
|
||||
execution_id: kubernetes.context().execution_id().to_string(),
|
||||
},
|
||||
Info,
|
||||
waiting_message.clone(),
|
||||
kubernetes.context().execution_id(),
|
||||
);
|
||||
let event_details = EventDetails::new(
|
||||
Some(Aws),
|
||||
QoveryIdentifier::new(organization_id.to_string()),
|
||||
QoveryIdentifier::new(cluster_id.to_string()),
|
||||
QoveryIdentifier::new(execution_id.to_string()),
|
||||
Some("region_fake".to_string()),
|
||||
Stage::Infrastructure(InfrastructureStep::LoadConfiguration),
|
||||
Transmitter::Kubernetes(cluster_id.to_string(), format!("{}-name", cluster_id)),
|
||||
);
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
// monitor thread to notify user while the blocking task is executed
|
||||
let _ = std::thread::Builder::new()
|
||||
.name("task-monitor".to_string())
|
||||
.spawn(move || {
|
||||
// stop the thread when the blocking task is done
|
||||
let listeners_helper = ListenersHelper::new(&listeners);
|
||||
let action = action;
|
||||
let progress_info = progress_info;
|
||||
let waiting_message = waiting_message.unwrap_or("no message ...".to_string());
|
||||
|
||||
loop {
|
||||
// do notify users here
|
||||
let progress_info = std::clone::Clone::clone(&progress_info);
|
||||
let event_details = std::clone::Clone::clone(&event_details);
|
||||
let event_message = EventMessage::new_from_safe(waiting_message.to_string());
|
||||
|
||||
match action {
|
||||
Action::Create => {
|
||||
listeners_helper.deployment_in_progress(progress_info);
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deploying(
|
||||
EventDetails::clone_changing_stage(
|
||||
event_details,
|
||||
Stage::Infrastructure(InfrastructureStep::Create),
|
||||
),
|
||||
event_message,
|
||||
),
|
||||
);
|
||||
}
|
||||
Action::Pause => {
|
||||
listeners_helper.pause_in_progress(progress_info);
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Pausing(
|
||||
EventDetails::clone_changing_stage(
|
||||
event_details,
|
||||
Stage::Infrastructure(InfrastructureStep::Pause),
|
||||
),
|
||||
event_message,
|
||||
),
|
||||
);
|
||||
}
|
||||
Action::Delete => {
|
||||
listeners_helper.delete_in_progress(progress_info);
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deleting(
|
||||
EventDetails::clone_changing_stage(
|
||||
event_details,
|
||||
Stage::Infrastructure(InfrastructureStep::Delete),
|
||||
),
|
||||
event_message,
|
||||
),
|
||||
);
|
||||
}
|
||||
Action::Nothing => {} // should not happens
|
||||
};
|
||||
|
||||
thread::sleep(Duration::from_secs(10));
|
||||
|
||||
// watch for thread termination
|
||||
match rx.try_recv() {
|
||||
Ok(_) | Err(TryRecvError::Disconnected) => break,
|
||||
Err(TryRecvError::Empty) => {}
|
||||
}
|
||||
let mut total_cpu = "0.25".to_string();
|
||||
let mut cpu_burst = "1".to_string();
|
||||
assert_eq!(
|
||||
validate_k8s_required_cpu_and_burstable(
|
||||
&listener_helper,
|
||||
execution_id,
|
||||
context_id,
|
||||
total_cpu,
|
||||
cpu_burst,
|
||||
event_details.clone(),
|
||||
&logger
|
||||
)
|
||||
.unwrap(),
|
||||
CpuLimits {
|
||||
cpu_request: "0.25".to_string(),
|
||||
cpu_limit: "1".to_string()
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
let blocking_task_result = long_task();
|
||||
let _ = tx.send(());
|
||||
|
||||
blocking_task_result
|
||||
total_cpu = "1".to_string();
|
||||
cpu_burst = "0.5".to_string();
|
||||
assert_eq!(
|
||||
validate_k8s_required_cpu_and_burstable(
|
||||
&listener_helper,
|
||||
execution_id,
|
||||
context_id,
|
||||
total_cpu,
|
||||
cpu_burst,
|
||||
event_details.clone(),
|
||||
&logger
|
||||
)
|
||||
.unwrap(),
|
||||
CpuLimits {
|
||||
cpu_request: "1".to_string(),
|
||||
cpu_limit: "1".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::cloud_provider::environment::Environment;
|
||||
use crate::cloud_provider::kubernetes::Kubernetes;
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EventDetails, Stage, ToTransmitter};
|
||||
use crate::models::{Context, Listen};
|
||||
|
||||
pub mod aws;
|
||||
@@ -21,7 +22,7 @@ pub mod scaleway;
|
||||
pub mod service;
|
||||
pub mod utilities;
|
||||
|
||||
pub trait CloudProvider: Listen {
|
||||
pub trait CloudProvider: Listen + ToTransmitter {
|
||||
fn context(&self) -> &Context;
|
||||
fn kind(&self) -> Kind;
|
||||
fn id(&self) -> &str;
|
||||
@@ -41,18 +42,8 @@ pub trait CloudProvider: Listen {
|
||||
/// environment variables to inject to generate Terraform files from templates
|
||||
fn tera_context_environment_variables(&self) -> Vec<(&str, &str)>;
|
||||
fn terraform_state_credentials(&self) -> &TerraformStateCredentials;
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::CloudProvider(self.id().to_string(), self.name().to_string())
|
||||
}
|
||||
fn engine_error(&self, cause: EngineErrorCause, message: String) -> EngineError {
|
||||
EngineError::new(
|
||||
cause,
|
||||
self.engine_error_scope(),
|
||||
self.context().execution_id(),
|
||||
Some(message),
|
||||
)
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn get_event_details(&self, stage: Stage) -> EventDetails;
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::str::FromStr;
|
||||
use tera::Context as TeraContext;
|
||||
|
||||
use crate::build_platform::Image;
|
||||
use crate::cloud_provider::kubernetes::validate_k8s_required_cpu_and_burstable;
|
||||
use crate::cloud_provider::models::{
|
||||
EnvironmentVariable, EnvironmentVariableDataTemplate, Storage, StorageDataTemplate,
|
||||
};
|
||||
@@ -12,14 +13,13 @@ use crate::cloud_provider::service::{
|
||||
scale_down_application, send_progress_on_long_task, Action, Application as CApplication, Create, Delete, Helm,
|
||||
Pause, Service, ServiceType, StatelessService,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{print_action, sanitize_name, validate_k8s_required_cpu_and_burstable};
|
||||
use crate::cloud_provider::utilities::{print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl::ScalingKind::{Deployment, Statefulset};
|
||||
use crate::error::EngineErrorCause::Internal;
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::errors::CommandError;
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::events::{EngineEvent, EnvironmentStep, EventMessage, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::{LogLevel, Logger};
|
||||
use crate::models::{Context, Listen, Listener, Listeners, ListenersHelper, Port};
|
||||
use ::function_name::named;
|
||||
|
||||
@@ -39,6 +39,7 @@ pub struct Application {
|
||||
storage: Vec<Storage<StorageType>>,
|
||||
environment_variables: Vec<EnvironmentVariable>,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
@@ -58,7 +59,8 @@ impl Application {
|
||||
storage: Vec<Storage<StorageType>>,
|
||||
environment_variables: Vec<EnvironmentVariable>,
|
||||
listeners: Listeners,
|
||||
) -> Application {
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Application {
|
||||
context,
|
||||
id: id.to_string(),
|
||||
@@ -75,6 +77,7 @@ impl Application {
|
||||
storage,
|
||||
environment_variables,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,6 +199,7 @@ impl Service for Application {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
@@ -210,9 +214,15 @@ impl Service for Application {
|
||||
),
|
||||
None => {
|
||||
let image_name_with_tag = self.image().name_with_tag();
|
||||
warn!(
|
||||
"there is no registry url, use image name with tag with the default container registry: {}",
|
||||
image_name_with_tag.as_str()
|
||||
self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new_from_safe(format!(
|
||||
"there is no registry url, use image name with tag with the default container registry: {}",
|
||||
image_name_with_tag.as_str()
|
||||
)),
|
||||
),
|
||||
);
|
||||
context.insert("image_name_with_tag", image_name_with_tag.as_str());
|
||||
}
|
||||
@@ -246,14 +256,16 @@ impl Service for Application {
|
||||
&self.id,
|
||||
self.total_cpus(),
|
||||
self.cpu_burst(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
) {
|
||||
Ok(l) => l,
|
||||
Err(e) => {
|
||||
return Err(EngineError::new(
|
||||
Internal,
|
||||
EngineErrorScope::Application(self.id().to_string(), self.name().to_string()),
|
||||
self.context.execution_id(),
|
||||
Some(e.to_string()),
|
||||
return Err(EngineError::new_k8s_validate_required_cpu_and_burstable_error(
|
||||
event_details.clone(),
|
||||
self.total_cpus(),
|
||||
self.cpu_burst(),
|
||||
e,
|
||||
));
|
||||
}
|
||||
};
|
||||
@@ -310,19 +322,22 @@ impl Service for Application {
|
||||
Some(format!("appId={}", self.id))
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Application(self.id().to_string(), self.name().to_string())
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
}
|
||||
|
||||
impl Create for Application {
|
||||
#[named]
|
||||
fn on_create(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
@@ -336,11 +351,14 @@ impl Create for Application {
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
@@ -352,11 +370,14 @@ impl Create for Application {
|
||||
impl Pause for Application {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -375,11 +396,14 @@ impl Pause for Application {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -395,6 +419,8 @@ impl Delete for Application {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
@@ -414,6 +440,8 @@ impl Delete for Application {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
|
||||
@@ -3,14 +3,15 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{get_self_hosted_mongodb_version, print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
@@ -28,6 +29,7 @@ pub struct MongoDB {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl MongoDB {
|
||||
@@ -44,6 +46,7 @@ impl MongoDB {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
MongoDB {
|
||||
context,
|
||||
@@ -58,11 +61,17 @@ impl MongoDB {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self) -> Result<String, EngineError> {
|
||||
check_service_version(get_self_hosted_mongodb_version(self.version()), self)
|
||||
fn matching_correct_version(&self, event_details: EventDetails) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
get_self_hosted_mongodb_version(self.version()),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn cloud_provider_name(&self) -> &str {
|
||||
@@ -152,18 +161,15 @@ impl Service for MongoDB {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -174,7 +180,7 @@ impl Service for MongoDB {
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
|
||||
let version = self.matching_correct_version()?;
|
||||
let version = self.matching_correct_version(event_details.clone())?.matched_version();
|
||||
context.insert("version", &version);
|
||||
|
||||
for (k, v) in kubernetes.cloud_provider().tera_context_environment_variables() {
|
||||
@@ -215,16 +221,12 @@ impl Service for MongoDB {
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn selector(&self) -> Option<String> {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,24 +273,35 @@ impl Create for MongoDB {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
deploy_stateful_service(target, self, event_details.clone())
|
||||
deploy_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
self.check_domains(self.listeners.clone(), vec![self.fqdn.as_str()])
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
self.check_domains(
|
||||
self.listeners.clone(),
|
||||
vec![self.fqdn.as_str()],
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -297,11 +310,14 @@ impl Create for MongoDB {
|
||||
impl Pause for MongoDB {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -315,11 +331,14 @@ impl Pause for MongoDB {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -335,10 +354,12 @@ impl Delete for MongoDB {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
delete_stateful_service(target, self, event_details.clone())
|
||||
delete_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -348,11 +369,14 @@ impl Delete for MongoDB {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{
|
||||
get_self_hosted_mysql_version, get_supported_version_to_use, print_action, sanitize_name, VersionsNumber,
|
||||
@@ -11,13 +11,13 @@ use crate::cloud_provider::utilities::{
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope, StringError};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub struct MySQL {
|
||||
context: Context,
|
||||
@@ -32,6 +32,7 @@ pub struct MySQL {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl MySQL {
|
||||
@@ -48,6 +49,7 @@ impl MySQL {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Self {
|
||||
context,
|
||||
@@ -62,21 +64,24 @@ impl MySQL {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self, is_managed_services: bool) -> Result<VersionsNumber, EngineError> {
|
||||
let version = check_service_version(Self::pick_mysql_version(self.version(), is_managed_services), self)?;
|
||||
match VersionsNumber::from_str(version.as_str()) {
|
||||
Ok(res) => Ok(res),
|
||||
Err(e) => Err(self.engine_error(
|
||||
EngineErrorCause::Internal,
|
||||
format!("cannot parse database version, err: {}", e),
|
||||
)),
|
||||
}
|
||||
fn matching_correct_version(
|
||||
&self,
|
||||
is_managed_services: bool,
|
||||
event_details: EventDetails,
|
||||
) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
Self::pick_mysql_version(self.version(), is_managed_services),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn pick_mysql_version(requested_version: String, is_managed_service: bool) -> Result<String, StringError> {
|
||||
fn pick_mysql_version(requested_version: String, is_managed_service: bool) -> Result<String, CommandError> {
|
||||
if is_managed_service {
|
||||
Self::pick_managed_mysql_version(requested_version)
|
||||
} else {
|
||||
@@ -84,7 +89,7 @@ impl MySQL {
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_managed_mysql_version(requested_version: String) -> Result<String, StringError> {
|
||||
fn pick_managed_mysql_version(requested_version: String) -> Result<String, CommandError> {
|
||||
// Scaleway supported MySQL versions
|
||||
// https://api.scaleway.com/rdb/v1/regions/fr-par/database-engines
|
||||
let mut supported_mysql_versions = HashMap::new();
|
||||
@@ -183,18 +188,14 @@ impl Service for MySQL {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -205,7 +206,9 @@ impl Service for MySQL {
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
|
||||
let version = &self.matching_correct_version(self.is_managed_service())?;
|
||||
let version = &self
|
||||
.matching_correct_version(self.is_managed_service(), event_details.clone())?
|
||||
.matched_version();
|
||||
context.insert("version_major", &version.to_major_version_string());
|
||||
context.insert("version", &version.to_string()); // Scaleway needs to have major version only
|
||||
|
||||
@@ -256,12 +259,8 @@ impl Service for MySQL {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,24 +307,35 @@ impl Create for MySQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
deploy_stateful_service(target, self, event_details.clone())
|
||||
deploy_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
self.check_domains(self.listeners.clone(), vec![self.fqdn.as_str()])
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
self.check_domains(
|
||||
self.listeners.clone(),
|
||||
vec![self.fqdn.as_str()],
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -335,11 +345,14 @@ impl Create for MySQL {
|
||||
impl Pause for MySQL {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -353,11 +366,14 @@ impl Pause for MySQL {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -373,10 +389,12 @@ impl Delete for MySQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
delete_stateful_service(target, self, event_details.clone())
|
||||
delete_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -386,11 +404,14 @@ impl Delete for MySQL {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{
|
||||
get_self_hosted_postgres_version, get_supported_version_to_use, print_action, sanitize_name, VersionsNumber,
|
||||
@@ -11,13 +11,13 @@ use crate::cloud_provider::utilities::{
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope, StringError};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub struct PostgreSQL {
|
||||
context: Context,
|
||||
@@ -32,6 +32,7 @@ pub struct PostgreSQL {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl PostgreSQL {
|
||||
@@ -48,6 +49,7 @@ impl PostgreSQL {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Self {
|
||||
context,
|
||||
@@ -62,21 +64,24 @@ impl PostgreSQL {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self, is_managed_services: bool) -> Result<VersionsNumber, EngineError> {
|
||||
let version = check_service_version(Self::pick_postgres_version(self.version(), is_managed_services), self)?;
|
||||
match VersionsNumber::from_str(version.as_str()) {
|
||||
Ok(res) => Ok(res),
|
||||
Err(e) => Err(self.engine_error(
|
||||
EngineErrorCause::Internal,
|
||||
format!("cannot parse database version, err: {}", e),
|
||||
)),
|
||||
}
|
||||
fn matching_correct_version(
|
||||
&self,
|
||||
is_managed_services: bool,
|
||||
event_details: EventDetails,
|
||||
) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
Self::pick_postgres_version(self.version(), is_managed_services),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn pick_postgres_version(requested_version: String, is_managed_service: bool) -> Result<String, StringError> {
|
||||
fn pick_postgres_version(requested_version: String, is_managed_service: bool) -> Result<String, CommandError> {
|
||||
if is_managed_service {
|
||||
Self::pick_managed_postgres_version(requested_version)
|
||||
} else {
|
||||
@@ -84,7 +89,7 @@ impl PostgreSQL {
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_managed_postgres_version(requested_version: String) -> Result<String, StringError> {
|
||||
fn pick_managed_postgres_version(requested_version: String) -> Result<String, CommandError> {
|
||||
// Scaleway supported postgres versions
|
||||
// https://api.scaleway.com/rdb/v1/regions/fr-par/database-engines
|
||||
let mut supported_postgres_versions = HashMap::new();
|
||||
@@ -192,18 +197,14 @@ impl Service for PostgreSQL {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -214,7 +215,9 @@ impl Service for PostgreSQL {
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
|
||||
let version = &self.matching_correct_version(self.is_managed_service())?;
|
||||
let version = &self
|
||||
.matching_correct_version(self.is_managed_service(), event_details.clone())?
|
||||
.matched_version();
|
||||
context.insert("version_major", &version.to_major_version_string());
|
||||
context.insert("version", &version.to_string()); // Scaleway needs to have major version only
|
||||
|
||||
@@ -265,12 +268,8 @@ impl Service for PostgreSQL {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,24 +316,35 @@ impl Create for PostgreSQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
deploy_stateful_service(target, self, event_details.clone())
|
||||
deploy_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
self.check_domains(self.listeners.clone(), vec![self.fqdn.as_str()])
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
self.check_domains(
|
||||
self.listeners.clone(),
|
||||
vec![self.fqdn.as_str()],
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -344,11 +354,14 @@ impl Create for PostgreSQL {
|
||||
impl Pause for PostgreSQL {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -362,11 +375,14 @@ impl Pause for PostgreSQL {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -382,10 +398,12 @@ impl Delete for PostgreSQL {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
delete_stateful_service(target, self, event_details.clone())
|
||||
delete_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -395,11 +413,14 @@ impl Delete for PostgreSQL {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3,14 +3,15 @@ use tera::Context as TeraContext;
|
||||
use crate::cloud_provider::service::{
|
||||
check_service_version, default_tera_context, delete_stateful_service, deploy_stateful_service, get_tfstate_name,
|
||||
get_tfstate_suffix, scale_down_database, send_progress_on_long_task, Action, Create, Database, DatabaseOptions,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, StatefulService, Terraform,
|
||||
DatabaseType, Delete, Helm, Pause, Service, ServiceType, ServiceVersionCheckResult, StatefulService, Terraform,
|
||||
};
|
||||
use crate::cloud_provider::utilities::{get_self_hosted_redis_version, print_action, sanitize_name};
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::cmd::kubectl;
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::Logger;
|
||||
use crate::models::DatabaseMode::MANAGED;
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
@@ -28,6 +29,7 @@ pub struct Redis {
|
||||
database_instance_type: String,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl Redis {
|
||||
@@ -44,6 +46,7 @@ impl Redis {
|
||||
database_instance_type: &str,
|
||||
options: DatabaseOptions,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Self {
|
||||
context,
|
||||
@@ -58,11 +61,17 @@ impl Redis {
|
||||
database_instance_type: database_instance_type.to_string(),
|
||||
options,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
fn matching_correct_version(&self) -> Result<String, EngineError> {
|
||||
check_service_version(get_self_hosted_redis_version(self.version()), self)
|
||||
fn matching_correct_version(&self, event_details: EventDetails) -> Result<ServiceVersionCheckResult, EngineError> {
|
||||
check_service_version(
|
||||
get_self_hosted_redis_version(self.version()),
|
||||
self,
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
fn cloud_provider_name(&self) -> &str {
|
||||
@@ -152,18 +161,14 @@ impl Service for Redis {
|
||||
}
|
||||
|
||||
fn tera_context(&self, target: &DeploymentTarget) -> Result<TeraContext, EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::LoadConfiguration));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
|
||||
let mut context = default_tera_context(self, kubernetes, environment);
|
||||
|
||||
// we need the kubernetes config file to store tfstates file in kube secrets
|
||||
let kube_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
return Err(e.to_legacy_engine_error());
|
||||
}
|
||||
};
|
||||
let kube_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
context.insert("kubeconfig_path", &kube_config_file_path);
|
||||
|
||||
kubectl::kubectl_exec_create_namespace_without_labels(
|
||||
@@ -172,7 +177,7 @@ impl Service for Redis {
|
||||
kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
);
|
||||
|
||||
let version = self.matching_correct_version()?;
|
||||
let version = self.matching_correct_version(event_details.clone())?.matched_version();
|
||||
|
||||
context.insert("namespace", environment.namespace());
|
||||
context.insert("version", &version);
|
||||
@@ -218,12 +223,8 @@ impl Service for Redis {
|
||||
Some(format!("app={}", self.sanitized_name()))
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Database(
|
||||
self.id().to_string(),
|
||||
self.service_type().name().to_string(),
|
||||
self.name().to_string(),
|
||||
)
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,24 +271,35 @@ impl Create for Redis {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
deploy_stateful_service(target, self, event_details.clone())
|
||||
deploy_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
self.check_domains(self.listeners.clone(), vec![self.fqdn.as_str()])
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
self.check_domains(
|
||||
self.listeners.clone(),
|
||||
vec![self.fqdn.as_str()],
|
||||
event_details,
|
||||
self.logger(),
|
||||
)
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -296,11 +308,14 @@ impl Create for Redis {
|
||||
impl Pause for Redis {
|
||||
#[named]
|
||||
fn on_pause(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Pause, || {
|
||||
@@ -314,11 +329,14 @@ impl Pause for Redis {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -333,10 +351,12 @@ impl Delete for Redis {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Delete, || {
|
||||
delete_stateful_service(target, self, event_details.clone())
|
||||
delete_stateful_service(target, self, event_details.clone(), self.logger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -346,11 +366,14 @@ impl Delete for Redis {
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ impl<'a> Kapsule<'a> {
|
||||
e,
|
||||
);
|
||||
|
||||
logger.log(LogLevel::Error, EngineEvent::Error(err.clone()));
|
||||
logger.log(LogLevel::Error, EngineEvent::Error(err.clone(), None));
|
||||
|
||||
return Err(err);
|
||||
}
|
||||
@@ -395,14 +395,17 @@ impl<'a> Kapsule<'a> {
|
||||
|
||||
self.logger.log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Error(EngineError::new_missing_workers_group_info_error(
|
||||
event_details,
|
||||
CommandError::new_from_safe_message(format!(
|
||||
"Missing node pool info {} for cluster {}",
|
||||
name,
|
||||
self.context.cluster_id()
|
||||
)),
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_missing_workers_group_info_error(
|
||||
event_details,
|
||||
CommandError::new_from_safe_message(format!(
|
||||
"Missing node pool info {} for cluster {}",
|
||||
name,
|
||||
self.context.cluster_id()
|
||||
)),
|
||||
),
|
||||
None,
|
||||
),
|
||||
);
|
||||
|
||||
if item.is_none() {
|
||||
@@ -550,10 +553,13 @@ impl<'a> Kapsule<'a> {
|
||||
Some(secret_id) => context.insert("vault_secret_id", secret_id.to_str().unwrap()),
|
||||
None => self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Error(EngineError::new_missing_required_env_variable(
|
||||
event_details.clone(),
|
||||
"VAULT_SECRET_ID".to_string(),
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_missing_required_env_variable(
|
||||
event_details.clone(),
|
||||
"VAULT_SECRET_ID".to_string(),
|
||||
),
|
||||
None,
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -635,7 +641,7 @@ impl<'a> Kapsule<'a> {
|
||||
)
|
||||
}
|
||||
Err(e) => {
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e));
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e, None));
|
||||
self.logger().log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Deploying(
|
||||
@@ -726,10 +732,10 @@ impl<'a> Kapsule<'a> {
|
||||
}
|
||||
Err(e) => self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Error(EngineError::new_terraform_state_does_not_exist(
|
||||
event_details.clone(),
|
||||
e,
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_terraform_state_does_not_exist(event_details.clone(), e),
|
||||
None,
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
@@ -751,7 +757,8 @@ impl<'a> Kapsule<'a> {
|
||||
self.kubeconfig_bucket_name(),
|
||||
CommandError::new(e.message.unwrap_or("No error message".to_string()), None),
|
||||
);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
@@ -762,7 +769,8 @@ impl<'a> Kapsule<'a> {
|
||||
self.logs_bucket_name(),
|
||||
CommandError::new(e.message.unwrap_or("No error message".to_string()), None),
|
||||
);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
@@ -793,7 +801,8 @@ impl<'a> Kapsule<'a> {
|
||||
kubeconfig_name.to_string(),
|
||||
CommandError::new(e.message.unwrap_or("No error message".to_string()), None),
|
||||
);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
@@ -912,14 +921,14 @@ impl<'a> Kapsule<'a> {
|
||||
Some(c),
|
||||
);
|
||||
self.logger
|
||||
.log(LogLevel::Error, EngineEvent::Error(current_error.clone()));
|
||||
.log(LogLevel::Error, EngineEvent::Error(current_error.clone(), None));
|
||||
OperationResult::Retry(current_error)
|
||||
}
|
||||
ScwNodeGroupErrors::ClusterDoesNotExists(c) => {
|
||||
let current_error =
|
||||
EngineError::new_no_cluster_found_error(event_details.clone(), c);
|
||||
self.logger
|
||||
.log(LogLevel::Error, EngineEvent::Error(current_error.clone()));
|
||||
.log(LogLevel::Error, EngineEvent::Error(current_error.clone(), None));
|
||||
OperationResult::Retry(current_error)
|
||||
}
|
||||
ScwNodeGroupErrors::MultipleClusterFound => {
|
||||
@@ -943,7 +952,7 @@ impl<'a> Kapsule<'a> {
|
||||
Some(c),
|
||||
);
|
||||
self.logger
|
||||
.log(LogLevel::Error, EngineEvent::Error(current_error.clone()));
|
||||
.log(LogLevel::Error, EngineEvent::Error(current_error.clone(), None));
|
||||
OperationResult::Retry(current_error)
|
||||
}
|
||||
}
|
||||
@@ -1191,7 +1200,8 @@ impl<'a> Kapsule<'a> {
|
||||
}
|
||||
Err(e) => {
|
||||
let error = EngineError::new_terraform_state_does_not_exist(event_details.clone(), e);
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(error.clone()));
|
||||
self.logger()
|
||||
.log(LogLevel::Error, EngineEvent::Error(error.clone(), None));
|
||||
return Err(error);
|
||||
}
|
||||
};
|
||||
@@ -1399,10 +1409,10 @@ impl<'a> Kapsule<'a> {
|
||||
// An issue occurred during the apply before destroy of Terraform, it may be expected if you're resuming a destroy
|
||||
self.logger().log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Error(EngineError::new_terraform_error_while_executing_pipeline(
|
||||
event_details.clone(),
|
||||
e,
|
||||
)),
|
||||
EngineEvent::Error(
|
||||
EngineError::new_terraform_error_while_executing_pipeline(event_details.clone(), e),
|
||||
None,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1759,22 +1769,28 @@ impl<'a> Kubernetes for Kapsule<'a> {
|
||||
|
||||
#[named]
|
||||
fn on_create(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Create));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.create())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Create));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.create_error())
|
||||
}
|
||||
@@ -1811,7 +1827,7 @@ impl<'a> Kubernetes for Kapsule<'a> {
|
||||
self.cloud_provider().credentials_environment_variables(),
|
||||
Stage::Infrastructure(InfrastructureStep::Upgrade),
|
||||
) {
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e.clone()));
|
||||
self.logger().log(LogLevel::Error, EngineEvent::Error(e.clone(), None));
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
@@ -1911,88 +1927,112 @@ impl<'a> Kubernetes for Kapsule<'a> {
|
||||
|
||||
#[named]
|
||||
fn on_upgrade(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Upgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.upgrade())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_upgrade_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Upgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.upgrade_error())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_downgrade(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Downgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.downgrade())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_downgrade_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Downgrade));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Create, || self.downgrade_error())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_pause(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Pause, || self.pause())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Pause, || self.pause_error())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_delete(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Delete, || self.delete())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn on_delete_error(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Infrastructure(InfrastructureStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
send_progress_on_long_task(self, Action::Delete, || self.delete_error())
|
||||
}
|
||||
@@ -2005,8 +2045,10 @@ impl<'a> Kubernetes for Kapsule<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::deploy_environment(self, environment, event_details)
|
||||
kubernetes::deploy_environment(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
@@ -2017,8 +2059,10 @@ impl<'a> Kubernetes for Kapsule<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::deploy_environment_error(self, environment, event_details)
|
||||
kubernetes::deploy_environment_error(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
@@ -2029,17 +2073,22 @@ impl<'a> Kubernetes for Kapsule<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::pause_environment(self, environment, event_details)
|
||||
kubernetes::pause_environment(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn pause_environment_error(&self, _environment: &Environment) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -2052,17 +2101,22 @@ impl<'a> Kubernetes for Kapsule<'a> {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
kubernetes::delete_environment(self, environment, event_details)
|
||||
kubernetes::delete_environment(self, environment, event_details, self.logger())
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn delete_environment_error(&self, _environment: &Environment) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Delete));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ use uuid::Uuid;
|
||||
|
||||
use crate::cloud_provider::{CloudProvider, EngineError, Kind, TerraformStateCredentials};
|
||||
use crate::constants::{SCALEWAY_ACCESS_KEY, SCALEWAY_DEFAULT_PROJECT_ID, SCALEWAY_SECRET_KEY};
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use crate::events::{EventDetails, Stage, ToTransmitter, Transmitter};
|
||||
use crate::models::{Context, Listen, Listener, Listeners, QoveryIdentifier};
|
||||
|
||||
pub mod application;
|
||||
pub mod databases;
|
||||
@@ -119,6 +120,19 @@ impl CloudProvider for Scaleway {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn get_event_details(&self, stage: Stage) -> EventDetails {
|
||||
let context = self.context();
|
||||
EventDetails::new(
|
||||
None,
|
||||
QoveryIdentifier::from(context.organization_id().to_string()),
|
||||
QoveryIdentifier::from(context.cluster_id().to_string()),
|
||||
QoveryIdentifier::from(context.execution_id().to_string()),
|
||||
None,
|
||||
stage,
|
||||
self.to_transmitter(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Listen for Scaleway {
|
||||
@@ -130,3 +144,9 @@ impl Listen for Scaleway {
|
||||
self.listeners.push(listener);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTransmitter for Scaleway {
|
||||
fn to_transmitter(&self) -> Transmitter {
|
||||
Transmitter::CloudProvider(self.id.to_string(), self.name.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ use crate::cloud_provider::utilities::{check_cname_for, print_action, sanitize_n
|
||||
use crate::cloud_provider::DeploymentTarget;
|
||||
use crate::cmd::helm;
|
||||
use crate::cmd::helm::Timeout;
|
||||
use crate::error::{EngineError, EngineErrorScope};
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
use crate::events::{EnvironmentStep, Stage, ToTransmitter, Transmitter};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{EngineEvent, EnvironmentStep, EventMessage, Stage, ToTransmitter, Transmitter};
|
||||
use crate::logger::{LogLevel, Logger};
|
||||
use crate::models::{Context, Listen, Listener, Listeners};
|
||||
use ::function_name::named;
|
||||
|
||||
@@ -26,6 +26,7 @@ pub struct Router {
|
||||
sticky_sessions_enabled: bool,
|
||||
routes: Vec<Route>,
|
||||
listeners: Listeners,
|
||||
logger: Box<dyn Logger>,
|
||||
}
|
||||
|
||||
impl Router {
|
||||
@@ -39,7 +40,8 @@ impl Router {
|
||||
routes: Vec<Route>,
|
||||
sticky_sessions_enabled: bool,
|
||||
listeners: Listeners,
|
||||
) -> Router {
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Self {
|
||||
Router {
|
||||
context,
|
||||
id: id.to_string(),
|
||||
@@ -50,6 +52,7 @@ impl Router {
|
||||
sticky_sessions_enabled,
|
||||
routes,
|
||||
listeners,
|
||||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,8 +198,8 @@ impl Service for Router {
|
||||
Some(format!("routerId={}", self.id))
|
||||
}
|
||||
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::Router(self.id().to_string(), self.name().to_string())
|
||||
fn logger(&self) -> &dyn Logger {
|
||||
&*self.logger
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,23 +262,22 @@ impl ToTransmitter for Router {
|
||||
impl Create for Router {
|
||||
#[named]
|
||||
fn on_create(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
let kubernetes = target.kubernetes;
|
||||
let environment = target.environment;
|
||||
|
||||
let workspace_dir = self.workspace_directory();
|
||||
let helm_release_name = self.helm_release_name();
|
||||
|
||||
let kubernetes_config_file_path = match kubernetes.get_kubeconfig_file_path() {
|
||||
Ok(p) => p,
|
||||
Err(e) => return Err(e.to_legacy_engine_error()),
|
||||
};
|
||||
let kubernetes_config_file_path = kubernetes.get_kubeconfig_file_path()?;
|
||||
|
||||
// respect order - getting the context here and not before is mandatory
|
||||
// the nginx-ingress must be available to get the external dns target if necessary
|
||||
@@ -285,13 +287,12 @@ impl Create for Router {
|
||||
if let Err(e) =
|
||||
crate::template::generate_and_copy_all_files_into_dir(from_dir.as_str(), workspace_dir.as_str(), context)
|
||||
{
|
||||
return Err(NewEngineError::new_cannot_copy_files_from_one_directory_to_another(
|
||||
return Err(EngineError::new_cannot_copy_files_from_one_directory_to_another(
|
||||
event_details.clone(),
|
||||
from_dir.to_string(),
|
||||
workspace_dir.to_string(),
|
||||
e,
|
||||
)
|
||||
.to_legacy_engine_error());
|
||||
));
|
||||
}
|
||||
|
||||
// do exec helm upgrade and return the last deployment status
|
||||
@@ -299,7 +300,8 @@ impl Create for Router {
|
||||
&kubernetes_config_file_path,
|
||||
&kubernetes.cloud_provider().credentials_environment_variables(),
|
||||
)
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())?;
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e))?;
|
||||
|
||||
let chart = ChartInfo::new_from_custom_namespace(
|
||||
helm_release_name,
|
||||
workspace_dir.clone(),
|
||||
@@ -314,12 +316,14 @@ impl Create for Router {
|
||||
);
|
||||
|
||||
helm.upgrade(&chart, &vec![])
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e).to_legacy_engine_error())
|
||||
.map_err(|e| helm::to_engine_error(&event_details, e))
|
||||
}
|
||||
|
||||
fn on_create_check(&self) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
|
||||
// check non custom domains
|
||||
self.check_domains()?;
|
||||
self.check_domains(event_details.clone(), self.logger())?;
|
||||
|
||||
// Wait/Check that custom domain is a CNAME targeting qovery
|
||||
for domain_to_check in self.custom_domains.iter() {
|
||||
@@ -333,9 +337,19 @@ impl Create for Router {
|
||||
continue
|
||||
}
|
||||
Ok(err) | Err(err) => {
|
||||
warn!(
|
||||
"Invalid CNAME for {}. Might not be an issue if user is using a CDN: {}",
|
||||
domain_to_check.domain, err
|
||||
// TODO(benjaminch): Handle better this one via a proper error eventually
|
||||
self.logger().log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(
|
||||
event_details.clone(),
|
||||
EventMessage::new(
|
||||
format!(
|
||||
"Invalid CNAME for {}. Might not be an issue if user is using a CDN.",
|
||||
domain_to_check.domain,
|
||||
),
|
||||
Some(err.to_string()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -346,11 +360,14 @@ impl Create for Router {
|
||||
|
||||
#[named]
|
||||
fn on_create_error(&self, target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Deploy));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
|
||||
send_progress_on_long_task(self, crate::cloud_provider::service::Action::Create, || {
|
||||
@@ -362,11 +379,14 @@ impl Create for Router {
|
||||
impl Pause for Router {
|
||||
#[named]
|
||||
fn on_pause(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -377,11 +397,14 @@ impl Pause for Router {
|
||||
|
||||
#[named]
|
||||
fn on_pause_error(&self, _target: &DeploymentTarget) -> Result<(), EngineError> {
|
||||
let event_details = self.get_event_details(Stage::Environment(EnvironmentStep::Pause));
|
||||
print_action(
|
||||
self.cloud_provider_name(),
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details,
|
||||
self.logger(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -396,6 +419,8 @@ impl Delete for Router {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
delete_router(target, self, false, event_details)
|
||||
}
|
||||
@@ -412,6 +437,8 @@ impl Delete for Router {
|
||||
self.struct_name(),
|
||||
function_name!(),
|
||||
self.name(),
|
||||
event_details.clone(),
|
||||
self.logger(),
|
||||
);
|
||||
delete_router(target, self, true, event_details)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::cloud_provider::models::CpuLimits;
|
||||
use crate::error::{EngineError, StringError};
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::events::{EngineEvent, EventDetails, EventMessage};
|
||||
use crate::logger::{LogLevel, Logger};
|
||||
use crate::models::{Listeners, ListenersHelper, ProgressInfo, ProgressLevel, ProgressScope};
|
||||
use chrono::Duration;
|
||||
use core::option::Option::{None, Some};
|
||||
@@ -11,13 +12,12 @@ use retry::delay::Fixed;
|
||||
use retry::OperationResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::num::ParseFloatError;
|
||||
use std::str::FromStr;
|
||||
use trust_dns_resolver::config::*;
|
||||
use trust_dns_resolver::proto::rr::{RData, RecordType};
|
||||
use trust_dns_resolver::Resolver;
|
||||
|
||||
pub fn get_self_hosted_postgres_version(requested_version: String) -> Result<String, StringError> {
|
||||
pub fn get_self_hosted_postgres_version(requested_version: String) -> Result<String, CommandError> {
|
||||
let mut supported_postgres_versions = HashMap::new();
|
||||
|
||||
// https://hub.docker.com/r/bitnami/postgresql/tags?page=1&ordering=last_updated
|
||||
@@ -41,7 +41,7 @@ pub fn get_self_hosted_postgres_version(requested_version: String) -> Result<Str
|
||||
get_supported_version_to_use("Postgresql", supported_postgres_versions, requested_version)
|
||||
}
|
||||
|
||||
pub fn get_self_hosted_mysql_version(requested_version: String) -> Result<String, StringError> {
|
||||
pub fn get_self_hosted_mysql_version(requested_version: String) -> Result<String, CommandError> {
|
||||
let mut supported_mysql_versions = HashMap::new();
|
||||
// https://hub.docker.com/r/bitnami/mysql/tags?page=1&ordering=last_updated
|
||||
|
||||
@@ -56,7 +56,7 @@ pub fn get_self_hosted_mysql_version(requested_version: String) -> Result<String
|
||||
get_supported_version_to_use("MySQL", supported_mysql_versions, requested_version)
|
||||
}
|
||||
|
||||
pub fn get_self_hosted_mongodb_version(requested_version: String) -> Result<String, StringError> {
|
||||
pub fn get_self_hosted_mongodb_version(requested_version: String) -> Result<String, CommandError> {
|
||||
let mut supported_mongodb_versions = HashMap::new();
|
||||
|
||||
// https://hub.docker.com/r/bitnami/mongodb/tags?page=1&ordering=last_updated
|
||||
@@ -80,7 +80,7 @@ pub fn get_self_hosted_mongodb_version(requested_version: String) -> Result<Stri
|
||||
get_supported_version_to_use("MongoDB", supported_mongodb_versions, requested_version)
|
||||
}
|
||||
|
||||
pub fn get_self_hosted_redis_version(requested_version: String) -> Result<String, StringError> {
|
||||
pub fn get_self_hosted_redis_version(requested_version: String) -> Result<String, CommandError> {
|
||||
let mut supported_redis_versions = HashMap::with_capacity(4);
|
||||
// https://hub.docker.com/r/bitnami/redis/tags?page=1&ordering=last_updated
|
||||
|
||||
@@ -96,11 +96,8 @@ pub fn get_supported_version_to_use(
|
||||
database_name: &str,
|
||||
all_supported_versions: HashMap<String, String>,
|
||||
version_to_check: String,
|
||||
) -> Result<String, StringError> {
|
||||
let version = match VersionsNumber::from_str(version_to_check.as_str()) {
|
||||
Ok(version) => version,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
) -> Result<String, CommandError> {
|
||||
let version = VersionsNumber::from_str(version_to_check.as_str())?;
|
||||
|
||||
// if a patch version is required
|
||||
if version.patch.is_some() {
|
||||
@@ -112,10 +109,10 @@ pub fn get_supported_version_to_use(
|
||||
)) {
|
||||
Some(version) => Ok(version.to_string()),
|
||||
None => {
|
||||
return Err(format!(
|
||||
return Err(CommandError::new_from_safe_message(format!(
|
||||
"{} {} version is not supported",
|
||||
database_name, version_to_check
|
||||
));
|
||||
)));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -125,10 +122,10 @@ pub fn get_supported_version_to_use(
|
||||
return match all_supported_versions.get(&format!("{}.{}", version.major, version.minor.unwrap())) {
|
||||
Some(version) => Ok(version.to_string()),
|
||||
None => {
|
||||
return Err(format!(
|
||||
return Err(CommandError::new_from_safe_message(format!(
|
||||
"{} {} version is not supported",
|
||||
database_name, version_to_check
|
||||
));
|
||||
)));
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -137,10 +134,10 @@ pub fn get_supported_version_to_use(
|
||||
match all_supported_versions.get(&version.major) {
|
||||
Some(version) => Ok(version.to_string()),
|
||||
None => {
|
||||
return Err(format!(
|
||||
return Err(CommandError::new_from_safe_message(format!(
|
||||
"{} {} version is not supported",
|
||||
database_name, version_to_check
|
||||
));
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,11 +272,13 @@ impl VersionsNumber {
|
||||
}
|
||||
|
||||
impl FromStr for VersionsNumber {
|
||||
type Err = StringError;
|
||||
type Err = CommandError;
|
||||
|
||||
fn from_str(version: &str) -> Result<Self, Self::Err> {
|
||||
if version.trim() == "" {
|
||||
return Err(StringError::from("version cannot be empty"));
|
||||
return Err(CommandError::new_from_safe_message(
|
||||
"version cannot be empty".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let mut version_split = version.splitn(4, '.').map(|v| v.trim());
|
||||
@@ -290,10 +289,10 @@ impl FromStr for VersionsNumber {
|
||||
major.replace("v", "")
|
||||
}
|
||||
None => {
|
||||
return Err(format!(
|
||||
return Err(CommandError::new_from_safe_message(format!(
|
||||
"please check the version you've sent ({}), it can't be checked",
|
||||
version
|
||||
))
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -438,19 +437,23 @@ pub fn check_domain_for(
|
||||
domains_to_check: Vec<&str>,
|
||||
execution_id: &str,
|
||||
context_id: &str,
|
||||
event_details: EventDetails,
|
||||
logger: &dyn Logger,
|
||||
) -> Result<(), EngineError> {
|
||||
let resolvers = dns_resolvers();
|
||||
|
||||
for domain in domains_to_check {
|
||||
let message = format!(
|
||||
"Let's check domain resolution for '{}'. Please wait, it can take some time...",
|
||||
domain
|
||||
);
|
||||
|
||||
listener_helper.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Environment {
|
||||
id: execution_id.to_string(),
|
||||
},
|
||||
ProgressLevel::Info,
|
||||
Some(format!(
|
||||
"Let's check domain resolution for '{}'. Please wait, it can take some time...",
|
||||
domain
|
||||
)),
|
||||
Some(message.to_string()),
|
||||
execution_id,
|
||||
));
|
||||
|
||||
@@ -460,13 +463,22 @@ pub fn check_domain_for(
|
||||
ix += 1;
|
||||
resolver
|
||||
};
|
||||
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(event_details.clone(), EventMessage::new_from_safe(message.to_string())),
|
||||
);
|
||||
|
||||
let fixed_iterable = Fixed::from_millis(3000).take(100);
|
||||
let check_result = retry::retry(fixed_iterable, || match next_resolver().lookup_ip(domain) {
|
||||
Ok(lookup_ip) => OperationResult::Ok(lookup_ip),
|
||||
Err(err) => {
|
||||
let x = format!("Domain resolution check for '{}' is still in progress...", domain);
|
||||
|
||||
info!("{}", x);
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(event_details.clone(), EventMessage::new_from_safe(x.to_string())),
|
||||
);
|
||||
|
||||
listener_helper.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Environment {
|
||||
@@ -485,7 +497,10 @@ pub fn check_domain_for(
|
||||
Ok(_) => {
|
||||
let x = format!("Domain {} is ready! ⚡️", domain);
|
||||
|
||||
info!("{}", x);
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(event_details.clone(), EventMessage::new_from_safe(message.to_string())),
|
||||
);
|
||||
|
||||
listener_helper.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Environment {
|
||||
@@ -503,7 +518,10 @@ pub fn check_domain_for(
|
||||
domain
|
||||
);
|
||||
|
||||
warn!("{}", message);
|
||||
logger.log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(event_details.clone(), EventMessage::new_from_safe(message.to_string())),
|
||||
);
|
||||
|
||||
listener_helper.deployment_in_progress(ProgressInfo::new(
|
||||
ProgressScope::Environment {
|
||||
@@ -533,122 +551,36 @@ pub fn managed_db_name_sanitizer(max_size: usize, prefix: &str, name: &str) -> S
|
||||
new_name
|
||||
}
|
||||
|
||||
pub fn convert_k8s_cpu_value_to_f32(value: String) -> Result<f32, ParseFloatError> {
|
||||
if value.ends_with('m') {
|
||||
let mut value_number_string = value;
|
||||
value_number_string.pop();
|
||||
return match value_number_string.parse::<f32>() {
|
||||
Ok(n) => {
|
||||
Ok(n * 0.001) // return in milli cpu the value
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
}
|
||||
|
||||
match value.parse::<f32>() {
|
||||
Ok(n) => Ok(n),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_k8s_required_cpu_and_burstable(
|
||||
listener_helper: &ListenersHelper,
|
||||
execution_id: &str,
|
||||
context_id: &str,
|
||||
total_cpu: String,
|
||||
cpu_burst: String,
|
||||
) -> Result<CpuLimits, ParseFloatError> {
|
||||
let total_cpu_float = convert_k8s_cpu_value_to_f32(total_cpu.clone())?;
|
||||
let cpu_burst_float = convert_k8s_cpu_value_to_f32(cpu_burst.clone())?;
|
||||
let mut set_cpu_burst = cpu_burst.clone();
|
||||
|
||||
if cpu_burst_float < total_cpu_float {
|
||||
let message = format!(
|
||||
"CPU burst value '{}' was lower than the desired total of CPUs {}, using burstable value. Please ensure your configuration is valid",
|
||||
cpu_burst,
|
||||
total_cpu,
|
||||
);
|
||||
|
||||
warn!("{}", message);
|
||||
|
||||
listener_helper.error(ProgressInfo::new(
|
||||
ProgressScope::Environment {
|
||||
id: execution_id.to_string(),
|
||||
},
|
||||
ProgressLevel::Warn,
|
||||
Some(message),
|
||||
context_id,
|
||||
));
|
||||
set_cpu_burst = total_cpu.clone();
|
||||
}
|
||||
|
||||
Ok(CpuLimits {
|
||||
cpu_limit: set_cpu_burst,
|
||||
cpu_request: total_cpu,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn print_action(cloud_provider_name: &str, struct_name: &str, fn_name: &str, item_name: &str) {
|
||||
pub fn print_action(
|
||||
cloud_provider_name: &str,
|
||||
struct_name: &str,
|
||||
fn_name: &str,
|
||||
item_name: &str,
|
||||
event_details: EventDetails,
|
||||
logger: &dyn Logger,
|
||||
) {
|
||||
let msg = format!(
|
||||
"{}.{}.{} called for {}",
|
||||
cloud_provider_name, struct_name, fn_name, item_name
|
||||
);
|
||||
match fn_name.contains("error") {
|
||||
true => warn!("{}", msg),
|
||||
false => info!("{}", msg),
|
||||
true => logger.log(
|
||||
LogLevel::Warning,
|
||||
EngineEvent::Warning(event_details, EventMessage::new_from_safe(msg)),
|
||||
),
|
||||
false => logger.log(
|
||||
LogLevel::Info,
|
||||
EngineEvent::Info(event_details, EventMessage::new_from_safe(msg)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::cloud_provider::models::CpuLimits;
|
||||
use crate::cloud_provider::utilities::{
|
||||
convert_k8s_cpu_value_to_f32, dns_resolvers, get_cname_record_value, validate_k8s_required_cpu_and_burstable,
|
||||
VersionsNumber,
|
||||
};
|
||||
use crate::error::StringError;
|
||||
use crate::models::ListenersHelper;
|
||||
use crate::cloud_provider::utilities::{dns_resolvers, get_cname_record_value, VersionsNumber};
|
||||
use crate::errors::CommandError;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
pub fn test_k8s_milli_cpu_convert() {
|
||||
let milli_cpu = "250m".to_string();
|
||||
let int_cpu = "2".to_string();
|
||||
|
||||
assert_eq!(convert_k8s_cpu_value_to_f32(milli_cpu).unwrap(), 0.25 as f32);
|
||||
assert_eq!(convert_k8s_cpu_value_to_f32(int_cpu).unwrap(), 2 as f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_cpu_set() {
|
||||
let v = vec![];
|
||||
let listener_helper = ListenersHelper::new(&v);
|
||||
let execution_id = "execution_id";
|
||||
let context_id = "context_id";
|
||||
|
||||
let mut total_cpu = "0.25".to_string();
|
||||
let mut cpu_burst = "1".to_string();
|
||||
assert_eq!(
|
||||
validate_k8s_required_cpu_and_burstable(&listener_helper, execution_id, context_id, total_cpu, cpu_burst)
|
||||
.unwrap(),
|
||||
CpuLimits {
|
||||
cpu_request: "0.25".to_string(),
|
||||
cpu_limit: "1".to_string()
|
||||
}
|
||||
);
|
||||
|
||||
total_cpu = "1".to_string();
|
||||
cpu_burst = "0.5".to_string();
|
||||
assert_eq!(
|
||||
validate_k8s_required_cpu_and_burstable(&listener_helper, execution_id, context_id, total_cpu, cpu_burst)
|
||||
.unwrap(),
|
||||
CpuLimits {
|
||||
cpu_request: "1".to_string(),
|
||||
cpu_limit: "1".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_cname_resolution() {
|
||||
let resolvers = dns_resolvers();
|
||||
@@ -662,24 +594,30 @@ mod tests {
|
||||
// setup:
|
||||
struct TestCase<'a> {
|
||||
input: &'a str,
|
||||
expected_output: Result<VersionsNumber, StringError>,
|
||||
expected_output: Result<VersionsNumber, CommandError>,
|
||||
description: &'a str,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
input: "",
|
||||
expected_output: Err(StringError::from("version cannot be empty")),
|
||||
expected_output: Err(CommandError::new_from_safe_message(
|
||||
"version cannot be empty".to_string(),
|
||||
)),
|
||||
description: "empty version str",
|
||||
},
|
||||
TestCase {
|
||||
input: " ",
|
||||
expected_output: Err(StringError::from("version cannot be empty")),
|
||||
expected_output: Err(CommandError::new_from_safe_message(
|
||||
"version cannot be empty".to_string(),
|
||||
)),
|
||||
description: "version a tab str",
|
||||
},
|
||||
TestCase {
|
||||
input: " ",
|
||||
expected_output: Err(StringError::from("version cannot be empty")),
|
||||
expected_output: Err(CommandError::new_from_safe_message(
|
||||
"version cannot be empty".to_string(),
|
||||
)),
|
||||
description: "version as a space str",
|
||||
},
|
||||
TestCase {
|
||||
|
||||
@@ -7,6 +7,8 @@ use crate::cmd::command::QoveryCommand;
|
||||
use crate::container_registry::docker::{docker_pull_image, docker_tag_and_push_image};
|
||||
use crate::container_registry::{ContainerRegistry, EngineError, Kind, PullResult, PushResult};
|
||||
use crate::error::EngineErrorCause;
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
use crate::events::{ToTransmitter, Transmitter};
|
||||
use crate::models::{
|
||||
Context, Listen, Listener, Listeners, ListenersHelper, ProgressInfo, ProgressLevel, ProgressScope,
|
||||
};
|
||||
@@ -72,6 +74,12 @@ impl DockerHub {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTransmitter for DockerHub {
|
||||
fn to_transmitter(&self) -> Transmitter {
|
||||
Transmitter::ContainerRegistry(self.id().to_string(), self.name().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl ContainerRegistry for DockerHub {
|
||||
fn context(&self) -> &Context {
|
||||
&self.context
|
||||
@@ -89,16 +97,7 @@ impl ContainerRegistry for DockerHub {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> Result<(), EngineError> {
|
||||
// check the version of docker and print it as info
|
||||
let mut output_from_cmd = String::new();
|
||||
let mut cmd = QoveryCommand::new("docker", &vec!["--version"], &vec![]);
|
||||
let _ = cmd.exec_with_output(
|
||||
|r_out| output_from_cmd.push_str(&r_out),
|
||||
|r_err| error!("Error executing docker command {}", r_err),
|
||||
);
|
||||
|
||||
info!("Using Docker: {}", output_from_cmd);
|
||||
fn is_valid(&self) -> Result<(), NewEngineError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ use crate::cmd::command::QoveryCommand;
|
||||
use crate::container_registry::docker::{docker_pull_image, docker_tag_and_push_image};
|
||||
use crate::container_registry::{ContainerRegistry, EngineError, Kind, PullResult, PushResult};
|
||||
use crate::error::{cast_simple_error_to_engine_error, EngineErrorCause, SimpleError, SimpleErrorKind};
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
use crate::events::{ToTransmitter, Transmitter};
|
||||
use crate::models::{
|
||||
Context, Listen, Listener, Listeners, ListenersHelper, ProgressInfo, ProgressLevel, ProgressScope,
|
||||
};
|
||||
@@ -228,6 +230,12 @@ impl DOCR {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTransmitter for DOCR {
|
||||
fn to_transmitter(&self) -> Transmitter {
|
||||
Transmitter::ContainerRegistry(self.id().to_string(), self.name().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl ContainerRegistry for DOCR {
|
||||
fn context(&self) -> &Context {
|
||||
&self.context
|
||||
@@ -245,7 +253,7 @@ impl ContainerRegistry for DOCR {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> Result<(), EngineError> {
|
||||
fn is_valid(&self) -> Result<(), NewEngineError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ use crate::cmd::command::QoveryCommand;
|
||||
use crate::container_registry::docker::{docker_pull_image, docker_tag_and_push_image};
|
||||
use crate::container_registry::{ContainerRegistry, Kind, PullResult, PushResult};
|
||||
use crate::error::{EngineError, EngineErrorCause};
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
use crate::events::{ToTransmitter, Transmitter};
|
||||
use crate::models::{
|
||||
Context, Listen, Listener, Listeners, ListenersHelper, ProgressInfo, ProgressLevel, ProgressScope,
|
||||
};
|
||||
@@ -359,6 +361,12 @@ impl ECR {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTransmitter for ECR {
|
||||
fn to_transmitter(&self) -> Transmitter {
|
||||
Transmitter::ContainerRegistry(self.id().to_string(), self.name().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl ContainerRegistry for ECR {
|
||||
fn context(&self) -> &Context {
|
||||
&self.context
|
||||
@@ -376,18 +384,14 @@ impl ContainerRegistry for ECR {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> Result<(), EngineError> {
|
||||
fn is_valid(&self) -> Result<(), NewEngineError> {
|
||||
let client = StsClient::new_with_client(self.client(), Region::default());
|
||||
let s = block_on(client.get_caller_identity(GetCallerIdentityRequest::default()));
|
||||
|
||||
match s {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(self.engine_error(
|
||||
EngineErrorCause::User(
|
||||
"Your ECR account seems to be no longer valid (bad Credentials). \
|
||||
Please contact your Organization administrator to fix or change the Credentials.",
|
||||
),
|
||||
format!("bad ECR credentials for {}", self.name_with_id()),
|
||||
Err(_) => Err(NewEngineError::new_client_invalid_cloud_provider_credentials(
|
||||
self.get_event_details(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::build_platform::Image;
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope};
|
||||
use crate::models::{Context, Listen};
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter};
|
||||
use crate::models::{Context, Listen, QoveryIdentifier};
|
||||
|
||||
pub mod docker;
|
||||
pub mod docker_hub;
|
||||
@@ -10,7 +12,7 @@ pub mod docr;
|
||||
pub mod ecr;
|
||||
pub mod scaleway_container_registry;
|
||||
|
||||
pub trait ContainerRegistry: Listen {
|
||||
pub trait ContainerRegistry: Listen + ToTransmitter {
|
||||
fn context(&self) -> &Context;
|
||||
fn kind(&self) -> Kind;
|
||||
fn id(&self) -> &str;
|
||||
@@ -18,7 +20,7 @@ pub trait ContainerRegistry: Listen {
|
||||
fn name_with_id(&self) -> String {
|
||||
format!("{} ({})", self.name(), self.id())
|
||||
}
|
||||
fn is_valid(&self) -> Result<(), EngineError>;
|
||||
fn is_valid(&self) -> Result<(), NewEngineError>;
|
||||
fn on_create(&self) -> Result<(), EngineError>;
|
||||
fn on_create_error(&self) -> Result<(), EngineError>;
|
||||
fn on_delete(&self) -> Result<(), EngineError>;
|
||||
@@ -38,6 +40,18 @@ pub trait ContainerRegistry: Listen {
|
||||
Some(message),
|
||||
)
|
||||
}
|
||||
fn get_event_details(&self) -> EventDetails {
|
||||
let context = self.context();
|
||||
EventDetails::new(
|
||||
None,
|
||||
QoveryIdentifier::from(context.organization_id().to_string()),
|
||||
QoveryIdentifier::from(context.cluster_id().to_string()),
|
||||
QoveryIdentifier::from(context.execution_id().to_string()),
|
||||
None,
|
||||
Stage::Environment(EnvironmentStep::Build),
|
||||
self.to_transmitter(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PushResult {
|
||||
|
||||
@@ -9,6 +9,8 @@ use crate::container_registry::docker::{
|
||||
};
|
||||
use crate::container_registry::{ContainerRegistry, Kind, PullResult, PushResult};
|
||||
use crate::error::{EngineError, EngineErrorCause};
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
use crate::events::{ToTransmitter, Transmitter};
|
||||
use crate::models::{
|
||||
Context, Listen, Listener, Listeners, ListenersHelper, ProgressInfo, ProgressLevel, ProgressScope,
|
||||
};
|
||||
@@ -341,6 +343,12 @@ impl ScalewayCR {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTransmitter for ScalewayCR {
|
||||
fn to_transmitter(&self) -> Transmitter {
|
||||
Transmitter::ContainerRegistry(self.id().to_string(), self.name().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl ContainerRegistry for ScalewayCR {
|
||||
fn context(&self) -> &Context {
|
||||
&self.context
|
||||
@@ -358,7 +366,7 @@ impl ContainerRegistry for ScalewayCR {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> Result<(), EngineError> {
|
||||
fn is_valid(&self) -> Result<(), NewEngineError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::dns_provider::{DnsProvider, Kind};
|
||||
use crate::error::{EngineError, EngineErrorCause};
|
||||
use crate::errors::EngineError;
|
||||
use crate::events::{ToTransmitter, Transmitter};
|
||||
use crate::models::{Context, Domain};
|
||||
|
||||
pub struct Cloudflare {
|
||||
@@ -72,15 +73,17 @@ impl DnsProvider for Cloudflare {
|
||||
|
||||
fn is_valid(&self) -> Result<(), EngineError> {
|
||||
if self.cloudflare_api_token.is_empty() || self.cloudflare_email.is_empty() {
|
||||
Err(self.engine_error(
|
||||
EngineErrorCause::User(
|
||||
"Your Cloudflare account seems to be no longer valid (bad Credentials). \
|
||||
Please contact your Organization administrator to fix or change the Credentials.",
|
||||
),
|
||||
format!("bad Cloudflare credentials for {}", self.name_with_id()),
|
||||
Err(EngineError::new_client_invalid_cloud_provider_credentials(
|
||||
self.get_event_details(),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTransmitter for Cloudflare {
|
||||
fn to_transmitter(&self) -> Transmitter {
|
||||
Transmitter::DnsProvider(self.id().to_string(), self.name().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,13 @@ use std::net::Ipv4Addr;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::{EngineError, EngineErrorCause, EngineErrorScope};
|
||||
use crate::models::{Context, Domain};
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
use crate::events::{EnvironmentStep, EventDetails, Stage, ToTransmitter};
|
||||
use crate::models::{Context, Domain, QoveryIdentifier};
|
||||
|
||||
pub mod cloudflare;
|
||||
|
||||
pub trait DnsProvider {
|
||||
pub trait DnsProvider: ToTransmitter {
|
||||
fn context(&self) -> &Context;
|
||||
fn provider_name(&self) -> &str;
|
||||
fn kind(&self) -> Kind;
|
||||
@@ -20,7 +22,7 @@ pub trait DnsProvider {
|
||||
fn token(&self) -> &str;
|
||||
fn domain(&self) -> &Domain;
|
||||
fn resolvers(&self) -> Vec<Ipv4Addr>;
|
||||
fn is_valid(&self) -> Result<(), EngineError>;
|
||||
fn is_valid(&self) -> Result<(), NewEngineError>;
|
||||
fn engine_error_scope(&self) -> EngineErrorScope {
|
||||
EngineErrorScope::DnsProvider(self.id().to_string(), self.name().to_string())
|
||||
}
|
||||
@@ -32,6 +34,18 @@ pub trait DnsProvider {
|
||||
Some(message),
|
||||
)
|
||||
}
|
||||
fn get_event_details(&self) -> EventDetails {
|
||||
let context = self.context();
|
||||
EventDetails::new(
|
||||
None,
|
||||
QoveryIdentifier::from(context.organization_id().to_string()),
|
||||
QoveryIdentifier::from(context.cluster_id().to_string()),
|
||||
QoveryIdentifier::from(context.execution_id().to_string()),
|
||||
None,
|
||||
Stage::Environment(EnvironmentStep::Deploy),
|
||||
self.to_transmitter(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::build_platform::BuildPlatform;
|
||||
use crate::cloud_provider::CloudProvider;
|
||||
use crate::container_registry::ContainerRegistry;
|
||||
use crate::dns_provider::DnsProvider;
|
||||
use crate::error::EngineError;
|
||||
use crate::errors::EngineError;
|
||||
use crate::logger::Logger;
|
||||
use crate::models::Context;
|
||||
use crate::session::Session;
|
||||
|
||||
@@ -6,6 +6,7 @@ pub type Id = String;
|
||||
pub type Name = String;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[deprecated(note = "errors.EngineError to be used instead")]
|
||||
pub struct EngineError {
|
||||
pub cause: EngineErrorCause,
|
||||
pub scope: EngineErrorScope,
|
||||
@@ -72,6 +73,7 @@ pub enum EngineErrorCause {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[deprecated(note = "errors.CommandError to be used instead")]
|
||||
pub struct SimpleError {
|
||||
pub kind: SimpleErrorKind,
|
||||
pub message: Option<String>,
|
||||
|
||||
@@ -79,6 +79,25 @@ pub enum Tag {
|
||||
NoClusterFound,
|
||||
OnlyOneClusterExpected,
|
||||
CloudProviderApiMissingInfo,
|
||||
K8sValidateRequiredCPUandBurstableError,
|
||||
TerraformContextUnsupportedParameterValue,
|
||||
ClientServiceFailedToStart,
|
||||
ClientServiceFailedToDeployBeforeStart,
|
||||
DatabaseFailedToStartAfterSeveralRetries,
|
||||
RouterFailedToDeploy,
|
||||
CloudProviderClientInvalidCredentials,
|
||||
VersionNumberParsingError,
|
||||
NotImplementedError,
|
||||
BuilderDockerCannotFindAnyDockerfile,
|
||||
BuilderDockerCannotReadDockerfile,
|
||||
BuilderDockerCannotExtractEnvVarsFromDockerfile,
|
||||
BuilderDockerCannotBuildContainerImage,
|
||||
BuilderBuildpackInvalidLanguageFormat,
|
||||
BuilderBuildpackCannotBuildContainerImage,
|
||||
BuilderGetBuildError,
|
||||
BuilderCloningRepositoryError,
|
||||
DockerPushImageError,
|
||||
DockerPullImageError,
|
||||
}
|
||||
|
||||
impl From<errors::Tag> for Tag {
|
||||
@@ -145,6 +164,28 @@ impl From<errors::Tag> for Tag {
|
||||
errors::Tag::NoClusterFound => Tag::NoClusterFound,
|
||||
errors::Tag::OnlyOneClusterExpected => Tag::OnlyOneClusterExpected,
|
||||
errors::Tag::CloudProviderApiMissingInfo => Tag::CloudProviderApiMissingInfo,
|
||||
errors::Tag::K8sValidateRequiredCPUandBurstableError => Tag::K8sValidateRequiredCPUandBurstableError,
|
||||
errors::Tag::TerraformContextUnsupportedParameterValue => Tag::TerraformContextUnsupportedParameterValue,
|
||||
errors::Tag::ClientServiceFailedToStart => Tag::ClientServiceFailedToStart,
|
||||
errors::Tag::ClientServiceFailedToDeployBeforeStart => Tag::ClientServiceFailedToDeployBeforeStart,
|
||||
errors::Tag::DatabaseFailedToStartAfterSeveralRetries => Tag::DatabaseFailedToStartAfterSeveralRetries,
|
||||
errors::Tag::RouterFailedToDeploy => Tag::RouterFailedToDeploy,
|
||||
errors::Tag::CloudProviderClientInvalidCredentials => Tag::CloudProviderClientInvalidCredentials,
|
||||
errors::Tag::VersionNumberParsingError => Tag::VersionNumberParsingError,
|
||||
errors::Tag::NotImplementedError => Tag::NotImplementedError,
|
||||
errors::Tag::TaskCancellationRequested => Tag::CannotPauseClusterTasksAreRunning,
|
||||
errors::Tag::BuilderDockerCannotFindAnyDockerfile => Tag::BuilderDockerCannotFindAnyDockerfile,
|
||||
errors::Tag::BuilderDockerCannotReadDockerfile => Tag::BuilderDockerCannotReadDockerfile,
|
||||
errors::Tag::BuilderDockerCannotExtractEnvVarsFromDockerfile => {
|
||||
Tag::BuilderDockerCannotExtractEnvVarsFromDockerfile
|
||||
}
|
||||
errors::Tag::BuilderDockerCannotBuildContainerImage => Tag::BuilderDockerCannotBuildContainerImage,
|
||||
errors::Tag::BuilderBuildpackInvalidLanguageFormat => Tag::BuilderBuildpackInvalidLanguageFormat,
|
||||
errors::Tag::BuilderBuildpackCannotBuildContainerImage => Tag::BuilderBuildpackCannotBuildContainerImage,
|
||||
errors::Tag::BuilderGetBuildError => Tag::BuilderGetBuildError,
|
||||
errors::Tag::BuilderCloningRepositoryError => Tag::BuilderCloningRepositoryError,
|
||||
errors::Tag::DockerPushImageError => Tag::DockerPushImageError,
|
||||
errors::Tag::DockerPullImageError => Tag::DockerPullImageError,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ 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 crate::events::{EventDetails, GeneralStep, Stage, Transmitter};
|
||||
use crate::models::QoveryIdentifier;
|
||||
use url::Url;
|
||||
|
||||
/// CommandError: command error, mostly returned by third party tools.
|
||||
@@ -32,7 +33,10 @@ impl CommandError {
|
||||
pub fn message(&self) -> String {
|
||||
// TODO(benjaminch): To be revamped, not sure how we should deal with safe and unsafe messages.
|
||||
if let Some(msg) = &self.message_safe {
|
||||
return format!("{} {}", msg, self.message_raw);
|
||||
// TODO(benjaminch): Handle raw / safe as for event message
|
||||
if self.message_raw != *msg {
|
||||
return format!("{} {}", msg, self.message_raw);
|
||||
}
|
||||
}
|
||||
|
||||
self.message_raw.to_string()
|
||||
@@ -82,7 +86,7 @@ impl CommandError {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
/// Tag: unique identifier for an error.
|
||||
pub enum Tag {
|
||||
/// Unknown: unknown error.
|
||||
@@ -155,6 +159,8 @@ pub enum Tag {
|
||||
K8sNodeIsNotReadyWithTheRequestedVersion,
|
||||
/// K8sNodeIsNotReady: represents an error where the given node is not ready.
|
||||
K8sNodeIsNotReady,
|
||||
/// K8sValidateRequiredCPUandBurstableError: represents an error validating required CPU and burstable.
|
||||
K8sValidateRequiredCPUandBurstableError,
|
||||
/// CannotFindRequiredBinary: represents an error where a required binary is not found on the system.
|
||||
CannotFindRequiredBinary,
|
||||
/// SubnetsCountShouldBeEven: represents an error where subnets count should be even to have as many public than private subnets.
|
||||
@@ -173,6 +179,8 @@ pub enum Tag {
|
||||
TerraformErrorWhileExecutingPipeline,
|
||||
/// TerraformErrorWhileExecutingDestroyPipeline: represents an error while executing Terraform destroying pipeline.
|
||||
TerraformErrorWhileExecutingDestroyPipeline,
|
||||
/// TerraformContextUnsupportedParameterValue: represents an error while trying to render terraform context because of unsupported parameter value.
|
||||
TerraformContextUnsupportedParameterValue,
|
||||
/// HelmChartsSetupError: represents an error while trying to setup helm charts.
|
||||
HelmChartsSetupError,
|
||||
/// HelmChartsDeployError: represents an error while trying to deploy helm charts.
|
||||
@@ -197,8 +205,44 @@ pub enum Tag {
|
||||
ObjectStorageCannotCreateBucket,
|
||||
/// ObjectStorageCannotPutFileIntoBucket: represents an error while trying to put a file into an object storage bucket.
|
||||
ObjectStorageCannotPutFileIntoBucket,
|
||||
/// ClientServiceFailedToStart: represent an error while trying to start a client's service.
|
||||
ClientServiceFailedToStart,
|
||||
/// ClientServiceFailedToDeployBeforeStart: represents an error while trying to deploy a client's service before start.
|
||||
ClientServiceFailedToDeployBeforeStart,
|
||||
/// DatabaseFailedToStartAfterSeveralRetries: represents an error while trying to start a database after several retries.
|
||||
DatabaseFailedToStartAfterSeveralRetries,
|
||||
/// RouterFailedToDeploy: represents an error while trying to deploy a router.
|
||||
RouterFailedToDeploy,
|
||||
/// CloudProviderClientInvalidCredentials: represents an error where client credentials for a cloud providers appear to be invalid.
|
||||
CloudProviderClientInvalidCredentials,
|
||||
/// CloudProviderApiMissingInfo: represents an error while expecting mandatory info
|
||||
CloudProviderApiMissingInfo,
|
||||
/// ServiceInvalidVersionNumberError: represents an error where the version number is not valid.
|
||||
VersionNumberParsingError,
|
||||
/// NotImplementedError: represents an error where feature / code has not been implemented yet.
|
||||
NotImplementedError,
|
||||
/// TaskCancellationRequested: represents an error where current task cancellation has been requested.
|
||||
TaskCancellationRequested,
|
||||
/// BuilderDockerCannotFindAnyDockerfile: represents an error when trying to get a Dockerfile.
|
||||
BuilderDockerCannotFindAnyDockerfile,
|
||||
/// BuilderDockerCannotReadDockerfile: represents an error while trying to read Dockerfile.
|
||||
BuilderDockerCannotReadDockerfile,
|
||||
/// BuilderDockerCannotExtractEnvVarsFromDockerfile: represents an error while trying to extract ENV vars from Dockerfile.
|
||||
BuilderDockerCannotExtractEnvVarsFromDockerfile,
|
||||
/// BuilderDockerCannotBuildContainerImage: represents an error while trying to build Docker container image.
|
||||
BuilderDockerCannotBuildContainerImage,
|
||||
/// BuilderBuildpackInvalidLanguageFormat: represents an error where buildback requested language has wrong format.
|
||||
BuilderBuildpackInvalidLanguageFormat,
|
||||
/// BuilderBuildpackCannotBuildContainerImage: represents an error while trying to build container image with Buildpack.
|
||||
BuilderBuildpackCannotBuildContainerImage,
|
||||
/// BuilderGetBuildError: represents an error when builder is trying to get parent build.
|
||||
BuilderGetBuildError,
|
||||
/// BuilderCloningRepositoryError: represents an error when builder is trying to clone a git repository.
|
||||
BuilderCloningRepositoryError,
|
||||
/// DockerPushImageError: represents an error when trying to push a docker image.
|
||||
DockerPushImageError,
|
||||
/// DockerPullImageError: represents an error when trying to pull a docker image.
|
||||
DockerPullImageError,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -291,6 +335,40 @@ impl EngineError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new engine error from legacy engine error easing migration.
|
||||
pub fn new_from_legacy_engine_error(e: LegacyEngineError) -> Self {
|
||||
let message = e.message.unwrap_or("".to_string());
|
||||
EngineError {
|
||||
tag: Tag::Unknown,
|
||||
event_details: EventDetails::new(
|
||||
None,
|
||||
QoveryIdentifier::new("".to_string()),
|
||||
QoveryIdentifier::new("".to_string()),
|
||||
QoveryIdentifier::new(e.execution_id.to_string()),
|
||||
None,
|
||||
Stage::General(GeneralStep::UnderMigration),
|
||||
match e.scope {
|
||||
EngineErrorScope::Engine => Transmitter::Kubernetes("".to_string(), "".to_string()),
|
||||
EngineErrorScope::BuildPlatform(id, name) => Transmitter::BuildPlatform(id, name),
|
||||
EngineErrorScope::ContainerRegistry(id, name) => Transmitter::ContainerRegistry(id, name),
|
||||
EngineErrorScope::CloudProvider(id, name) => Transmitter::CloudProvider(id, name),
|
||||
EngineErrorScope::Kubernetes(id, name) => Transmitter::Kubernetes(id, name),
|
||||
EngineErrorScope::DnsProvider(id, name) => Transmitter::DnsProvider(id, name),
|
||||
EngineErrorScope::ObjectStorage(id, name) => Transmitter::ObjectStorage(id, name),
|
||||
EngineErrorScope::Environment(id, name) => Transmitter::Environment(id, name),
|
||||
EngineErrorScope::Database(id, db_type, name) => Transmitter::Database(id, db_type, name),
|
||||
EngineErrorScope::Application(id, name) => Transmitter::Application(id, name),
|
||||
EngineErrorScope::Router(id, name) => Transmitter::Router(id, name),
|
||||
},
|
||||
),
|
||||
qovery_log_message: message.to_string(),
|
||||
user_log_message: message.to_string(),
|
||||
message: None,
|
||||
link: None,
|
||||
hint_message: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts to legacy engine error easing migration.
|
||||
pub fn to_legacy_engine_error(self) -> LegacyEngineError {
|
||||
LegacyEngineError::new(
|
||||
@@ -382,8 +460,6 @@ impl EngineError {
|
||||
|
||||
/// Missing API info from the Cloud provider itself
|
||||
///
|
||||
///
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
@@ -1228,6 +1304,36 @@ impl EngineError {
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error for kubernetes validate required CPU and burstable.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `total_cpus_raw`: Total CPUs raw format.
|
||||
/// * `cpu_burst_raw`: CPU burst raw.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_k8s_validate_required_cpu_and_burstable_error(
|
||||
event_details: EventDetails,
|
||||
total_cpus_raw: String,
|
||||
cpu_burst_raw: String,
|
||||
raw_error: CommandError,
|
||||
) -> EngineError {
|
||||
let message = format!(
|
||||
"Error while trying to validate required CPU ({}) and burstable ({}).",
|
||||
total_cpus_raw, cpu_burst_raw
|
||||
);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::K8sValidateRequiredCPUandBurstableError,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
Some(raw_error),
|
||||
None,
|
||||
Some("Please ensure your configuration is valid.".to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error for kubernetes not being able to get crash looping pods.
|
||||
///
|
||||
/// Arguments:
|
||||
@@ -1444,6 +1550,38 @@ impl EngineError {
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error representing an unsupported value for Terraform context parameter.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `service_type`: Service type.
|
||||
/// * `parameter_name`: Context parameter name.
|
||||
/// * `parameter_value`: Context parameter value.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_terraform_unsupported_context_parameter_value(
|
||||
event_details: EventDetails,
|
||||
service_type: String,
|
||||
parameter_name: String,
|
||||
parameter_value: String,
|
||||
raw_error: Option<CommandError>,
|
||||
) -> EngineError {
|
||||
let message = format!(
|
||||
"{} value `{}` not supported for parameter `{}`",
|
||||
service_type, parameter_value, parameter_name,
|
||||
);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::TerraformContextUnsupportedParameterValue,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
raw_error,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error while setup Helm charts to deploy.
|
||||
///
|
||||
/// Arguments:
|
||||
@@ -1637,11 +1775,11 @@ impl EngineError {
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `product_name`: Product name for which version is not supported.
|
||||
/// * `raw_error`: Raw error message.
|
||||
/// * `version`: unsupported version raw string.
|
||||
pub fn new_unsupported_version_error(
|
||||
event_details: EventDetails,
|
||||
product_name: String,
|
||||
version: VersionsNumber,
|
||||
version: String,
|
||||
) -> EngineError {
|
||||
let message = format!(
|
||||
"Error, version `{}` is not supported for `{}`.",
|
||||
@@ -1739,6 +1877,158 @@ impl EngineError {
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error while trying to start a client service.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `service_id`: Client service ID.
|
||||
/// * `service_name`: Client service name.
|
||||
pub fn new_client_service_failed_to_start_error(
|
||||
event_details: EventDetails,
|
||||
service_id: String,
|
||||
service_name: String,
|
||||
) -> EngineError {
|
||||
// TODO(benjaminch): Service should probably passed otherwise, either inside event_details or via a new dedicated struct.
|
||||
let message = format!("Service `{}` (id `{}`) failed to start. ⤬", service_name, service_id);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::ClientServiceFailedToStart,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
None,
|
||||
None,
|
||||
Some("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).".to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error while trying to deploy a client service before start.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `service_id`: Client service ID.
|
||||
/// * `service_name`: Client service name.
|
||||
pub fn new_client_service_failed_to_deploy_before_start_error(
|
||||
event_details: EventDetails,
|
||||
service_id: String,
|
||||
service_name: String,
|
||||
) -> EngineError {
|
||||
// TODO(benjaminch): Service should probably passed otherwise, either inside event_details or via a new dedicated struct.
|
||||
let message = format!(
|
||||
"Service `{}` (id `{}`) failed to deploy (before start).",
|
||||
service_name, service_id
|
||||
);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::ClientServiceFailedToDeployBeforeStart,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error while trying to start a client service before start.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `service_id`: Client service ID.
|
||||
/// * `service_type`: Client service type.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_database_failed_to_start_after_several_retries(
|
||||
event_details: EventDetails,
|
||||
service_id: String,
|
||||
service_type: String,
|
||||
raw_error: Option<CommandError>,
|
||||
) -> EngineError {
|
||||
let message = format!(
|
||||
"Database `{}` (id `{}`) failed to start after several retries.",
|
||||
service_type, service_id
|
||||
);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::DatabaseFailedToStartAfterSeveralRetries,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
raw_error,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error while trying to deploy a router.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
pub fn new_router_failed_to_deploy(event_details: EventDetails) -> EngineError {
|
||||
let message = "Router has failed to be deployed.";
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::RouterFailedToDeploy,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when trying to connect to user's account with its credentials.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
pub fn new_client_invalid_cloud_provider_credentials(event_details: EventDetails) -> EngineError {
|
||||
let message = "Your cloud provider account seems to be no longer valid (bad credentials).";
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::CloudProviderClientInvalidCredentials,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
None,
|
||||
None,
|
||||
Some("Please contact your Organization administrator to fix or change the Credentials.".to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when trying to parse a version number.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `raw_version_number`: Raw version number string.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_version_number_parsing_error(
|
||||
event_details: EventDetails,
|
||||
raw_version_number: String,
|
||||
raw_error: CommandError,
|
||||
) -> EngineError {
|
||||
let message = format!(
|
||||
"Error while trying to parse `{}` to a version number.",
|
||||
raw_version_number
|
||||
);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::VersionNumberParsingError,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
Some(raw_error),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error while trying to get cluster.
|
||||
///
|
||||
/// Arguments:
|
||||
@@ -1801,4 +2091,303 @@ impl EngineError {
|
||||
Some("Please contact Qovery support for investigation.".to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Current task cancellation has been requested.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
pub fn new_task_cancellation_requested(event_details: EventDetails) -> EngineError {
|
||||
let message = "Task cancellation has been requested.";
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::TaskCancellationRequested,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when trying to get Dockerfile.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `location_path`: Dockerfile location path.
|
||||
pub fn new_docker_cannot_find_dockerfile(event_details: EventDetails, location_path: String) -> EngineError {
|
||||
let message = format!("Dockerfile not found at location `{}`.", location_path);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::BuilderDockerCannotFindAnyDockerfile,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
None,
|
||||
None,
|
||||
Some("Your Dockerfile is not present at the specified location, check your settings.".to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error buildpack invalid language format.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `requested_language`: Requested language.
|
||||
pub fn new_buildpack_invalid_language_format(
|
||||
event_details: EventDetails,
|
||||
requested_language: String,
|
||||
) -> EngineError {
|
||||
let message = format!(
|
||||
"Cannot build: Invalid buildpacks language format: `{}`.",
|
||||
requested_language
|
||||
);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::BuilderBuildpackInvalidLanguageFormat,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
None,
|
||||
None,
|
||||
Some("Expected format `builder[@version]`.".to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when trying to build container.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `container_image_name`: Container image name.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_buildpack_cannot_build_container_image(
|
||||
event_details: EventDetails,
|
||||
container_image_name: String,
|
||||
builders: Vec<String>,
|
||||
raw_error: CommandError,
|
||||
) -> EngineError {
|
||||
let message = "Cannot find a builder to build application.";
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::BuilderBuildpackCannotBuildContainerImage,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
Some(raw_error),
|
||||
None,
|
||||
Some(format!(
|
||||
"Qovery can't build your container image {} with one of the following builders: {}. Please do provide a valid Dockerfile to build your application or contact the support.",
|
||||
container_image_name,
|
||||
builders.join(", ")
|
||||
),),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when trying to get build.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `commit_id`: Commit ID of build to be retrieved.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_builder_get_build_error(
|
||||
event_details: EventDetails,
|
||||
commit_id: String,
|
||||
raw_error: CommandError,
|
||||
) -> EngineError {
|
||||
let message = format!("Error while trying to get build with commit ID: `{}`.", commit_id);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::BuilderGetBuildError,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
Some(raw_error),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when builder is trying to clone a git repository.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `repository_url`: Repository URL.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_builder_clone_repository_error(
|
||||
event_details: EventDetails,
|
||||
repository_url: String,
|
||||
raw_error: CommandError,
|
||||
) -> EngineError {
|
||||
let message = format!("Error while cloning repository `{}`.", repository_url);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::BuilderCloningRepositoryError,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
Some(raw_error),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when something went wrong because it's not implemented.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
pub fn new_not_implemented_error(event_details: EventDetails) -> EngineError {
|
||||
let message = "Error, something went wrong because it's not implemented.";
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::NotImplementedError,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when trying to push a Docker image.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `image_name`: Docker image name.
|
||||
/// * `repository_url`: Repository URL.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_docker_push_image_error(
|
||||
event_details: EventDetails,
|
||||
image_name: String,
|
||||
repository_url: String,
|
||||
raw_error: CommandError,
|
||||
) -> EngineError {
|
||||
let message = format!(
|
||||
"Error, trying to push Docker image `{}` to repository `{}`.",
|
||||
image_name, repository_url
|
||||
);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::DockerPushImageError,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
Some(raw_error),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when trying to pull a Docker image.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `image_name`: Docker image name.
|
||||
/// * `repository_url`: Repository URL.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_docker_pull_image_error(
|
||||
event_details: EventDetails,
|
||||
image_name: String,
|
||||
repository_url: String,
|
||||
raw_error: CommandError,
|
||||
) -> EngineError {
|
||||
let message = format!(
|
||||
"Error, trying to pull Docker image `{}` from repository `{}`.",
|
||||
image_name, repository_url
|
||||
);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::DockerPullImageError,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
Some(raw_error),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when trying to read Dockerfile content.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `dockerfile_path`: Dockerfile path.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_docker_cannot_read_dockerfile(
|
||||
event_details: EventDetails,
|
||||
dockerfile_path: String,
|
||||
raw_error: CommandError,
|
||||
) -> EngineError {
|
||||
let message = format!("Can't read Dockerfile `{}`.", dockerfile_path);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::BuilderDockerCannotReadDockerfile,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
Some(raw_error),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when trying to extract env vars from Dockerfile.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `dockerfile_path`: Dockerfile path.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_docker_cannot_extract_env_vars_from_dockerfile(
|
||||
event_details: EventDetails,
|
||||
dockerfile_path: String,
|
||||
raw_error: CommandError,
|
||||
) -> EngineError {
|
||||
let message = format!("Can't extract ENV vars from Dockerfile `{}`.", dockerfile_path);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::BuilderDockerCannotExtractEnvVarsFromDockerfile,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
Some(raw_error),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates new error when trying to build Docker container.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `event_details`: Error linked event details.
|
||||
/// * `container_image_name`: Container image name.
|
||||
/// * `raw_error`: Raw error message.
|
||||
pub fn new_docker_cannot_build_container_image(
|
||||
event_details: EventDetails,
|
||||
container_image_name: String,
|
||||
raw_error: CommandError,
|
||||
) -> EngineError {
|
||||
let message = format!("Error while building container image `{}`.", container_image_name);
|
||||
|
||||
EngineError::new(
|
||||
event_details,
|
||||
Tag::BuilderDockerCannotBuildContainerImage,
|
||||
message.to_string(),
|
||||
message.to_string(),
|
||||
Some(raw_error),
|
||||
None,
|
||||
Some("It looks like there is something wrong in your Dockerfile. Try building the application locally with `docker build --no-cache`.".to_string()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ pub enum EngineEvent {
|
||||
},
|
||||
Error {
|
||||
error: EngineError,
|
||||
message: Option<EventMessage>,
|
||||
},
|
||||
#[deprecated(note = "event status is carried by EventDetails directly")]
|
||||
Waiting {
|
||||
@@ -76,8 +77,12 @@ impl From<events::EngineEvent> for EngineEvent {
|
||||
details: EventDetails::from(d),
|
||||
message: EventMessage::from(m),
|
||||
},
|
||||
events::EngineEvent::Error(e) => EngineEvent::Error {
|
||||
events::EngineEvent::Error(e, m) => EngineEvent::Error {
|
||||
error: EngineError::from(e),
|
||||
message: match m {
|
||||
Some(msg) => Some(EventMessage::from(msg)),
|
||||
None => None,
|
||||
},
|
||||
},
|
||||
events::EngineEvent::Waiting(d, m) => EngineEvent::Waiting {
|
||||
details: EventDetails::from(d),
|
||||
@@ -151,6 +156,7 @@ pub enum GeneralStep {
|
||||
RetrieveClusterConfig,
|
||||
RetrieveClusterResources,
|
||||
ValidateSystemRequirements,
|
||||
UnderMigration,
|
||||
}
|
||||
|
||||
impl From<events::GeneralStep> for GeneralStep {
|
||||
@@ -159,6 +165,7 @@ impl From<events::GeneralStep> for GeneralStep {
|
||||
events::GeneralStep::RetrieveClusterConfig => GeneralStep::RetrieveClusterConfig,
|
||||
events::GeneralStep::RetrieveClusterResources => GeneralStep::RetrieveClusterResources,
|
||||
events::GeneralStep::ValidateSystemRequirements => GeneralStep::ValidateSystemRequirements,
|
||||
events::GeneralStep::UnderMigration => GeneralStep::UnderMigration,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ pub mod io;
|
||||
extern crate url;
|
||||
|
||||
use crate::cloud_provider::Kind;
|
||||
use crate::errors::EngineError;
|
||||
use crate::errors::{CommandError, EngineError};
|
||||
use crate::models::QoveryIdentifier;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
@@ -19,7 +19,7 @@ pub enum EngineEvent {
|
||||
/// Warning: represents a warning message event.
|
||||
Warning(EventDetails, EventMessage),
|
||||
/// Error: represents an error event.
|
||||
Error(EngineError),
|
||||
Error(EngineError, Option<EventMessage>),
|
||||
/// Waiting: represents an engine waiting event.
|
||||
///
|
||||
/// Engine is waiting for a task to be done.
|
||||
@@ -52,7 +52,7 @@ impl EngineEvent {
|
||||
EngineEvent::Debug(details, _message) => details,
|
||||
EngineEvent::Info(details, _message) => details,
|
||||
EngineEvent::Warning(details, _message) => details,
|
||||
EngineEvent::Error(engine_error) => engine_error.event_details(),
|
||||
EngineEvent::Error(engine_error, _message) => engine_error.event_details(),
|
||||
EngineEvent::Waiting(details, _message) => details,
|
||||
EngineEvent::Deploying(details, _message) => details,
|
||||
EngineEvent::Pausing(details, _message) => details,
|
||||
@@ -69,7 +69,7 @@ impl EngineEvent {
|
||||
EngineEvent::Debug(_details, message) => message.message(message_verbosity),
|
||||
EngineEvent::Info(_details, message) => message.message(message_verbosity),
|
||||
EngineEvent::Warning(_details, message) => message.message(message_verbosity),
|
||||
EngineEvent::Error(engine_error) => engine_error.message(),
|
||||
EngineEvent::Error(engine_error, _message) => engine_error.message(),
|
||||
EngineEvent::Waiting(_details, message) => message.message(message_verbosity),
|
||||
EngineEvent::Deploying(_details, message) => message.message(message_verbosity),
|
||||
EngineEvent::Pausing(_details, message) => message.message(message_verbosity),
|
||||
@@ -142,6 +142,12 @@ impl EventMessage {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CommandError> for EventMessage {
|
||||
fn from(e: CommandError) -> Self {
|
||||
EventMessage::new(e.message_raw(), e.message_safe())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for EventMessage {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.message(EventMessageVerbosity::SafeOnly).as_str()) // By default, expose only the safe message.
|
||||
@@ -193,6 +199,8 @@ pub enum GeneralStep {
|
||||
RetrieveClusterConfig,
|
||||
/// RetrieveClusterResources: retrieving cluster resources
|
||||
RetrieveClusterResources,
|
||||
/// UnderMigration: error migration hasn't been completed yet.
|
||||
UnderMigration,
|
||||
}
|
||||
|
||||
impl Display for GeneralStep {
|
||||
@@ -204,6 +212,7 @@ impl Display for GeneralStep {
|
||||
GeneralStep::RetrieveClusterConfig => "retrieve-cluster-config",
|
||||
GeneralStep::RetrieveClusterResources => "retrieve-cluster-resources",
|
||||
GeneralStep::ValidateSystemRequirements => "validate-system-requirements",
|
||||
GeneralStep::UnderMigration => "under-migration",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#![allow(deprecated)]
|
||||
|
||||
extern crate tera;
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
extern crate trust_dns_resolver;
|
||||
|
||||
pub mod build_platform;
|
||||
#[allow(deprecated)]
|
||||
pub mod cloud_provider;
|
||||
pub mod cmd;
|
||||
pub mod constants;
|
||||
|
||||
@@ -116,25 +116,28 @@ mod tests {
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
log_level: LogLevel::Error,
|
||||
event: EngineEvent::Error(EngineError::new_unknown(
|
||||
EventDetails::new(
|
||||
Some(Kind::Scw),
|
||||
orga_id.clone(),
|
||||
cluster_id.clone(),
|
||||
execution_id.clone(),
|
||||
Some(ScwRegion::Paris.as_str().to_string()),
|
||||
Stage::Infrastructure(InfrastructureStep::Create),
|
||||
Transmitter::Kubernetes(cluster_id.to_string(), cluster_name.to_string()),
|
||||
event: EngineEvent::Error(
|
||||
EngineError::new_unknown(
|
||||
EventDetails::new(
|
||||
Some(Kind::Scw),
|
||||
orga_id.clone(),
|
||||
cluster_id.clone(),
|
||||
execution_id.clone(),
|
||||
Some(ScwRegion::Paris.as_str().to_string()),
|
||||
Stage::Infrastructure(InfrastructureStep::Create),
|
||||
Transmitter::Kubernetes(cluster_id.to_string(), cluster_name.to_string()),
|
||||
),
|
||||
qovery_message.to_string(),
|
||||
user_message.to_string(),
|
||||
Some(errors::CommandError::new(
|
||||
safe_message.to_string(),
|
||||
Some(raw_message.to_string()),
|
||||
)),
|
||||
Some(link.clone()),
|
||||
Some(hint.to_string()),
|
||||
),
|
||||
qovery_message.to_string(),
|
||||
user_message.to_string(),
|
||||
Some(errors::CommandError::new(
|
||||
safe_message.to_string(),
|
||||
Some(raw_message.to_string()),
|
||||
)),
|
||||
Some(link.clone()),
|
||||
Some(hint.to_string()),
|
||||
)),
|
||||
None,
|
||||
),
|
||||
description: "Error event",
|
||||
},
|
||||
TestCase {
|
||||
|
||||
@@ -23,6 +23,7 @@ use crate::cloud_provider::utilities::VersionsNumber;
|
||||
use crate::cloud_provider::CloudProvider;
|
||||
use crate::cloud_provider::Kind as CPKind;
|
||||
use crate::git;
|
||||
use crate::logger::Logger;
|
||||
use crate::utilities::get_image_tag;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -100,13 +101,14 @@ impl Environment {
|
||||
context: &Context,
|
||||
built_applications: &Vec<Box<dyn crate::cloud_provider::service::Application>>,
|
||||
cloud_provider: &dyn CloudProvider,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> crate::cloud_provider::environment::Environment {
|
||||
let applications = self
|
||||
.applications
|
||||
.iter()
|
||||
.map(|x| match built_applications.iter().find(|y| x.id.as_str() == y.id()) {
|
||||
Some(app) => x.to_stateless_service(context, app.image().clone(), cloud_provider),
|
||||
_ => x.to_stateless_service(context, x.to_image(), cloud_provider),
|
||||
Some(app) => x.to_stateless_service(context, app.image().clone(), cloud_provider, logger.clone()),
|
||||
_ => x.to_stateless_service(context, x.to_image(), cloud_provider, logger.clone()),
|
||||
})
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
@@ -115,7 +117,7 @@ impl Environment {
|
||||
let routers = self
|
||||
.routers
|
||||
.iter()
|
||||
.map(|x| x.to_stateless_service(context, cloud_provider))
|
||||
.map(|x| x.to_stateless_service(context, cloud_provider, logger.clone()))
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
@@ -129,7 +131,7 @@ impl Environment {
|
||||
let databases = self
|
||||
.databases
|
||||
.iter()
|
||||
.map(|x| x.to_stateful_service(context, cloud_provider))
|
||||
.map(|x| x.to_stateful_service(context, cloud_provider, logger.clone()))
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
@@ -221,6 +223,7 @@ impl Application {
|
||||
context: &Context,
|
||||
image: &Image,
|
||||
cloud_provider: &dyn CloudProvider,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Option<Box<(dyn crate::cloud_provider::service::Application)>> {
|
||||
let environment_variables = to_environment_variable(&self.environment_vars);
|
||||
let listeners = cloud_provider.listeners().clone();
|
||||
@@ -242,6 +245,7 @@ impl Application {
|
||||
self.storage.iter().map(|s| s.to_aws_storage()).collect::<Vec<_>>(),
|
||||
environment_variables,
|
||||
listeners,
|
||||
logger,
|
||||
))),
|
||||
CPKind::Do => Some(Box::new(
|
||||
crate::cloud_provider::digitalocean::application::Application::new(
|
||||
@@ -260,6 +264,7 @@ impl Application {
|
||||
self.storage.iter().map(|s| s.to_do_storage()).collect::<Vec<_>>(),
|
||||
environment_variables,
|
||||
listeners,
|
||||
logger,
|
||||
),
|
||||
)),
|
||||
CPKind::Scw => Some(Box::new(
|
||||
@@ -279,6 +284,7 @@ impl Application {
|
||||
self.storage.iter().map(|s| s.to_scw_storage()).collect::<Vec<_>>(),
|
||||
environment_variables,
|
||||
listeners,
|
||||
logger,
|
||||
),
|
||||
)),
|
||||
}
|
||||
@@ -289,6 +295,7 @@ impl Application {
|
||||
context: &Context,
|
||||
image: Image,
|
||||
cloud_provider: &dyn CloudProvider,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Option<Box<dyn StatelessService>> {
|
||||
let environment_variables = to_environment_variable(&self.environment_vars);
|
||||
let listeners = cloud_provider.listeners().clone();
|
||||
@@ -310,6 +317,7 @@ impl Application {
|
||||
self.storage.iter().map(|s| s.to_aws_storage()).collect::<Vec<_>>(),
|
||||
environment_variables,
|
||||
listeners,
|
||||
logger.clone(),
|
||||
))),
|
||||
CPKind::Do => Some(Box::new(
|
||||
crate::cloud_provider::digitalocean::application::Application::new(
|
||||
@@ -328,6 +336,7 @@ impl Application {
|
||||
self.storage.iter().map(|s| s.to_do_storage()).collect::<Vec<_>>(),
|
||||
environment_variables,
|
||||
listeners,
|
||||
logger.clone(),
|
||||
),
|
||||
)),
|
||||
CPKind::Scw => Some(Box::new(
|
||||
@@ -347,6 +356,7 @@ impl Application {
|
||||
self.storage.iter().map(|s| s.to_scw_storage()).collect::<Vec<_>>(),
|
||||
environment_variables,
|
||||
listeners,
|
||||
logger.clone(),
|
||||
),
|
||||
)),
|
||||
}
|
||||
@@ -583,6 +593,7 @@ impl Router {
|
||||
&self,
|
||||
context: &Context,
|
||||
cloud_provider: &dyn CloudProvider,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Option<Box<dyn StatelessService>> {
|
||||
let custom_domains = self
|
||||
.custom_domains
|
||||
@@ -616,6 +627,7 @@ impl Router {
|
||||
routes,
|
||||
self.sticky_sessions_enabled,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
Some(router)
|
||||
}
|
||||
@@ -631,6 +643,7 @@ impl Router {
|
||||
routes,
|
||||
self.sticky_sessions_enabled,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
Some(router)
|
||||
}
|
||||
@@ -645,6 +658,7 @@ impl Router {
|
||||
routes,
|
||||
self.sticky_sessions_enabled,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
Some(router)
|
||||
}
|
||||
@@ -701,6 +715,7 @@ impl Database {
|
||||
&self,
|
||||
context: &Context,
|
||||
cloud_provider: &dyn CloudProvider,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Option<Box<dyn StatefulService>> {
|
||||
let database_options = DatabaseOptions {
|
||||
mode: self.mode.clone(),
|
||||
@@ -734,6 +749,7 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
|
||||
Some(db)
|
||||
@@ -752,6 +768,7 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
|
||||
Some(db)
|
||||
@@ -770,6 +787,7 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
|
||||
Some(db)
|
||||
@@ -788,6 +806,7 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
|
||||
Some(db)
|
||||
@@ -809,6 +828,7 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -829,6 +849,7 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
|
||||
Some(db)
|
||||
@@ -848,6 +869,7 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
|
||||
Some(db)
|
||||
@@ -867,6 +889,7 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
|
||||
Some(db)
|
||||
@@ -889,12 +912,16 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger.clone(),
|
||||
));
|
||||
|
||||
Some(db)
|
||||
}
|
||||
Err(e) => {
|
||||
error!("{}", format!("error while parsing postgres version, error: {}", e));
|
||||
error!(
|
||||
"{}",
|
||||
format!("error while parsing postgres version, error: {}", e.message())
|
||||
);
|
||||
None
|
||||
}
|
||||
},
|
||||
@@ -914,12 +941,16 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger.clone(),
|
||||
));
|
||||
|
||||
Some(db)
|
||||
}
|
||||
Err(e) => {
|
||||
error!("{}", format!("error while parsing mysql version, error: {}", e));
|
||||
error!(
|
||||
"{}",
|
||||
format!("error while parsing mysql version, error: {}", e.message())
|
||||
);
|
||||
None
|
||||
}
|
||||
},
|
||||
@@ -938,6 +969,7 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger.clone(),
|
||||
));
|
||||
|
||||
Some(db)
|
||||
@@ -957,6 +989,7 @@ impl Database {
|
||||
self.database_instance_type.as_str(),
|
||||
database_options,
|
||||
listeners,
|
||||
logger,
|
||||
));
|
||||
|
||||
Some(db)
|
||||
|
||||
@@ -6,8 +6,9 @@ use crate::cloud_provider::kubernetes::Kubernetes;
|
||||
use crate::cloud_provider::service::{Application, Service};
|
||||
use crate::container_registry::PushResult;
|
||||
use crate::engine::Engine;
|
||||
use crate::error::EngineError;
|
||||
use crate::errors::EngineError as NewEngineError;
|
||||
use crate::errors::{EngineError, Tag};
|
||||
use crate::events::{EngineEvent, EventMessage};
|
||||
use crate::logger::{LogLevel, Logger};
|
||||
use crate::models::{
|
||||
Action, Environment, EnvironmentAction, EnvironmentError, ListenersHelper, ProgressInfo, ProgressLevel,
|
||||
ProgressScope,
|
||||
@@ -28,7 +29,7 @@ impl<'a> Transaction<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_kubernetes(&mut self, kubernetes: &'a dyn Kubernetes) -> Result<(), NewEngineError> {
|
||||
pub fn create_kubernetes(&mut self, kubernetes: &'a dyn Kubernetes) -> Result<(), EngineError> {
|
||||
match kubernetes.is_valid() {
|
||||
Ok(_) => {
|
||||
self.steps.push(Step::CreateKubernetes(kubernetes));
|
||||
@@ -38,7 +39,7 @@ impl<'a> Transaction<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pause_kubernetes(&mut self, kubernetes: &'a dyn Kubernetes) -> Result<(), NewEngineError> {
|
||||
pub fn pause_kubernetes(&mut self, kubernetes: &'a dyn Kubernetes) -> Result<(), EngineError> {
|
||||
match kubernetes.is_valid() {
|
||||
Ok(_) => {
|
||||
self.steps.push(Step::PauseKubernetes(kubernetes));
|
||||
@@ -48,7 +49,7 @@ impl<'a> Transaction<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_kubernetes(&mut self, kubernetes: &'a dyn Kubernetes) -> Result<(), NewEngineError> {
|
||||
pub fn delete_kubernetes(&mut self, kubernetes: &'a dyn Kubernetes) -> Result<(), EngineError> {
|
||||
match kubernetes.is_valid() {
|
||||
Ok(_) => {
|
||||
self.steps.push(Step::DeleteKubernetes(kubernetes));
|
||||
@@ -151,17 +152,12 @@ impl<'a> Transaction<'a> {
|
||||
container_registry.kind()
|
||||
))
|
||||
);
|
||||
return Err(err);
|
||||
return Err(EngineError::new_from_legacy_engine_error(err));
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"load build app {} cache error: {}",
|
||||
app.name.as_str(),
|
||||
err.message.clone().unwrap_or("<no message>".to_string())
|
||||
);
|
||||
|
||||
warn!("load build app {} cache error: {}", app.name.as_str(), err.message());
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
@@ -173,6 +169,7 @@ impl<'a> Transaction<'a> {
|
||||
&self,
|
||||
environment: &Environment,
|
||||
option: &DeploymentOption,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Result<Vec<Box<dyn Application>>, EngineError> {
|
||||
// do the same for applications
|
||||
let apps_to_build = environment
|
||||
@@ -219,6 +216,7 @@ impl<'a> Transaction<'a> {
|
||||
self.engine.context(),
|
||||
&build_result.build.image,
|
||||
self.engine.cloud_provider(),
|
||||
logger.clone(),
|
||||
) {
|
||||
applications.push(app)
|
||||
}
|
||||
@@ -252,7 +250,7 @@ impl<'a> Transaction<'a> {
|
||||
Ok(tuple) => results.push(tuple),
|
||||
Err(err) => {
|
||||
error!("error pushing docker image {:?}", err);
|
||||
return Err(err);
|
||||
return Err(EngineError::new_from_legacy_engine_error(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,10 +258,14 @@ impl<'a> Transaction<'a> {
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
fn check_environment(&self, environment: &crate::cloud_provider::environment::Environment) -> TransactionResult {
|
||||
fn check_environment(
|
||||
&self,
|
||||
environment: &crate::cloud_provider::environment::Environment,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> TransactionResult {
|
||||
if let Err(engine_error) = environment.is_valid() {
|
||||
warn!("ROLLBACK STARTED! an error occurred {:?}", engine_error);
|
||||
return match self.rollback() {
|
||||
return match self.rollback(logger) {
|
||||
Ok(_) => TransactionResult::Rollback(engine_error),
|
||||
Err(err) => {
|
||||
error!("ROLLBACK FAILED! fatal error: {:?}", err);
|
||||
@@ -275,25 +277,25 @@ impl<'a> Transaction<'a> {
|
||||
TransactionResult::Ok
|
||||
}
|
||||
|
||||
pub fn rollback(&self) -> Result<(), RollbackError> {
|
||||
pub fn rollback(&self, logger: Box<dyn Logger>) -> Result<(), RollbackError> {
|
||||
for step in self.executed_steps.iter() {
|
||||
match step {
|
||||
Step::CreateKubernetes(kubernetes) => {
|
||||
// revert kubernetes creation
|
||||
if let Err(err) = kubernetes.on_create_error() {
|
||||
return Err(RollbackError::CommitError(err.to_legacy_engine_error()));
|
||||
return Err(RollbackError::CommitError(err));
|
||||
};
|
||||
}
|
||||
Step::DeleteKubernetes(kubernetes) => {
|
||||
// revert kubernetes deletion
|
||||
if let Err(err) = kubernetes.on_delete_error() {
|
||||
return Err(RollbackError::CommitError(err.to_legacy_engine_error()));
|
||||
return Err(RollbackError::CommitError(err));
|
||||
};
|
||||
}
|
||||
Step::PauseKubernetes(kubernetes) => {
|
||||
// revert pause
|
||||
if let Err(err) = kubernetes.on_pause_error() {
|
||||
return Err(RollbackError::CommitError(err.to_legacy_engine_error()));
|
||||
return Err(RollbackError::CommitError(err));
|
||||
};
|
||||
}
|
||||
Step::BuildEnvironment(_environment_action, _option) => {
|
||||
@@ -301,13 +303,13 @@ impl<'a> Transaction<'a> {
|
||||
}
|
||||
Step::DeployEnvironment(kubernetes, environment_action) => {
|
||||
// revert environment deployment
|
||||
self.rollback_environment(*kubernetes, *environment_action)?;
|
||||
self.rollback_environment(*kubernetes, *environment_action, logger.clone())?;
|
||||
}
|
||||
Step::PauseEnvironment(kubernetes, environment_action) => {
|
||||
self.rollback_environment(*kubernetes, *environment_action)?;
|
||||
self.rollback_environment(*kubernetes, *environment_action, logger.clone())?;
|
||||
}
|
||||
Step::DeleteEnvironment(kubernetes, environment_action) => {
|
||||
self.rollback_environment(*kubernetes, *environment_action)?;
|
||||
self.rollback_environment(*kubernetes, *environment_action, logger.clone())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,21 +323,29 @@ impl<'a> Transaction<'a> {
|
||||
&self,
|
||||
kubernetes: &dyn Kubernetes,
|
||||
environment_action: &EnvironmentAction,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> Result<(), RollbackError> {
|
||||
let qe_environment = |environment: &Environment| {
|
||||
let mut _applications = Vec::with_capacity(environment.applications.len());
|
||||
for application in environment.applications.iter() {
|
||||
let build = application.to_build();
|
||||
|
||||
if let Some(x) =
|
||||
application.to_application(self.engine.context(), &build.image, self.engine.cloud_provider())
|
||||
{
|
||||
if let Some(x) = application.to_application(
|
||||
self.engine.context(),
|
||||
&build.image,
|
||||
self.engine.cloud_provider(),
|
||||
logger.clone(),
|
||||
) {
|
||||
_applications.push(x)
|
||||
}
|
||||
}
|
||||
|
||||
let qe_environment =
|
||||
environment.to_qe_environment(self.engine.context(), &_applications, self.engine.cloud_provider());
|
||||
let qe_environment = environment.to_qe_environment(
|
||||
self.engine.context(),
|
||||
&_applications,
|
||||
self.engine.cloud_provider(),
|
||||
logger.clone(),
|
||||
);
|
||||
|
||||
qe_environment
|
||||
};
|
||||
@@ -354,7 +364,7 @@ impl<'a> Transaction<'a> {
|
||||
|
||||
let _ = match action {
|
||||
Ok(_) => {}
|
||||
Err(err) => return Err(RollbackError::CommitError(err.to_legacy_engine_error())),
|
||||
Err(err) => return Err(RollbackError::CommitError(err)),
|
||||
};
|
||||
|
||||
Err(RollbackError::NoFailoverEnvironment)
|
||||
@@ -362,7 +372,7 @@ impl<'a> Transaction<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit(mut self) -> TransactionResult {
|
||||
pub fn commit(mut self, logger: Box<dyn Logger>) -> TransactionResult {
|
||||
let mut applications_by_environment: HashMap<&Environment, Vec<Box<dyn Application>>> = HashMap::new();
|
||||
|
||||
for step in self.steps.iter() {
|
||||
@@ -375,7 +385,8 @@ impl<'a> Transaction<'a> {
|
||||
match self.commit_infrastructure(
|
||||
*kubernetes,
|
||||
Action::Create,
|
||||
kubernetes.on_create().map_err(|e| e.to_legacy_engine_error()),
|
||||
kubernetes.on_create(),
|
||||
logger.clone(),
|
||||
) {
|
||||
TransactionResult::Ok => {}
|
||||
err => {
|
||||
@@ -389,7 +400,8 @@ impl<'a> Transaction<'a> {
|
||||
match self.commit_infrastructure(
|
||||
*kubernetes,
|
||||
Action::Delete,
|
||||
kubernetes.on_delete().map_err(|e| e.to_legacy_engine_error()),
|
||||
kubernetes.on_delete(),
|
||||
logger.clone(),
|
||||
) {
|
||||
TransactionResult::Ok => {}
|
||||
err => {
|
||||
@@ -400,11 +412,8 @@ impl<'a> Transaction<'a> {
|
||||
}
|
||||
Step::PauseKubernetes(kubernetes) => {
|
||||
// pause kubernetes
|
||||
match self.commit_infrastructure(
|
||||
*kubernetes,
|
||||
Action::Pause,
|
||||
kubernetes.on_pause().map_err(|e| e.to_legacy_engine_error()),
|
||||
) {
|
||||
match self.commit_infrastructure(*kubernetes, Action::Pause, kubernetes.on_pause(), logger.clone())
|
||||
{
|
||||
TransactionResult::Ok => {}
|
||||
err => {
|
||||
error!("Error while pausing infrastructure: {:?}", err);
|
||||
@@ -418,11 +427,21 @@ impl<'a> Transaction<'a> {
|
||||
EnvironmentAction::Environment(te) => te,
|
||||
};
|
||||
|
||||
let applications_builds = match self.build_applications(target_environment, option) {
|
||||
let applications_builds = match self.build_applications(target_environment, option, logger.clone())
|
||||
{
|
||||
Ok(apps) => apps,
|
||||
Err(engine_err) => {
|
||||
warn!("ROLLBACK STARTED! an error occurred {:?}", engine_err);
|
||||
return if engine_err.is_cancel() {
|
||||
logger.log(
|
||||
LogLevel::Error,
|
||||
EngineEvent::Error(
|
||||
engine_err.clone(),
|
||||
Some(EventMessage::new_from_safe(
|
||||
"ROLLBACK STARTED! an error occurred".to_string(),
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
return if engine_err.tag() == &Tag::TaskCancellationRequested {
|
||||
TransactionResult::Canceled
|
||||
} else {
|
||||
TransactionResult::Rollback(engine_err)
|
||||
@@ -442,7 +461,7 @@ impl<'a> Transaction<'a> {
|
||||
}
|
||||
Err(engine_err) => {
|
||||
warn!("ROLLBACK STARTED! an error occurred {:?}", engine_err);
|
||||
return match self.rollback() {
|
||||
return match self.rollback(logger.clone()) {
|
||||
Ok(_) => TransactionResult::Rollback(engine_err),
|
||||
Err(err) => {
|
||||
error!("ROLLBACK FAILED! fatal error: {:?}", err);
|
||||
@@ -460,11 +479,8 @@ impl<'a> Transaction<'a> {
|
||||
*kubernetes,
|
||||
*environment_action,
|
||||
&applications_by_environment,
|
||||
|qe_env| {
|
||||
kubernetes
|
||||
.deploy_environment(qe_env)
|
||||
.map_err(|e| e.to_legacy_engine_error())
|
||||
},
|
||||
|qe_env| kubernetes.deploy_environment(qe_env),
|
||||
logger.clone(),
|
||||
) {
|
||||
TransactionResult::Ok => {}
|
||||
err => {
|
||||
@@ -479,11 +495,8 @@ impl<'a> Transaction<'a> {
|
||||
*kubernetes,
|
||||
*environment_action,
|
||||
&applications_by_environment,
|
||||
|qe_env| {
|
||||
kubernetes
|
||||
.pause_environment(qe_env)
|
||||
.map_err(|e| e.to_legacy_engine_error())
|
||||
},
|
||||
|qe_env| kubernetes.pause_environment(qe_env),
|
||||
logger.clone(),
|
||||
) {
|
||||
TransactionResult::Ok => {}
|
||||
err => {
|
||||
@@ -498,11 +511,8 @@ impl<'a> Transaction<'a> {
|
||||
*kubernetes,
|
||||
*environment_action,
|
||||
&applications_by_environment,
|
||||
|qe_env| {
|
||||
kubernetes
|
||||
.delete_environment(qe_env)
|
||||
.map_err(|e| e.to_legacy_engine_error())
|
||||
},
|
||||
|qe_env| kubernetes.delete_environment(qe_env),
|
||||
logger.clone(),
|
||||
) {
|
||||
TransactionResult::Ok => {}
|
||||
err => {
|
||||
@@ -522,6 +532,7 @@ impl<'a> Transaction<'a> {
|
||||
kubernetes: &dyn Kubernetes,
|
||||
action: Action,
|
||||
result: Result<(), EngineError>,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> TransactionResult {
|
||||
// send back the right progress status
|
||||
fn send_progress(lh: &ListenersHelper, action: Action, execution_id: &str, is_error: bool) {
|
||||
@@ -563,7 +574,7 @@ impl<'a> Transaction<'a> {
|
||||
match result {
|
||||
Err(err) => {
|
||||
warn!("infrastructure ROLLBACK STARTED! an error occurred {:?}", err);
|
||||
match self.rollback() {
|
||||
match self.rollback(logger) {
|
||||
Ok(_) => {
|
||||
// an error occurred on infrastructure deployment BUT rolledback is OK
|
||||
send_progress(&lh, action, execution_id, true);
|
||||
@@ -591,6 +602,7 @@ impl<'a> Transaction<'a> {
|
||||
environment_action: &EnvironmentAction,
|
||||
applications_by_environment: &HashMap<&Environment, Vec<Box<dyn Application>>>,
|
||||
action_fn: F,
|
||||
logger: Box<dyn Logger>,
|
||||
) -> TransactionResult
|
||||
where
|
||||
F: Fn(&crate::cloud_provider::environment::Environment) -> Result<(), EngineError>,
|
||||
@@ -609,9 +621,10 @@ impl<'a> Transaction<'a> {
|
||||
self.engine.context(),
|
||||
built_applications,
|
||||
kubernetes.cloud_provider(),
|
||||
logger.clone(),
|
||||
);
|
||||
|
||||
let _ = match self.check_environment(&qe_environment) {
|
||||
let _ = match self.check_environment(&qe_environment, logger.clone()) {
|
||||
TransactionResult::Ok => {}
|
||||
err => return err, // which it means that an error occurred
|
||||
};
|
||||
@@ -661,7 +674,7 @@ impl<'a> Transaction<'a> {
|
||||
|
||||
let _ = match action_fn(&qe_environment) {
|
||||
Err(err) => {
|
||||
let rollback_result = match self.rollback() {
|
||||
let rollback_result = match self.rollback(logger) {
|
||||
Ok(_) => TransactionResult::Rollback(err),
|
||||
Err(rollback_err) => {
|
||||
error!("ROLLBACK FAILED! fatal error: {:?}", rollback_err);
|
||||
|
||||
@@ -66,7 +66,7 @@ impl Cluster<AWS, Options> for AWS {
|
||||
let container_registry = Box::new(container_registry_ecr(context));
|
||||
|
||||
// use LocalDocker
|
||||
let build_platform = Box::new(build_platform_local_docker(context));
|
||||
let build_platform = Box::new(build_platform_local_docker(context, logger.clone()));
|
||||
|
||||
// use AWS
|
||||
let cloud_provider = AWS::cloud_provider(context);
|
||||
|
||||
@@ -120,7 +120,7 @@ impl Infrastructure for Environment {
|
||||
},
|
||||
);
|
||||
|
||||
tx.commit()
|
||||
tx.commit(logger.clone())
|
||||
}
|
||||
|
||||
fn pause_environment(
|
||||
@@ -151,7 +151,7 @@ impl Infrastructure for Environment {
|
||||
|
||||
let _ = tx.pause_environment(k.as_ref(), &environment_action);
|
||||
|
||||
tx.commit()
|
||||
tx.commit(logger.clone())
|
||||
}
|
||||
|
||||
fn delete_environment(
|
||||
@@ -182,7 +182,7 @@ impl Infrastructure for Environment {
|
||||
|
||||
let _ = tx.delete_environment(k.as_ref(), &environment_action);
|
||||
|
||||
tx.commit()
|
||||
tx.commit(logger.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -990,6 +990,7 @@ pub fn test_db(
|
||||
let context_for_delete = context.clone_not_same_execution_id();
|
||||
|
||||
let app_id = generate_id();
|
||||
|
||||
let database_username = "superuser".to_string();
|
||||
let database_password = generate_password(true);
|
||||
let db_kind_str = db_kind.name().to_string();
|
||||
@@ -1384,7 +1385,7 @@ pub fn cluster_test(
|
||||
if let Err(err) = deploy_tx.create_kubernetes(kubernetes.as_ref()) {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
assert!(matches!(deploy_tx.commit(), TransactionResult::Ok));
|
||||
assert!(matches!(deploy_tx.commit(logger.clone()), TransactionResult::Ok));
|
||||
|
||||
// Deploy env if any
|
||||
if let Some(env) = environment_to_deploy {
|
||||
@@ -1395,7 +1396,7 @@ pub fn cluster_test(
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
|
||||
assert!(matches!(deploy_env_tx.commit(), TransactionResult::Ok));
|
||||
assert!(matches!(deploy_env_tx.commit(logger.clone()), TransactionResult::Ok));
|
||||
}
|
||||
|
||||
if let Err(err) = metrics_server_test(
|
||||
@@ -1417,14 +1418,14 @@ pub fn cluster_test(
|
||||
if let Err(err) = pause_tx.pause_kubernetes(kubernetes.as_ref()) {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
assert!(matches!(pause_tx.commit(), TransactionResult::Ok));
|
||||
assert!(matches!(pause_tx.commit(logger.clone()), TransactionResult::Ok));
|
||||
|
||||
// Resume
|
||||
if let Err(err) = resume_tx.create_kubernetes(kubernetes.as_ref()) {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
|
||||
assert!(matches!(resume_tx.commit(), TransactionResult::Ok));
|
||||
assert!(matches!(resume_tx.commit(logger.clone()), TransactionResult::Ok));
|
||||
|
||||
if let Err(err) = metrics_server_test(
|
||||
kubernetes
|
||||
@@ -1458,7 +1459,7 @@ pub fn cluster_test(
|
||||
if let Err(err) = upgrade_tx.create_kubernetes(upgraded_kubernetes.as_ref()) {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
assert!(matches!(upgrade_tx.commit(), TransactionResult::Ok));
|
||||
assert!(matches!(upgrade_tx.commit(logger.clone()), TransactionResult::Ok));
|
||||
|
||||
if let Err(err) = metrics_server_test(
|
||||
upgraded_kubernetes
|
||||
@@ -1477,7 +1478,7 @@ pub fn cluster_test(
|
||||
if let Err(err) = delete_tx.delete_kubernetes(upgraded_kubernetes.as_ref()) {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
assert!(matches!(delete_tx.commit(), TransactionResult::Ok));
|
||||
assert!(matches!(delete_tx.commit(logger.clone()), TransactionResult::Ok));
|
||||
|
||||
return test_name.to_string();
|
||||
}
|
||||
@@ -1491,14 +1492,14 @@ pub fn cluster_test(
|
||||
if let Err(err) = destroy_env_tx.delete_environment(kubernetes.as_ref(), env) {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
assert!(matches!(destroy_env_tx.commit(), TransactionResult::Ok));
|
||||
assert!(matches!(destroy_env_tx.commit(logger.clone()), TransactionResult::Ok));
|
||||
}
|
||||
|
||||
// Delete
|
||||
if let Err(err) = delete_tx.delete_kubernetes(kubernetes.as_ref()) {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
assert!(matches!(delete_tx.commit(), TransactionResult::Ok));
|
||||
assert!(matches!(delete_tx.commit(logger.clone()), TransactionResult::Ok));
|
||||
|
||||
test_name.to_string()
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ impl Cluster<DO, DoksOptions> for DO {
|
||||
// use DigitalOcean Container Registry
|
||||
let container_registry = Box::new(container_registry_digital_ocean(context));
|
||||
// use LocalDocker
|
||||
let build_platform = Box::new(build_platform_local_docker(context));
|
||||
let build_platform = Box::new(build_platform_local_docker(context, logger.clone()));
|
||||
// use Digital Ocean
|
||||
let cloud_provider = DO::cloud_provider(context);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(deprecated)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate maplit;
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ impl Cluster<Scaleway, KapsuleOptions> for Scaleway {
|
||||
let container_registry = Box::new(container_registry_scw(context));
|
||||
|
||||
// use LocalDocker
|
||||
let build_platform = Box::new(build_platform_local_docker(context));
|
||||
let build_platform = Box::new(build_platform_local_docker(context, logger.clone()));
|
||||
|
||||
// use Scaleway
|
||||
let cloud_provider = Scaleway::cloud_provider(context);
|
||||
|
||||
@@ -362,8 +362,8 @@ impl FuncTestsSecrets {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_platform_local_docker(context: &Context) -> LocalDocker {
|
||||
LocalDocker::new(context.clone(), "oxqlm3r99vwcmvuj", "qovery-local-docker")
|
||||
pub fn build_platform_local_docker(context: &Context, logger: Box<dyn Logger>) -> LocalDocker {
|
||||
LocalDocker::new(context.clone(), "oxqlm3r99vwcmvuj", "qovery-local-docker", logger)
|
||||
}
|
||||
|
||||
pub fn init() -> Instant {
|
||||
|
||||
@@ -105,7 +105,7 @@ fn test_build_cache() {
|
||||
);
|
||||
|
||||
let ecr = container_registry_ecr(&context);
|
||||
let local_docker = build_platform_local_docker(&context);
|
||||
let local_docker = build_platform_local_docker(&context, logger());
|
||||
let app = environment.applications.first().unwrap();
|
||||
let image = app.to_image();
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ fn test_build_cache() {
|
||||
);
|
||||
|
||||
let docr = container_registry_digital_ocean(&context);
|
||||
let local_docker = build_platform_local_docker(&context);
|
||||
let local_docker = build_platform_local_docker(&context, logger());
|
||||
let app = environment.applications.first().unwrap();
|
||||
let image = app.to_image();
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ fn create_digitalocean_kubernetes_doks_test_cluster() {
|
||||
if let Err(err) = tx.create_kubernetes(&kubernetes) {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
let ret = tx.commit();
|
||||
let ret = tx.commit(logger.clone());
|
||||
assert!(matches!(ret, TransactionResult::Ok));
|
||||
|
||||
test_name.to_string()
|
||||
@@ -129,7 +129,7 @@ fn destroy_digitalocean_kubernetes_doks_test_cluster() {
|
||||
if let Err(err) = tx.delete_kubernetes(&kubernetes) {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
let ret = tx.commit();
|
||||
let ret = tx.commit(logger.clone());
|
||||
assert!(matches!(ret, TransactionResult::Ok));
|
||||
|
||||
test_name.to_string()
|
||||
|
||||
@@ -112,7 +112,7 @@ fn test_build_cache() {
|
||||
);
|
||||
|
||||
let scr = container_registry_scw(&context);
|
||||
let local_docker = build_platform_local_docker(&context);
|
||||
let local_docker = build_platform_local_docker(&context, logger());
|
||||
let app = environment.applications.first().unwrap();
|
||||
let image = app.to_image();
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ fn create_scaleway_kubernetes_kapsule_test_cluster() {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
|
||||
assert!(matches!(tx.commit(), TransactionResult::Ok));
|
||||
assert!(matches!(tx.commit(logger.clone()), TransactionResult::Ok));
|
||||
|
||||
test_name.to_string()
|
||||
});
|
||||
@@ -127,7 +127,7 @@ fn destroy_scaleway_kubernetes_kapsule_test_cluster() {
|
||||
if let Err(err) = tx.delete_kubernetes(&kubernetes) {
|
||||
panic!("{:?}", err)
|
||||
}
|
||||
let ret = tx.commit();
|
||||
let ret = tx.commit(logger.clone());
|
||||
assert!(matches!(ret, TransactionResult::Ok));
|
||||
|
||||
test_name.to_string()
|
||||
|
||||
Reference in New Issue
Block a user