feat: introduce new error handling models (#503)

Ticket: DEV-1004
This commit is contained in:
Benjamin
2021-11-25 20:00:39 +01:00
committed by GitHub
parent f84e1b171e
commit d63cc03e31
7 changed files with 433 additions and 10 deletions

1
Cargo.lock generated
View File

@@ -2110,6 +2110,7 @@ dependencies = [
"tracing-subscriber",
"tracing-test",
"trust-dns-resolver",
"url 2.2.2",
"uuid 0.8.2",
"walkdir",
]

View File

@@ -25,6 +25,7 @@ futures = "0.3.15"
timeout-readwrite = "0.3.1"
lazy_static = "1.4.0"
uuid = { version = "0.8", features = ["v4"] }
url = "2.2.2"
function_name = "0.2.0"
# FIXME use https://crates.io/crates/blocking instead of runtime.rs

132
src/errors/io.rs Normal file
View File

@@ -0,0 +1,132 @@
use super::url::Url;
use crate::cloud_provider::Kind;
use crate::errors;
use crate::models::QoveryIdentifier;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
#[derive(Serialize, Deserialize)]
pub enum LogLevel {
Debug,
Info,
Warning,
Error,
}
impl From<LogLevel> for errors::LogLevel {
fn from(log_level: LogLevel) -> Self {
match log_level {
LogLevel::Debug => errors::LogLevel::Debug,
LogLevel::Info => errors::LogLevel::Info,
LogLevel::Warning => errors::LogLevel::Warning,
LogLevel::Error => errors::LogLevel::Error,
}
}
}
#[derive(Serialize, Deserialize)]
pub enum Stage {
Infrastructure(InfrastructureStep),
Environment(EnvironmentStep),
}
impl From<Stage> for errors::Stage {
fn from(stage: Stage) -> Self {
match stage {
Stage::Infrastructure(steps) => errors::Stage::Infrastructure(errors::InfrastructureStep::from(steps)),
Stage::Environment(steps) => errors::Stage::Environment(errors::EnvironmentStep::from(steps)),
}
}
}
#[derive(Serialize, Deserialize)]
pub enum InfrastructureStep {
Instantiate,
Create,
Pause,
Upgrade,
Delete,
}
impl From<InfrastructureStep> for errors::InfrastructureStep {
fn from(step: InfrastructureStep) -> Self {
match step {
InfrastructureStep::Instantiate => errors::InfrastructureStep::Instantiate,
InfrastructureStep::Create => errors::InfrastructureStep::Create,
InfrastructureStep::Upgrade => errors::InfrastructureStep::Upgrade,
InfrastructureStep::Delete => errors::InfrastructureStep::Delete,
InfrastructureStep::Pause => errors::InfrastructureStep::Pause,
}
}
}
#[derive(Serialize, Deserialize)]
pub enum EnvironmentStep {
Build,
Deploy,
Update,
Delete,
}
impl From<EnvironmentStep> for errors::EnvironmentStep {
fn from(step: EnvironmentStep) -> Self {
match step {
EnvironmentStep::Build => errors::EnvironmentStep::Build,
EnvironmentStep::Deploy => errors::EnvironmentStep::Deploy,
EnvironmentStep::Update => errors::EnvironmentStep::Update,
EnvironmentStep::Delete => errors::EnvironmentStep::Delete,
}
}
}
#[derive(Serialize, Deserialize)]
pub enum Tag {
UnsupportedInstanceType(String),
}
impl From<Tag> for errors::Tag {
fn from(tag: Tag) -> Self {
match tag {
Tag::UnsupportedInstanceType(s) => errors::Tag::UnsupportedInstanceType(s),
}
}
}
#[derive(Serialize, Deserialize)]
struct UserEngineError {
provider_kind: Kind,
organisation_id: String,
cluster_id: String,
execution_id: String,
tag: Tag,
stage: Stage,
log_level: LogLevel,
log_message: String,
raw_message_safe: Option<String>,
link: Option<String>,
hint_message: Option<String>,
}
impl From<UserEngineError> for errors::UserEngineError {
fn from(e: UserEngineError) -> Self {
errors::UserEngineError::new(
e.provider_kind,
QoveryIdentifier::new(e.organisation_id),
QoveryIdentifier::new(e.cluster_id),
QoveryIdentifier::new(e.execution_id),
errors::Tag::from(e.tag),
errors::Stage::from(e.stage),
errors::LogLevel::from(e.log_level),
e.log_message,
e.raw_message_safe,
match e.link {
Some(url) => match Url::from_str(&url) {
Ok(url) => Some(url),
Err(_) => None,
},
None => None,
},
e.hint_message,
)
}
}

253
src/errors/mod.rs Normal file
View File

@@ -0,0 +1,253 @@
pub mod io;
extern crate url;
use crate::cloud_provider::Kind;
use crate::models::QoveryIdentifier;
use url::Url;
pub struct SimpleError {
message: String,
message_safe: String,
}
#[derive(Debug)]
pub enum LogLevel {
Debug,
Info,
Warning,
Error,
}
#[derive(Debug)]
pub enum Stage {
Infrastructure(InfrastructureStep),
Environment(EnvironmentStep),
}
#[derive(Debug)]
pub enum InfrastructureStep {
Instantiate,
Create,
Pause,
Upgrade,
Delete,
}
#[derive(Debug)]
pub enum EnvironmentStep {
Build,
Deploy,
Update,
Delete,
}
#[derive(Debug)]
pub enum Tag {
UnsupportedInstanceType(String),
}
impl SimpleError {
pub fn message(&self) -> &str {
&self.message
}
pub fn message_safe(&self) -> &str {
&self.message_safe
}
pub fn new_from_safe_message(message: String) -> Self {
SimpleError::new(message.clone(), message)
}
pub fn new(message: String, message_safe: String) -> Self {
SimpleError { message, message_safe }
}
}
#[derive(Debug)]
pub struct UserEngineError {
provider_kind: Kind,
organisation_id: QoveryIdentifier,
cluster_id: QoveryIdentifier,
execution_id: QoveryIdentifier,
tag: Tag,
stage: Stage,
log_level: LogLevel,
log_message: String,
raw_message_safe: Option<String>,
link: Option<Url>,
hint_message: Option<String>,
}
impl UserEngineError {
pub fn new(
provider_kind: Kind,
organisation_id: QoveryIdentifier,
cluster_id: QoveryIdentifier,
execution_id: QoveryIdentifier,
tag: Tag,
stage: Stage,
log_level: LogLevel,
log_message: String,
raw_message_safe: Option<String>,
link: Option<Url>,
hint_message: Option<String>,
) -> Self {
UserEngineError {
provider_kind,
organisation_id,
cluster_id,
execution_id,
tag,
stage,
log_level,
log_message,
raw_message_safe,
link,
hint_message,
}
}
}
impl From<EngineError> for UserEngineError {
fn from(error: EngineError) -> Self {
UserEngineError::new(
error.provider_kind,
error.organisation_id,
error.cluster_id,
error.execution_id,
error.tag,
error.stage,
error.user_log_level,
error.user_log_message,
error.raw_message_without_secrets,
error.link,
error.hint_message,
)
}
}
#[derive(Debug)]
pub struct EngineError {
provider_kind: Kind,
tag: Tag,
organisation_id: QoveryIdentifier,
cluster_id: QoveryIdentifier,
execution_id: QoveryIdentifier,
stage: Stage,
qovery_log_level: LogLevel,
qovery_log_message: String,
user_log_level: LogLevel,
user_log_message: String,
raw_message: Option<String>,
raw_message_without_secrets: Option<String>,
link: Option<Url>,
hint_message: Option<String>,
}
impl EngineError {
pub fn provider_kind(&self) -> &Kind {
&self.provider_kind
}
pub fn tag(&self) -> &Tag {
&self.tag
}
pub fn execution_id(&self) -> &QoveryIdentifier {
&self.execution_id
}
pub fn stage(&self) -> &Stage {
&self.stage
}
pub fn qovery_log_level(&self) -> &LogLevel {
&self.qovery_log_level
}
pub fn qovery_log_message(&self) -> &str {
&self.qovery_log_message
}
pub fn user_log_level(&self) -> &LogLevel {
&self.user_log_level
}
pub fn user_log_message(&self) -> &str {
&self.user_log_message
}
pub fn raw_message(&self) -> Option<String> {
self.raw_message.clone()
}
pub fn raw_message_without_secrets(&self) -> Option<String> {
self.raw_message_without_secrets.clone()
}
pub fn link(&self) -> &Option<Url> {
&self.link
}
pub fn hint_message(&self) -> &Option<String> {
&self.hint_message
}
fn new(
provider_kind: Kind,
tag: Tag,
organisation_id: QoveryIdentifier,
cluster_id: QoveryIdentifier,
execution_id: QoveryIdentifier,
stage: Stage,
qovery_log_level: LogLevel,
qovery_log_message: String,
user_log_level: LogLevel,
user_log_message: String,
raw_message: Option<String>,
raw_message_without_secrets: Option<String>,
link: Option<Url>,
hint_message: Option<String>,
) -> Self {
EngineError {
provider_kind,
tag,
stage,
organisation_id,
cluster_id,
execution_id,
qovery_log_level,
qovery_log_message,
user_log_level,
user_log_message,
raw_message,
raw_message_without_secrets,
link,
hint_message,
}
}
pub fn to_user_error(self) -> UserEngineError {
UserEngineError::from(self)
}
pub fn new_unsupported_instance_type(
provider_kind: Kind,
organisation_id: QoveryIdentifier,
cluster_id: QoveryIdentifier,
execution_id: QoveryIdentifier,
stage: Stage,
requested_instance_type: &str,
raw_message: Option<String>,
raw_message_safe: Option<String>,
) -> EngineError {
let message = format!("`{}` instance type is not supported", requested_instance_type);
EngineError::new(
provider_kind,
Tag::UnsupportedInstanceType(requested_instance_type.to_string()),
organisation_id,
cluster_id,
execution_id,
stage,
LogLevel::Error,
message.to_string(),
LogLevel::Error,
message.to_string(),
raw_message,
raw_message_safe,
None, // TODO(documentation): Create a page entry to details this error
Some("Selected instance type is not supported, please check provider's documentation.".to_string()),
)
}
}

View File

@@ -13,6 +13,7 @@ mod deletion_utilities;
pub mod dns_provider;
pub mod engine;
pub mod error;
pub mod errors;
pub mod fs;
pub mod git;
pub mod models;

View File

@@ -17,9 +17,43 @@ use crate::cloud_provider::CloudProvider;
use crate::cloud_provider::Kind as CPKind;
use crate::git::Credentials;
use std::collections::BTreeMap;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use std::sync::Arc;
#[derive(Clone, Debug)]
pub struct QoveryIdentifier {
raw: String,
short: String,
}
impl QoveryIdentifier {
pub fn new(raw: String) -> Self {
QoveryIdentifier {
raw: raw.to_string(),
short: QoveryIdentifier::extract_short(raw.as_str()),
}
}
fn extract_short(raw: &str) -> String {
let max_execution_id_chars: usize = 7;
match raw.char_indices().nth(max_execution_id_chars) {
None => raw.to_string(),
Some((idx, _)) => raw[..idx].to_string(),
}
}
pub fn short(&self) -> &str {
&self.short
}
}
impl Display for QoveryIdentifier {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.raw.as_str())
}
}
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
pub enum EnvironmentAction {
Environment(TargetEnvironment),

View File

@@ -973,7 +973,7 @@ dependencies = [
"log",
"openssl-probe",
"openssl-sys",
"url 2.2.0",
"url 2.2.2",
]
[[package]]
@@ -1077,7 +1077,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"url 2.2.0",
"url 2.2.2",
]
[[package]]
@@ -2094,7 +2094,7 @@ dependencies = [
"idna 0.2.0",
"lazy_static",
"regex",
"url 2.2.0",
"url 2.2.2",
]
[[package]]
@@ -2139,6 +2139,7 @@ dependencies = [
"tracing-subscriber",
"tracing-test",
"trust-dns-resolver",
"url 2.2.2",
"uuid 0.8.2",
"walkdir",
]
@@ -2566,7 +2567,7 @@ dependencies = [
"serde_urlencoded 0.6.1",
"tokio 0.2.24",
"tokio-tls",
"url 2.2.0",
"url 2.2.2",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
@@ -2602,7 +2603,7 @@ dependencies = [
"serde_urlencoded 0.7.0",
"tokio 1.10.0",
"tokio-native-tls",
"url 2.2.0",
"url 2.2.2",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
@@ -2840,7 +2841,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"url 2.2.0",
"url 2.2.2",
]
[[package]]
@@ -2961,7 +2962,7 @@ dependencies = [
"dtoa",
"itoa",
"serde",
"url 2.2.0",
"url 2.2.2",
]
[[package]]
@@ -3760,7 +3761,7 @@ dependencies = [
"thiserror",
"tinyvec",
"tokio 1.10.0",
"url 2.2.0",
"url 2.2.2",
]
[[package]]
@@ -3918,9 +3919,9 @@ dependencies = [
[[package]]
name = "url"
version = "2.2.0"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna 0.2.0",