From bce17f8a99a166781f600351e0fad4ad97eb577e Mon Sep 17 00:00:00 2001 From: Romaric Philogene Date: Mon, 21 Dec 2020 12:07:00 +0100 Subject: [PATCH] wip: check domain propagation --- Cargo.lock | 147 +++++++++++++++-- Cargo.toml | 2 +- src/cloud_provider/aws/router.rs | 153 ++++++++++++------ .../digitalocean/kubernetes/mod.rs | 12 ++ src/cloud_provider/mod.rs | 3 +- src/lib.rs | 5 +- src/models.rs | 15 +- tests/digitalocean/do_environment.rs | 4 +- tests/digitalocean/mod.rs | 2 +- 9 files changed, 261 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5e0efb4..f4782e6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -498,18 +498,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" -[[package]] -name = "dns-lookup" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093d88961fd18c4ecacb8c80cd0b356463ba941ba11e0e01f9cf5271380b79dc" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "socket2", - "winapi 0.3.9", -] - [[package]] name = "dtoa" version = "0.4.6" @@ -531,6 +519,18 @@ dependencies = [ "cfg-if 0.1.10", ] +[[package]] +name = "enum-as-inner" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" +dependencies = [ + "heck", + "proc-macro2 1.0.24", + "quote 1.0.7", + "syn 1.0.48", +] + [[package]] name = "error-chain" version = "0.12.4" @@ -915,6 +915,15 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hermit-abi" version = "0.1.17" @@ -940,6 +949,17 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi 0.3.9", +] + [[package]] name = "http" version = "0.1.21" @@ -1141,6 +1161,18 @@ dependencies = [ "libc", ] +[[package]] +name = "ipconfig" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" +dependencies = [ + "socket2", + "widestring", + "winapi 0.3.9", + "winreg 0.6.2", +] + [[package]] name = "ipnet" version = "2.3.0" @@ -1242,6 +1274,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linked-hash-map" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" + [[package]] name = "lock_api" version = "0.3.4" @@ -1273,12 +1311,27 @@ dependencies = [ "serde_json", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "maplit" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.0.1" @@ -1732,7 +1785,6 @@ dependencies = [ "cmd_lib", "digitalocean", "dirs 3.0.1", - "dns-lookup", "flate2", "fs2", "futures 0.3.7", @@ -1759,9 +1811,16 @@ dependencies = [ "tokio 0.2.22", "tracing", "tracing-subscriber", + "trust-dns-resolver", "walkdir", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "0.6.13" @@ -2082,6 +2141,16 @@ dependencies = [ "winreg 0.7.0", ] +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + [[package]] name = "retry" version = "1.1.0" @@ -3052,6 +3121,46 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "trust-dns-proto" +version = "0.19.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53861fcb288a166aae4c508ae558ed18b53838db728d4d310aad08270a7d4c2b" +dependencies = [ + "async-trait", + "backtrace", + "enum-as-inner", + "futures 0.3.7", + "idna 0.2.0", + "lazy_static", + "log", + "rand 0.7.3", + "smallvec 1.5.0", + "thiserror", + "tokio 0.2.22", + "url 2.1.1", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.19.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6759e8efc40465547b0dfce9500d733c65f969a4cbbfbe3ccf68daaa46ef179e" +dependencies = [ + "backtrace", + "cfg-if 0.1.10", + "futures 0.3.7", + "ipconfig", + "lazy_static", + "log", + "lru-cache", + "resolv-conf", + "smallvec 1.5.0", + "thiserror", + "tokio 0.2.22", + "trust-dns-proto", +] + [[package]] name = "try-lock" version = "0.2.3" @@ -3156,6 +3265,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" + [[package]] name = "unicode-xid" version = "0.1.0" @@ -3343,6 +3458,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "widestring" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" + [[package]] name = "winapi" version = "0.2.8" diff --git a/Cargo.toml b/Cargo.toml index d164823d..3d0e3cab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ base64 = "0.12.3" dirs = "3.0.1" rust-crypto = "0.2.36" retry = "1.0.0" -dns-lookup = "1.0.3" +trust-dns-resolver = "0.19.6" rand = "0.7.3" gethostname = "0.2.1" reqwest = { version = "0.10.8", features = ["blocking"] } diff --git a/src/cloud_provider/aws/router.rs b/src/cloud_provider/aws/router.rs index f67e6dde..7c67f60f 100644 --- a/src/cloud_provider/aws/router.rs +++ b/src/cloud_provider/aws/router.rs @@ -1,8 +1,14 @@ -use dns_lookup::lookup_host; -use retry::delay::Fibonacci; +use futures::io::Error; +use retry::delay::{Fibonacci, Fixed}; use retry::OperationResult; use serde::{Deserialize, Serialize}; use tera::Context as TeraContext; +use trust_dns_resolver::config::{ResolverConfig, ResolverOpts}; +use trust_dns_resolver::error::ResolveError; +use trust_dns_resolver::lookup_ip::LookupIp; +use trust_dns_resolver::Resolver; + +use dns_lookup::lookup_host; use crate::cloud_provider::aws::{common, AWS}; use crate::cloud_provider::environment::Environment; @@ -14,7 +20,9 @@ use crate::cloud_provider::DeploymentTarget; use crate::cmd::helm::Timeout; use crate::constants::{AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY}; use crate::error::{cast_simple_error_to_engine_error, EngineError, EngineErrorCause}; -use crate::models::{Context, Listeners}; +use crate::models::{ + Context, Listeners, ListenersHelper, ProgressInfo, ProgressLevel, ProgressScope, +}; pub struct Router { context: Context, @@ -479,51 +487,100 @@ impl Create for Router { } fn on_create_check(&self) -> Result<(), EngineError> { - // FIXME remove this - return Ok(()); - // - // // TODO ------------------------------------------------------------- - // // TODO integration tests required before using DNS propagation check - // // TODO ------------------------------------------------------------- - // let listeners_helper = ListenersHelper::new(&self.listeners); - // // Todo: inform the client about the fact we're going to check for a certain amount of time - // - // let check_result = retry::retry(Fixed::from_millis(3000).take(200), || { - // let rs_ips = lookup_host(self.default_domain.as_str()); - // match rs_ips { - // Ok(ips) => { - // info!("Records from DNS are successfully retrieved."); - // OperationResult::Ok(ips) - // } - // Err(err) => { - // warn!( - // "Failed to retrieve record from DNS '{}', retrying...", - // self.default_domain.as_str() - // ); - // warn!("DNS lookup error: {:?}", err); - // OperationResult::Retry(err) - // } - // } - // }); - // - // match check_result { - // Ok(_) => Ok(()), - // Err(_) => { - // let message = format!("Wasn't able to check DNS availability '{}', can be due to a too long DNS propagation. Please retry and contact your administrator if the problem persists", self.default_domain.as_str()); - // error!("{}", message); - // - // listeners_helper.error(ProgressInfo::new( - // ProgressScope::Router { - // id: self.id().into(), - // }, - // ProgressLevel::Error, - // Some("DNS propagation goes wrong."), - // self.context.execution_id(), - // )); - // // TODO: fixme I shouldn't return OK but I think I have a cache issue - // Ok(()) - // } - // } + let listeners_helper = ListenersHelper::new(&self.listeners); + + listeners_helper.start_in_progress(ProgressInfo::new( + ProgressScope::Router { + id: self.id().into(), + }, + ProgressLevel::Info, + Some(format!( + "Let's check that {} domain is ready. Please wait, it can take some time...", + self.name_with_id() + )), + self.context.execution_id(), + )); + + let mut resolver_options = ResolverOpts::default(); + resolver_options.cache_size = 0; + resolver_options.use_hosts_file = false; + + let resolver = match Resolver::new(ResolverConfig::google(), resolver_options) { + Ok(resolver) => resolver, + Err(err) => { + error!("{:?}", err); + return Err(self.engine_error( + EngineErrorCause::Internal, + format!("can't get DNS resolver {:?}", err), + )); + } + }; + + let check_result = retry::retry(Fixed::from_millis(3000).take(200), || { + match resolver.lookup_ip(self.default_domain.as_str()) { + Ok(x) => OperationResult::Ok(x), + Err(err) => { + let x = format!( + "Check for {} domain still in progress...", + self.default_domain.as_str() + ); + + warn!("{}", x); + + listeners_helper.start_in_progress(ProgressInfo::new( + ProgressScope::Router { + id: self.id().into(), + }, + ProgressLevel::Info, + Some(x), + self.context.execution_id(), + )); + + OperationResult::Retry(err) + } + } + }); + + match check_result { + Ok(_) => { + let x = format!("Domain {} is ready! ⚡️", self.default_domain.as_str()); + + info!("{}", x); + + listeners_helper.start_in_progress(ProgressInfo::new( + ProgressScope::Router { + id: self.id().into(), + }, + ProgressLevel::Info, + Some(x), + self.context.execution_id(), + )); + + Ok(()) + } + Err(_) => { + let message = format!( + "Wasn't able to check domain availability for {}. \ + It can be due to a too long DNS propagation. \ + Please retry and contact your administrator \ + if the problem persists", + self.default_domain.as_str() + ); + + error!("{}", message); + + listeners_helper.error(ProgressInfo::new( + ProgressScope::Router { + id: self.id().into(), + }, + ProgressLevel::Error, + Some(message), + self.context.execution_id(), + )); + + Ok(()) + } + } } fn on_create_error(&self, target: &DeploymentTarget) -> Result<(), EngineError> { diff --git a/src/cloud_provider/digitalocean/kubernetes/mod.rs b/src/cloud_provider/digitalocean/kubernetes/mod.rs index e6b66be1..6a48af34 100644 --- a/src/cloud_provider/digitalocean/kubernetes/mod.rs +++ b/src/cloud_provider/digitalocean/kubernetes/mod.rs @@ -118,10 +118,12 @@ impl<'a> DOKS<'a> { "engine_version_controller_token", &self.options.engine_version_controller_token, ); + context.insert( "agent_version_controller_token", &self.options.agent_version_controller_token, ); + context.insert("test_cluster", &test_cluster); context.insert("qovery_api_url", self.options.qovery_api_url.as_str()); context.insert("qovery_nats_url", self.options.qovery_nats_url.as_str()); @@ -144,6 +146,7 @@ impl<'a> DOKS<'a> { true => "https://acme-staging-v02.api.letsencrypt.org/directory", false => "https://acme-v02.api.letsencrypt.org/directory", }; + context.insert("acme_server_url", lets_encrypt_url); context.insert("dns_email_report", &self.options.tls_email_report); @@ -152,22 +155,27 @@ impl<'a> DOKS<'a> { let managed_dns_domains_helm_format = vec![format!("\"{}\"", self.dns_provider.domain())]; let managed_dns_domains_terraform_format = terraform_list_format(vec![self.dns_provider.domain().to_string()]); + let managed_dns_resolvers: Vec = self .dns_provider .resolvers() .iter() .map(|x| format!("{}", x.clone().to_string())) .collect(); + let managed_dns_resolvers_terraform_format = terraform_list_format(managed_dns_resolvers); + context.insert("managed_dns", &managed_dns_list); context.insert( "managed_dns_domains_helm_format", &managed_dns_domains_helm_format, ); + context.insert( "managed_dns_domains_terraform_format", &managed_dns_domains_terraform_format, ); + context.insert( "managed_dns_resolvers_terraform_format", &managed_dns_resolvers_terraform_format, @@ -188,6 +196,7 @@ impl<'a> DOKS<'a> { // Sapces Credentiales context.insert("spaces_access_id", &self.cloud_provider.spaces_access_id); context.insert("spaces_secret_key", &self.cloud_provider.spaces_secret_key); + let space_kubeconfig_bucket = get_space_bucket_kubeconfig_name(self.id.clone()); context.insert("space_bucket_kubeconfig", &space_kubeconfig_bucket); @@ -207,6 +216,7 @@ impl<'a> DOKS<'a> { .secret_access_key .as_str(), ); + context.insert( "aws_region_tfstates_account", self.cloud_provider() @@ -219,6 +229,7 @@ impl<'a> DOKS<'a> { "aws_terraform_backend_dynamodb_table", "qovery-terrafom-tfstates", ); + context.insert("aws_terraform_backend_bucket", "qovery-terrafom-tfstates"); // kubernetes workers @@ -235,6 +246,7 @@ impl<'a> DOKS<'a> { min_size: nodes.len().to_string(), }) .collect::>(); + context.insert("oks_worker_nodes", &worker_nodes); context diff --git a/src/cloud_provider/mod.rs b/src/cloud_provider/mod.rs index 5d3b10f7..086925df 100644 --- a/src/cloud_provider/mod.rs +++ b/src/cloud_provider/mod.rs @@ -8,12 +8,12 @@ use crate::error::{EngineError, EngineErrorCause, EngineErrorScope}; use crate::models::{Context, Listener}; pub mod aws; +mod common; pub mod digitalocean; pub mod environment; pub mod gcp; pub mod kubernetes; pub mod service; -mod common; pub trait CloudProvider { fn context(&self) -> &Context; @@ -44,7 +44,6 @@ pub trait CloudProvider { #[derive(Serialize, Deserialize, Clone)] pub enum Kind { AWS, - GCP, DO, } diff --git a/src/lib.rs b/src/lib.rs index 05fe9e39..cc80c5ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ +extern crate tera; #[macro_use] extern crate tracing; -extern crate tera; +extern crate trust_dns_resolver; pub mod build_platform; pub mod cloud_provider; @@ -16,6 +17,7 @@ pub mod error; pub mod fs; pub mod git; pub mod models; +mod object_storage; mod runtime; pub mod s3; pub mod session; @@ -24,4 +26,3 @@ mod template; pub mod transaction; mod unit_conversion; mod utilities; -mod object_storage; diff --git a/src/models.rs b/src/models.rs index fa5294d4..0c446bd2 100644 --- a/src/models.rs +++ b/src/models.rs @@ -197,7 +197,6 @@ impl Application { .collect::>(), ), )), - CPKind::GCP => None, CPKind::DO => Some(Box::new( crate::cloud_provider::digitalocean::application::Application::new( context.clone(), @@ -217,7 +216,6 @@ impl Application { .collect::>(), ), )), - //TODO to implement } } @@ -251,7 +249,6 @@ impl Application { .collect::>(), ), )), - CPKind::GCP => None, CPKind::DO => Some(Box::new( crate::cloud_provider::digitalocean::application::Application::new( context.clone(), @@ -271,7 +268,6 @@ impl Application { .collect::>(), ), )), - //TODO to implement } } @@ -435,9 +431,6 @@ impl Router { )); Some(router) } - - CPKind::GCP => None, - CPKind::DO => { let router: Box = Box::new(crate::cloud_provider::digitalocean::router::Router::new( @@ -585,9 +578,7 @@ impl Database { Some(db) } }, - CPKind::GCP => None, - _ => None, - //TODO to implement + CPKind::DO => None, } } } @@ -641,9 +632,7 @@ impl ExternalService { .collect::>(), ), )), - CPKind::GCP => None, _ => None, - //TODO to implement } } @@ -669,9 +658,7 @@ impl ExternalService { .collect::>(), ), )), - CPKind::GCP => None, _ => None, - //TODO to implement } } diff --git a/tests/digitalocean/do_environment.rs b/tests/digitalocean/do_environment.rs index 016f63cd..9d689bf8 100644 --- a/tests/digitalocean/do_environment.rs +++ b/tests/digitalocean/do_environment.rs @@ -36,6 +36,7 @@ fn deploy_a_working_environment_with_no_router_on_do() { commit_id: "".to_string(), registry_url: None, }; + assert!(!registry.does_image_exists(&image)); match deploy_environment_on_do(&context, &ea) { @@ -51,9 +52,10 @@ fn deploy_a_working_environment_with_no_router_on_do() { .unwrap() .as_str() ); + assert!(registry.does_image_exists(&image)); /* - TODO: delete environement is not implemented yet + TODO: delete environment is not implemented yet match deploy_environment_on_do(&context_for_delete, &ea_delete) { TransactionResult::Ok => assert!(true), TransactionResult::Rollback(_) => assert!(false), diff --git a/tests/digitalocean/mod.rs b/tests/digitalocean/mod.rs index dfefbd6f..dbe6bab9 100644 --- a/tests/digitalocean/mod.rs +++ b/tests/digitalocean/mod.rs @@ -19,7 +19,7 @@ pub fn deploy_environment_on_do( let dns_provider = dns_provider_cloudflare(context); let k = test_utilities::digitalocean::do_kubernetes_ks(&context, &cp, &dns_provider, nodes); - tx.deploy_environment_with_options( + let _ = tx.deploy_environment_with_options( &k, &environment_action, DeploymentOption {