From 17964dbae7c0523b25ccaa53ff1c90bf765d0526 Mon Sep 17 00:00:00 2001 From: Pierre Mavro Date: Fri, 22 Oct 2021 20:09:34 +0200 Subject: [PATCH] fix: better support node numbers --- lib/aws/bootstrap/eks-workers-nodes.j2.tf | 7 +- .../bootstrap/doks-master-cluster.j2.tf | 8 +- .../bootstrap/doks-worker-node.j2.tf | 6 +- lib/scaleway/bootstrap/ks-workers-nodes.j2.tf | 8 +- src/cloud_provider/aws/kubernetes/mod.rs | 55 +++--- src/cloud_provider/aws/kubernetes/node.rs | 140 +++++++-------- .../digitalocean/kubernetes/mod.rs | 50 +++--- .../digitalocean/kubernetes/node.rs | 132 +++++++++----- src/cloud_provider/kubernetes.rs | 31 +++- src/cloud_provider/models.rs | 24 ++- src/cloud_provider/scaleway/kubernetes/mod.rs | 49 +++--- .../scaleway/kubernetes/node.rs | 162 +++++++++--------- test_utilities/src/aws.rs | 26 +-- test_utilities/src/digitalocean.rs | 18 +- test_utilities/src/scaleway.rs | 15 +- tests/aws/aws_kubernetes.rs | 9 +- tests/digitalocean/do_kubernetes.rs | 6 +- ...do_utility_kubernetes_doks_test_cluster.rs | 6 +- tests/scaleway/scw_kubernetes.rs | 6 +- ...utility_kubernetes_kapsule_test_cluster.rs | 9 +- 20 files changed, 425 insertions(+), 342 deletions(-) diff --git a/lib/aws/bootstrap/eks-workers-nodes.j2.tf b/lib/aws/bootstrap/eks-workers-nodes.j2.tf index 1d92dfb1..1ad60b3f 100644 --- a/lib/aws/bootstrap/eks-workers-nodes.j2.tf +++ b/lib/aws/bootstrap/eks-workers-nodes.j2.tf @@ -12,13 +12,14 @@ resource "aws_eks_node_group" "eks_cluster_workers_{{ loop.index }}" { local.tags_eks, { "QoveryNodeGroupId" = "${var.kubernetes_cluster_id}-{{ loop.index }}" + "QoveryNodeGroupName" = "{{ eks_worker_node.name }}" } ) scaling_config { - desired_size = "{{ eks_worker_node.desired_size }}" - max_size = "{{ eks_worker_node.max_size }}" - min_size = "{{ eks_worker_node.min_size }}" + desired_size = "{{ eks_worker_node.min_nodes }}" + max_size = "{{ eks_worker_node.max_nodes }}" + min_size = "{{ eks_worker_node.min_nodes }}" } lifecycle { diff --git a/lib/digitalocean/bootstrap/doks-master-cluster.j2.tf b/lib/digitalocean/bootstrap/doks-master-cluster.j2.tf index f44645c6..335a807d 100644 --- a/lib/digitalocean/bootstrap/doks-master-cluster.j2.tf +++ b/lib/digitalocean/bootstrap/doks-master-cluster.j2.tf @@ -8,15 +8,15 @@ resource "digitalocean_kubernetes_cluster" "kubernetes_cluster" { auto_upgrade = true surge_upgrade = true - tags = local.tags_ks_list + tags = concat(local.tags_ks_list, ["QoveryNodeGroupName:{{ doks_worker_nodes[0].name }}", "QoveryNodeGroupId:${var.kubernetes_cluster_id}-0"]) node_pool { - tags = local.tags_ks_list + tags = concat(local.tags_ks_list, ["QoveryNodeGroupName:{{ doks_worker_nodes[0].name }}", "QoveryNodeGroupId:${var.kubernetes_cluster_id}-0"]) name = var.kubernetes_cluster_id size = "{{ doks_worker_nodes[0].instance_type }}" # use Digital Ocean built-in cluster autoscaler auto_scale = true - min_nodes = "{{ doks_worker_nodes[0].min_size }}" - max_nodes = "{{ doks_worker_nodes[0].max_size }}" + min_nodes = "{{ doks_worker_nodes[0].min_nodes }}" + max_nodes = "{{ doks_worker_nodes[0].max_nodes }}" } } \ No newline at end of file diff --git a/lib/digitalocean/bootstrap/doks-worker-node.j2.tf b/lib/digitalocean/bootstrap/doks-worker-node.j2.tf index 4b139abd..0b741d6b 100644 --- a/lib/digitalocean/bootstrap/doks-worker-node.j2.tf +++ b/lib/digitalocean/bootstrap/doks-worker-node.j2.tf @@ -8,10 +8,10 @@ resource "digitalocean_kubernetes_node_pool" "app_node_pool_{{ loop.index }}" { name = "qovery-{{kubernetes_cluster_id}}-{{ loop.index }}" size = "{{ doks_worker_node.instance_type }}" - tags = local.tags_ks_list + tags = concat(local.tags_doks_list, ["QoveryNodeGroupId:${var.kubernetes_cluster_id}-{{ loop.index }}", "QoveryNodeGroupName:{{ eks_worker_node.name }}"]) auto_scale = true - min_nodes = "{{ doks_worker_node.min_size }}" - max_nodes = "{{ doks_worker_node.max_size }}" + min_nodes = {{ doks_worker_node.min_nodes }} + max_nodes = {{ doks_worker_node.max_nodes }} depends_on = [ digitalocean_kubernetes_cluster.kubernetes_cluster, diff --git a/lib/scaleway/bootstrap/ks-workers-nodes.j2.tf b/lib/scaleway/bootstrap/ks-workers-nodes.j2.tf index b76845fa..b23d5c8a 100644 --- a/lib/scaleway/bootstrap/ks-workers-nodes.j2.tf +++ b/lib/scaleway/bootstrap/ks-workers-nodes.j2.tf @@ -10,14 +10,14 @@ resource "scaleway_k8s_pool" "kubernetes_cluster_workers_{{ loop.index }}" { # use Scaleway built-in cluster autoscaler autoscaling = {{ scw_ks_pool_autoscale }} autohealing = true - size = "{{ scw_ks_worker_node.min_size }}" - min_size = "{{ scw_ks_worker_node.min_size }}" - max_size = "{{ scw_ks_worker_node.max_size }}" + size = "{{ scw_ks_worker_node.min_nodes }}" + min_size = "{{ scw_ks_worker_node.min_nodes }}" + max_size = "{{ scw_ks_worker_node.max_nodes }}" depends_on = [ scaleway_k8s_cluster.kubernetes_cluster, ] - tags = local.tags_ks_list + tags = concat(local.tags_ks_list, ["QoveryNodeGroupName:{{ scw_ks_worker_node.name }}", "QoveryNodeGroupId:${var.kubernetes_cluster_id}-{{ loop.index }}"]) } {% endfor %} \ No newline at end of file diff --git a/src/cloud_provider/aws/kubernetes/mod.rs b/src/cloud_provider/aws/kubernetes/mod.rs index 53bb5f3c..7de29bde 100644 --- a/src/cloud_provider/aws/kubernetes/mod.rs +++ b/src/cloud_provider/aws/kubernetes/mod.rs @@ -1,7 +1,8 @@ +use core::fmt; use std::env; +use std::path::PathBuf; use std::str::FromStr; -use itertools::Itertools; use retry::delay::{Fibonacci, Fixed}; use retry::Error::Operation; use retry::OperationResult; @@ -10,16 +11,16 @@ use serde::{Deserialize, Serialize}; use tera::Context as TeraContext; use crate::cloud_provider::aws::kubernetes::helm_charts::{aws_helm_charts, ChartsConfigPrerequisites}; -use crate::cloud_provider::aws::kubernetes::node::Node; +use crate::cloud_provider::aws::kubernetes::node::AwsInstancesType; use crate::cloud_provider::aws::kubernetes::roles::get_default_roles_to_create; use crate::cloud_provider::aws::AWS; use crate::cloud_provider::environment::Environment; use crate::cloud_provider::helm::deploy_charts_levels; use crate::cloud_provider::kubernetes::{ - is_kubernetes_upgrade_required, uninstall_cert_manager, Kind, Kubernetes, KubernetesNode, KubernetesNodesType, + is_kubernetes_upgrade_required, uninstall_cert_manager, Kind, Kubernetes, KubernetesNodesType, KubernetesUpgradeStatus, }; -use crate::cloud_provider::models::WorkerNodeDataTemplate; +use crate::cloud_provider::models::{NodeGroups, NodeGroupsFormat}; use crate::cloud_provider::qovery::EngineLocation; use crate::cloud_provider::{kubernetes, CloudProvider}; use crate::cmd; @@ -43,8 +44,6 @@ use crate::models::{ use crate::object_storage::s3::S3; use crate::object_storage::ObjectStorage; use crate::string::terraform_list_format; -use core::fmt; -use std::path::PathBuf; pub mod helm_charts; pub mod node; @@ -117,7 +116,7 @@ pub struct EKS<'a> { cloud_provider: &'a AWS, dns_provider: &'a dyn DnsProvider, s3: S3, - nodes: Vec, + nodes_groups: Vec, template_directory: String, options: Options, listeners: Listeners, @@ -134,10 +133,24 @@ impl<'a> EKS<'a> { cloud_provider: &'a AWS, dns_provider: &'a dyn DnsProvider, options: Options, - nodes: Vec, - ) -> Self { + nodes_groups: Vec, + ) -> Result { let template_directory = format!("{}/aws/bootstrap", context.lib_root_dir()); + for node_group in &nodes_groups { + if AwsInstancesType::from_str(node_group.instance_type.as_str()).is_err() { + return Err(EngineError::new( + EngineErrorCause::Internal, + EngineErrorScope::Engine, + context.execution_id(), + Some(format!( + "Nodegroup instance type {} is not valid for {}", + node_group.instance_type, cloud_provider.name + )), + )); + } + } + // TODO export this let s3 = S3::new( context.clone(), @@ -147,7 +160,7 @@ impl<'a> EKS<'a> { cloud_provider.secret_access_key.clone(), ); - EKS { + Ok(EKS { context, id: id.to_string(), long_id, @@ -158,10 +171,10 @@ impl<'a> EKS<'a> { dns_provider, s3, options, - nodes, + nodes_groups, template_directory, listeners: cloud_provider.listeners.clone(), // copy listeners from CloudProvider - } + }) } fn get_engine_location(&self) -> EngineLocation { @@ -270,20 +283,6 @@ impl<'a> EKS<'a> { let eks_access_cidr_blocks = format_ips(&self.options.eks_access_cidr_blocks); - let worker_nodes = self - .nodes - .iter() - .group_by(|e| e.instance_type()) - .into_iter() - .map(|(instance_type, group)| (instance_type, group.collect::>())) - .map(|(instance_type, nodes)| WorkerNodeDataTemplate { - instance_type: instance_type.to_string(), - desired_size: "3".to_string(), - max_size: nodes.len().to_string(), - min_size: "3".to_string(), - }) - .collect::>(); - let qovery_api_url = self.options.qovery_api_url.clone(); let rds_cidr_subnet = self.options.rds_cidr_subnet.clone(); let documentdb_cidr_subnet = self.options.documentdb_cidr_subnet.clone(); @@ -417,7 +416,7 @@ impl<'a> EKS<'a> { context.insert("kubernetes_cluster_name", &self.name()); context.insert("kubernetes_cluster_id", self.id()); context.insert("eks_region_cluster_id", region_cluster_id.as_str()); - context.insert("eks_worker_nodes", &worker_nodes); + context.insert("eks_worker_nodes", &self.nodes_groups); context.insert("eks_zone_a_subnet_blocks_private", &eks_zone_a_subnet_blocks_private); context.insert("eks_zone_b_subnet_blocks_private", &eks_zone_b_subnet_blocks_private); context.insert("eks_zone_c_subnet_blocks_private", &eks_zone_c_subnet_blocks_private); @@ -1058,7 +1057,7 @@ impl<'a> Kubernetes for EKS<'a> { let mut context = self.tera_context()?; // pause: remove all worker nodes to reduce the bill but keep master to keep all the deployment config, certificates etc... - let worker_nodes: Vec = Vec::new(); + let worker_nodes: Vec = Vec::new(); context.insert("eks_worker_nodes", &worker_nodes); let _ = cast_simple_error_to_engine_error( diff --git a/src/cloud_provider/aws/kubernetes/node.rs b/src/cloud_provider/aws/kubernetes/node.rs index 565375dc..41ad93a1 100644 --- a/src/cloud_provider/aws/kubernetes/node.rs +++ b/src/cloud_provider/aws/kubernetes/node.rs @@ -1,90 +1,92 @@ -use std::any::Any; +use crate::cloud_provider::kubernetes::InstanceType; +use core::fmt; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; -use crate::cloud_provider::kubernetes::KubernetesNode; - -#[derive(Clone)] -pub struct Node { - instance_type: String, +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum AwsInstancesType { + T2Large, // 2 cores 8Gb RAM + T2Xlarge, // 4 cores 16Gb RAM + T3Large, // 2 cores 8Gb RAM + T3Xlarge, // 4 cores 16Gb RAM + T3aLarge, // 2 cores 8Gb RAM + T3a2xlarge, // 8 cores 32Gb RAM } -impl Node { - /// Number of CPUs and total memory wanted - the right AWS EC2 instance type is found algorithmically - /// Eg. total_cpu = 1 and total_memory_in_gib = 2 means `t2.small` instance type - /// BUT total_cpu = 1 and total_memory_in_gib = 3 does not have an existing instance - so we will pick the upper closest, - /// which is `t2.medium` with 2 cpu and 4 GiB - /// ``` - /// use qovery_engine::cloud_provider::aws::kubernetes::node::Node; - /// use qovery_engine::cloud_provider::kubernetes::KubernetesNode; - /// - /// let node = Node::new_with_cpu_and_mem(2, 4); - /// assert_eq!(node.instance_type(), "t2.medium") - /// ``` - pub fn new_with_cpu_and_mem(total_cpu: u8, total_memory_in_gib: u16) -> Self { - let instance_types_table = [ - (1, 1, "t2.micro"), - (1, 2, "t2.small"), - (2, 4, "t2.medium"), - (2, 8, "t2.large"), - (4, 16, "t2.xlarge"), - (8, 32, "t2.2xlarge"), - // TODO add other instance types - ]; - - if total_cpu == 0 || total_memory_in_gib == 0 { - let (_, _, instance_type) = instance_types_table.first().unwrap(); - return Node::new(*instance_type); +impl InstanceType for AwsInstancesType { + fn to_cloud_provider_format(&self) -> String { + match self { + AwsInstancesType::T2Large => "t2.large", + AwsInstancesType::T2Xlarge => "t2x.large", + AwsInstancesType::T3Large => "t3.large", + AwsInstancesType::T3Xlarge => "t3x.large", + AwsInstancesType::T3aLarge => "t3a.large", + AwsInstancesType::T3a2xlarge => "t3a.2xlarge", } - - for (_cpu, mem, instance_type) in instance_types_table.iter() { - if total_memory_in_gib <= *mem { - return Node::new(*instance_type); - } - } - - let (_, _, instance_type) = instance_types_table.last().unwrap(); - Node::new(*instance_type) + .to_string() } +} - pub fn new>(instance_type: T) -> Self { - Node { - instance_type: instance_type.into(), +impl AwsInstancesType { + pub fn as_str(&self) -> &str { + match self { + AwsInstancesType::T2Large => "t2.large", + AwsInstancesType::T2Xlarge => "t2x.large", + AwsInstancesType::T3Large => "t3.large", + AwsInstancesType::T3Xlarge => "t3x.large", + AwsInstancesType::T3aLarge => "t3a.large", + AwsInstancesType::T3a2xlarge => "t3a.2xlarge", } } } -impl KubernetesNode for Node { - fn instance_type(&self) -> &str { - self.instance_type.as_str() +impl fmt::Display for AwsInstancesType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + AwsInstancesType::T2Large => write!(f, "t2.large"), + AwsInstancesType::T2Xlarge => write!(f, "t2x.large"), + AwsInstancesType::T3Large => write!(f, "t3.large"), + AwsInstancesType::T3Xlarge => write!(f, "t3x.large"), + AwsInstancesType::T3aLarge => write!(f, "t3a.large"), + AwsInstancesType::T3a2xlarge => write!(f, "t3a.2xlarge"), + } } +} - fn as_any(&self) -> &dyn Any { - self +impl FromStr for AwsInstancesType { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "t2.large" => Ok(AwsInstancesType::T2Large), + "t2x.large" => Ok(AwsInstancesType::T2Xlarge), + "t3.large" => Ok(AwsInstancesType::T3Large), + "t3x.large" => Ok(AwsInstancesType::T3Xlarge), + "t3a.large" => Ok(AwsInstancesType::T3aLarge), + "t3a.2xlarge" => Ok(AwsInstancesType::T3a2xlarge), + _ => Err(()), + } } } #[cfg(test)] mod tests { - use crate::cloud_provider::aws::kubernetes::node::Node; - use crate::cloud_provider::kubernetes::KubernetesNode; + use crate::cloud_provider::models::NodeGroups; #[test] - fn test_instance_types() { - assert_eq!(Node::new_with_cpu_and_mem(0, 0).instance_type(), "t2.micro"); - assert_eq!(Node::new_with_cpu_and_mem(1, 0).instance_type(), "t2.micro"); - assert_eq!(Node::new_with_cpu_and_mem(0, 1).instance_type(), "t2.micro"); - assert_eq!(Node::new_with_cpu_and_mem(1, 1).instance_type(), "t2.micro"); - assert_eq!(Node::new_with_cpu_and_mem(1, 2).instance_type(), "t2.small"); - assert_eq!(Node::new_with_cpu_and_mem(2, 4).instance_type(), "t2.medium"); - assert_eq!(Node::new_with_cpu_and_mem(2, 5).instance_type(), "t2.large"); - assert_eq!(Node::new_with_cpu_and_mem(1, 6).instance_type(), "t2.large"); - assert_eq!(Node::new_with_cpu_and_mem(1, 7).instance_type(), "t2.large"); - assert_eq!(Node::new_with_cpu_and_mem(2, 8).instance_type(), "t2.large"); - assert_eq!(Node::new_with_cpu_and_mem(3, 8).instance_type(), "t2.large"); - assert_eq!(Node::new_with_cpu_and_mem(3, 10).instance_type(), "t2.xlarge"); - assert_eq!(Node::new_with_cpu_and_mem(3, 12).instance_type(), "t2.xlarge"); - assert_eq!(Node::new_with_cpu_and_mem(4, 16).instance_type(), "t2.xlarge"); - assert_eq!(Node::new_with_cpu_and_mem(4, 17).instance_type(), "t2.2xlarge"); - assert_eq!(Node::new_with_cpu_and_mem(8, 32).instance_type(), "t2.2xlarge"); - assert_eq!(Node::new_with_cpu_and_mem(16, 64).instance_type(), "t2.2xlarge"); + fn test_groups_nodes() { + assert!(NodeGroups::new("".to_string(), 2, 1, "t2.large".to_string()).is_err()); + assert!(NodeGroups::new("".to_string(), 2, 2, "t2.large".to_string()).is_ok()); + assert!(NodeGroups::new("".to_string(), 2, 3, "t2.large".to_string()).is_ok()); + + assert_eq!( + NodeGroups::new("".to_string(), 2, 2, "t2.large".to_string()).unwrap(), + NodeGroups { + name: "".to_string(), + min_nodes: 2, + max_nodes: 2, + instance_type: "t2.large".to_string() + } + ); } } diff --git a/src/cloud_provider/digitalocean/kubernetes/mod.rs b/src/cloud_provider/digitalocean/kubernetes/mod.rs index b960ae71..143081f1 100644 --- a/src/cloud_provider/digitalocean/kubernetes/mod.rs +++ b/src/cloud_provider/digitalocean/kubernetes/mod.rs @@ -1,6 +1,5 @@ use std::env; -use itertools::Itertools; use serde::{Deserialize, Serialize}; use tera::Context as TeraContext; @@ -10,7 +9,7 @@ use crate::cloud_provider::digitalocean::kubernetes::doks_api::{ get_do_latest_doks_slug_from_api, get_doks_info_from_name, }; use crate::cloud_provider::digitalocean::kubernetes::helm_charts::{do_helm_charts, ChartsConfigPrerequisites}; -use crate::cloud_provider::digitalocean::kubernetes::node::Node; +use crate::cloud_provider::digitalocean::kubernetes::node::DoInstancesType; use crate::cloud_provider::digitalocean::models::doks::KubernetesCluster; use crate::cloud_provider::digitalocean::network::load_balancer::do_get_load_balancer_ip; use crate::cloud_provider::digitalocean::network::vpc::{ @@ -19,8 +18,8 @@ use crate::cloud_provider::digitalocean::network::vpc::{ use crate::cloud_provider::digitalocean::DO; use crate::cloud_provider::environment::Environment; use crate::cloud_provider::helm::{deploy_charts_levels, ChartInfo, ChartSetValue, HelmChartNamespaces}; -use crate::cloud_provider::kubernetes::{uninstall_cert_manager, Kind, Kubernetes, KubernetesNode}; -use crate::cloud_provider::models::WorkerNodeDataTemplate; +use crate::cloud_provider::kubernetes::{uninstall_cert_manager, Kind, Kubernetes}; +use crate::cloud_provider::models::NodeGroups; use crate::cloud_provider::qovery::EngineLocation; use crate::cloud_provider::{kubernetes, CloudProvider}; use crate::cmd::helm::{helm_exec_upgrade_with_chart_info, helm_upgrade_diff_with_chart_info}; @@ -43,6 +42,7 @@ use retry::delay::Fibonacci; use retry::Error::Operation; use retry::OperationResult; use std::path::PathBuf; +use std::str::FromStr; pub mod cidr; pub mod doks_api; @@ -82,7 +82,7 @@ pub struct DOKS<'a> { version: String, region: Region, cloud_provider: &'a DO, - nodes: Vec, + nodes_groups: Vec, dns_provider: &'a dyn DnsProvider, spaces: Spaces, template_directory: String, @@ -100,11 +100,25 @@ impl<'a> DOKS<'a> { region: Region, cloud_provider: &'a DO, dns_provider: &'a dyn DnsProvider, - nodes: Vec, + nodes_groups: Vec, options: DoksOptions, - ) -> Self { + ) -> Result { let template_directory = format!("{}/digitalocean/bootstrap", context.lib_root_dir()); + for node_group in &nodes_groups { + if DoInstancesType::from_str(node_group.instance_type.as_str()).is_err() { + return Err(EngineError::new( + EngineErrorCause::Internal, + EngineErrorScope::Engine, + context.execution_id(), + Some(format!( + "Nodegroup instance type {} is not valid for {}", + node_group.instance_type, cloud_provider.name + )), + )); + } + } + let spaces = Spaces::new( context.clone(), "spaces-temp-id".to_string(), @@ -114,7 +128,7 @@ impl<'a> DOKS<'a> { region, ); - DOKS { + Ok(DOKS { context, id, long_id, @@ -125,10 +139,10 @@ impl<'a> DOKS<'a> { dns_provider, spaces, options, - nodes, + nodes_groups, template_directory, listeners: cloud_provider.listeners.clone(), // copy listeners from CloudProvider - } + }) } fn get_engine_location(&self) -> EngineLocation { @@ -376,21 +390,7 @@ impl<'a> DOKS<'a> { }; // kubernetes workers - let worker_nodes = self - .nodes - .iter() - .group_by(|e| e.instance_type()) - .into_iter() - .map(|(instance_type, group)| (instance_type, group.collect::>())) - .map(|(instance_type, nodes)| WorkerNodeDataTemplate { - instance_type: instance_type.to_string(), - desired_size: "3".to_string(), - max_size: nodes.len().to_string(), - min_size: "3".to_string(), - }) - .collect::>(); - - context.insert("doks_worker_nodes", &worker_nodes); + context.insert("doks_worker_nodes", &self.nodes_groups); Ok(context) } diff --git a/src/cloud_provider/digitalocean/kubernetes/node.rs b/src/cloud_provider/digitalocean/kubernetes/node.rs index 08cb0b5d..0d2b04a4 100644 --- a/src/cloud_provider/digitalocean/kubernetes/node.rs +++ b/src/cloud_provider/digitalocean/kubernetes/node.rs @@ -1,51 +1,97 @@ -use std::any::Any; +use crate::cloud_provider::kubernetes::InstanceType; +use core::fmt; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; -use crate::cloud_provider::kubernetes::KubernetesNode; - -#[derive(Clone)] -pub struct Node { - instance_type: String, +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum DoInstancesType { + S1vcpu1gb, + S1vcpu2gb, + S1vcpu3gb, + S2vcpu4gb, + S4vcpu8gb, + S6vcpu16gb, + S8vcpu32gb, } -impl Node { - pub fn new_with_cpu_and_mem(total_cpu: u8, total_memory_in_gib: u16) -> Self { - let instance_types_table = [ - (1, 1, "s-1vcpu-1gb"), - (1, 2, "s-1vcpu-2gb"), - (2, 4, "s-2vcpu-4gb"), - (4, 8, "s-4vcpu-8gb"), - (6, 16, "s-6vcpu-16gb"), - (8, 32, "s-8vcpu-32gb"), - ]; - - if total_cpu == 0 || total_memory_in_gib == 0 { - let (_, _, instance_type) = instance_types_table.first().unwrap(); - return Node::new(*instance_type); +impl InstanceType for DoInstancesType { + fn to_cloud_provider_format(&self) -> String { + match self { + DoInstancesType::S1vcpu1gb => "s-1vcpu-1gb", + DoInstancesType::S1vcpu2gb => "s-1vcpu-2gb", + DoInstancesType::S1vcpu3gb => "s-1vcpu-3gb", + DoInstancesType::S2vcpu4gb => "s-2vcpu-4gb", + DoInstancesType::S4vcpu8gb => "s-4vcpu-8gb", + DoInstancesType::S6vcpu16gb => "s-6vcpu-16gb", + DoInstancesType::S8vcpu32gb => "s-8vcpu-32gb", } + .to_string() + } +} - for (_cpu, mem, instance_type) in instance_types_table.iter() { - if total_memory_in_gib <= *mem { - return Node::new(*instance_type); +impl DoInstancesType { + pub fn as_str(&self) -> &str { + match self { + DoInstancesType::S1vcpu1gb => "s-1vcpu-1gb", + DoInstancesType::S1vcpu2gb => "s-1vcpu-2gb", + DoInstancesType::S1vcpu3gb => "s-1vcpu-3gb", + DoInstancesType::S2vcpu4gb => "s-2vcpu-4gb", + DoInstancesType::S4vcpu8gb => "s-4vcpu-8gb", + DoInstancesType::S6vcpu16gb => "s-6vcpu-16gb", + DoInstancesType::S8vcpu32gb => "s-8vcpu-32gb", + } + } +} + +impl fmt::Display for DoInstancesType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + DoInstancesType::S1vcpu1gb => write!(f, "s-1vcpu-1gb"), + DoInstancesType::S1vcpu2gb => write!(f, "s-1vcpu-2gb"), + DoInstancesType::S1vcpu3gb => write!(f, "s-1vcpu-3gb"), + DoInstancesType::S2vcpu4gb => write!(f, "s-2vcpu-4gb"), + DoInstancesType::S4vcpu8gb => write!(f, "s-4vcpu-8gb"), + DoInstancesType::S6vcpu16gb => write!(f, "s-6vcpu-16gb"), + DoInstancesType::S8vcpu32gb => write!(f, "s-8vcpu-32gb"), + } + } +} + +impl FromStr for DoInstancesType { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "s-1vcpu-1gb" => Ok(DoInstancesType::S1vcpu1gb), + "s-1vcpu-2gb" => Ok(DoInstancesType::S1vcpu2gb), + "s-1vcpu-3gb" => Ok(DoInstancesType::S1vcpu3gb), + "s-2vcpu-4gb" => Ok(DoInstancesType::S2vcpu4gb), + "s-4vcpu-8gb" => Ok(DoInstancesType::S4vcpu8gb), + "s-6vcpu-16gb" => Ok(DoInstancesType::S6vcpu16gb), + "s-8vcpu-32gb" => Ok(DoInstancesType::S8vcpu32gb), + _ => Err(()), + } + } +} + +#[cfg(test)] +mod tests { + use crate::cloud_provider::models::NodeGroups; + + #[test] + fn test_groups_nodes() { + assert!(NodeGroups::new("".to_string(), 2, 1, "s-2vcpu-4gb".to_string()).is_err()); + assert!(NodeGroups::new("".to_string(), 2, 2, "s-2vcpu-4gb".to_string()).is_ok()); + assert!(NodeGroups::new("".to_string(), 2, 3, "s-2vcpu-4gb".to_string()).is_ok()); + + assert_eq!( + NodeGroups::new("".to_string(), 2, 2, "s-2vcpu-4gb".to_string()).unwrap(), + NodeGroups { + name: "".to_string(), + min_nodes: 2, + max_nodes: 2, + instance_type: "s-2vcpu-4gb".to_string() } - } - - let (_, _, instance_type) = instance_types_table.last().unwrap(); - Node::new(*instance_type) - } - - pub fn new>(instance_type: T) -> Self { - Node { - instance_type: instance_type.into(), - } - } -} - -impl KubernetesNode for Node { - fn instance_type(&self) -> &str { - self.instance_type.as_str() - } - - fn as_any(&self) -> &dyn Any { - self + ); } } diff --git a/src/cloud_provider/kubernetes.rs b/src/cloud_provider/kubernetes.rs index af71f0bc..d5636d40 100644 --- a/src/cloud_provider/kubernetes.rs +++ b/src/cloud_provider/kubernetes.rs @@ -2,6 +2,7 @@ use std::any::Any; use std::fs::File; use std::os::unix::fs::PermissionsExt; use std::path::Path; +use std::str::FromStr; use std::thread; use retry::delay::Fibonacci; @@ -10,6 +11,7 @@ use retry::OperationResult; use serde::{Deserialize, Serialize}; use crate::cloud_provider::environment::Environment; +use crate::cloud_provider::models::NodeGroups; use crate::cloud_provider::service::CheckAction; use crate::cloud_provider::utilities::VersionsNumber; use crate::cloud_provider::{service, CloudProvider, DeploymentTarget}; @@ -26,7 +28,6 @@ use crate::error::{ use crate::models::{Context, Listen, ListenersHelper, ProgressInfo, ProgressLevel, ProgressScope, StringPath}; use crate::object_storage::ObjectStorage; use crate::unit_conversion::{any_to_mi, cpu_string_to_float}; -use std::str::FromStr; pub trait Kubernetes: Listen { fn context(&self) -> &Context; @@ -875,14 +876,40 @@ pub fn compare_kubernetes_cluster_versions_for_upgrade( Ok(upgrade_required) } +pub trait InstanceType { + fn to_cloud_provider_format(&self) -> String; +} + +impl NodeGroups { + pub fn new(group_name: String, min_nodes: i32, max_nodes: i32, instance_type: String) -> Result { + if min_nodes > max_nodes { + return Err(SimpleError { + kind: SimpleErrorKind::Other, + message: Some(format!( + "The number of minimum nodes ({}) for group name {} is higher than maximum nodes ({})", + &group_name, &min_nodes, &max_nodes + )), + }); + } + + Ok(NodeGroups { + name: group_name, + min_nodes, + max_nodes, + instance_type, + }) + } +} + #[cfg(test)] mod tests { + use std::str::FromStr; + use crate::cloud_provider::kubernetes::{ check_kubernetes_upgrade_status, compare_kubernetes_cluster_versions_for_upgrade, KubernetesNodesType, }; use crate::cloud_provider::utilities::VersionsNumber; use crate::cmd::structs::{KubernetesList, KubernetesNode, KubernetesVersion}; - use std::str::FromStr; #[test] pub fn check_kubernetes_upgrade_method() { diff --git a/src/cloud_provider/models.rs b/src/cloud_provider/models.rs index be947cdf..53c0bd03 100644 --- a/src/cloud_provider/models.rs +++ b/src/cloud_provider/models.rs @@ -1,13 +1,5 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] -pub struct WorkerNodeDataTemplate { - pub instance_type: String, - pub desired_size: String, - pub max_size: String, - pub min_size: String, -} - #[derive(Clone, Eq, PartialEq, Hash)] pub struct EnvironmentVariable { pub key: String, @@ -69,3 +61,19 @@ pub struct CpuLimits { pub cpu_request: String, pub cpu_limit: String, } + +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] +pub struct NodeGroups { + pub name: String, + pub min_nodes: i32, + pub max_nodes: i32, + pub instance_type: String, +} + +#[derive(Serialize, Deserialize)] +pub struct NodeGroupsFormat { + pub name: String, + pub min_nodes: String, + pub max_nodes: String, + pub instance_type: String, +} diff --git a/src/cloud_provider/scaleway/kubernetes/mod.rs b/src/cloud_provider/scaleway/kubernetes/mod.rs index dceb5918..b0301fb4 100644 --- a/src/cloud_provider/scaleway/kubernetes/mod.rs +++ b/src/cloud_provider/scaleway/kubernetes/mod.rs @@ -4,13 +4,13 @@ pub mod node; use crate::cloud_provider::environment::Environment; use crate::cloud_provider::helm::deploy_charts_levels; use crate::cloud_provider::kubernetes::{ - is_kubernetes_upgrade_required, uninstall_cert_manager, Kind, Kubernetes, KubernetesNode, KubernetesUpgradeStatus, + is_kubernetes_upgrade_required, uninstall_cert_manager, Kind, Kubernetes, KubernetesUpgradeStatus, }; -use crate::cloud_provider::models::WorkerNodeDataTemplate; +use crate::cloud_provider::models::NodeGroups; use crate::cloud_provider::qovery::EngineLocation; use crate::cloud_provider::scaleway::application::Zone; use crate::cloud_provider::scaleway::kubernetes::helm_charts::{scw_helm_charts, ChartsConfigPrerequisites}; -use crate::cloud_provider::scaleway::kubernetes::node::Node; +use crate::cloud_provider::scaleway::kubernetes::node::ScwInstancesType; use crate::cloud_provider::scaleway::Scaleway; use crate::cloud_provider::{kubernetes, CloudProvider}; use crate::cmd::kubectl::kubectl_exec_get_all_namespaces; @@ -28,13 +28,13 @@ use crate::object_storage::scaleway_object_storage::{BucketDeleteStrategy, Scale use crate::object_storage::ObjectStorage; use crate::string::terraform_list_format; use crate::{cmd, dns_provider}; -use itertools::Itertools; use retry::delay::Fibonacci; use retry::Error::Operation; use retry::OperationResult; use serde::{Deserialize, Serialize}; use std::env; use std::path::PathBuf; +use std::str::FromStr; use tera::Context as TeraContext; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -112,7 +112,7 @@ pub struct Kapsule<'a> { cloud_provider: &'a Scaleway, dns_provider: &'a dyn DnsProvider, object_storage: ScalewayOS, - nodes: Vec, + nodes_groups: Vec, template_directory: String, options: KapsuleOptions, listeners: Listeners, @@ -128,11 +128,25 @@ impl<'a> Kapsule<'a> { zone: Zone, cloud_provider: &'a Scaleway, dns_provider: &'a dyn DnsProvider, - nodes: Vec, + nodes_groups: Vec, options: KapsuleOptions, - ) -> Kapsule<'a> { + ) -> Result, EngineError> { let template_directory = format!("{}/scaleway/bootstrap", context.lib_root_dir()); + for node_group in &nodes_groups { + if ScwInstancesType::from_str(node_group.instance_type.as_str()).is_err() { + return Err(EngineError::new( + EngineErrorCause::Internal, + EngineErrorScope::Engine, + context.execution_id(), + Some(format!( + "Nodegroup instance type {} is not valid for {}", + node_group.instance_type, cloud_provider.name + )), + )); + } + } + let object_storage = ScalewayOS::new( context.clone(), "s3-temp-id".to_string(), @@ -144,7 +158,7 @@ impl<'a> Kapsule<'a> { false, ); - Kapsule { + Ok(Kapsule { context, id, long_id, @@ -154,11 +168,11 @@ impl<'a> Kapsule<'a> { cloud_provider, dns_provider, object_storage, - nodes, + nodes_groups, template_directory, options, listeners: cloud_provider.listeners.clone(), // copy listeners from CloudProvider - } + }) } fn get_engine_location(&self) -> EngineLocation { @@ -310,20 +324,7 @@ impl<'a> Kapsule<'a> { context.insert("grafana_admin_password", self.options.grafana_admin_password.as_str()); // Kubernetes workers - let worker_nodes = self - .nodes - .iter() - .group_by(|e| e.instance_type()) - .into_iter() - .map(|(instance_type, group)| (instance_type, group.collect::>())) - .map(|(instance_type, nodes)| WorkerNodeDataTemplate { - instance_type: instance_type.to_string().to_uppercase(), - desired_size: "3".to_string(), - max_size: nodes.len().to_string(), - min_size: "3".to_string(), - }) - .collect::>(); - context.insert("scw_ks_worker_nodes", &worker_nodes); + context.insert("scw_ks_worker_nodes", &self.nodes_groups); context.insert("scw_ks_pool_autoscale", &true); Ok(context) diff --git a/src/cloud_provider/scaleway/kubernetes/node.rs b/src/cloud_provider/scaleway/kubernetes/node.rs index e70d179a..cde7c6e1 100644 --- a/src/cloud_provider/scaleway/kubernetes/node.rs +++ b/src/cloud_provider/scaleway/kubernetes/node.rs @@ -1,110 +1,110 @@ -use crate::cloud_provider::kubernetes::KubernetesNode; -use std::any::Any; +use crate::cloud_provider::kubernetes::InstanceType; +use serde::{Deserialize, Serialize}; use std::fmt; use std::str::FromStr; -#[derive(Clone)] -pub enum NodeType { - Gp1Xs, // 4 cores 16 Go RAM - Gp1S, // 8 cores 32 Go RAM - Gp1M, // 16 cores 64 Go RAM - Gp1L, // 32 cores 128 Go RAM - Gp1Xl, // 64 cores 256 Go RAM - Dev1M, // 3 cores 4 Go RAM - Dev1L, // 4 cores 8 Go RAM - Dev1Xl, // 4 cores 12 Go RAM - RenderS, // 10 cores 45 Go RAM 1 GPU 1 Go VRAM +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum ScwInstancesType { + Gp1Xs, // 4 cores 16 Gb RAM + Gp1S, // 8 cores 32 Gb RAM + Gp1M, // 16 cores 64 Gb RAM + Gp1L, // 32 cores 128 Gb RAM + Gp1Xl, // 64 cores 256 Gb RAM + Dev1M, // 3 cores 4 Gb RAM + Dev1L, // 4 cores 8 Gb RAM + Dev1Xl, // 4 cores 12 Gb RAM + RenderS, // 10 cores 45 Gb RAM 1 GPU 1 Gb VRAM } -impl NodeType { +impl InstanceType for ScwInstancesType { + fn to_cloud_provider_format(&self) -> String { + match self { + ScwInstancesType::Gp1Xs => "gp1-xs", + ScwInstancesType::Gp1S => "gp1-s", + ScwInstancesType::Gp1M => "gp1-m", + ScwInstancesType::Gp1L => "gp1-l", + ScwInstancesType::Gp1Xl => "gp1-xl", + ScwInstancesType::Dev1M => "dev1-m", + ScwInstancesType::Dev1L => "dev1-l", + ScwInstancesType::Dev1Xl => "dev1-xl", + ScwInstancesType::RenderS => "render-s", + } + .to_string() + } +} + +impl ScwInstancesType { pub fn as_str(&self) -> &str { match self { - NodeType::Gp1Xs => "gp1-xs", - NodeType::Gp1S => "gp1-s", - NodeType::Gp1M => "gp1-m", - NodeType::Gp1L => "gp1-l", - NodeType::Gp1Xl => "gp1-xl", - NodeType::Dev1M => "dev1-m", - NodeType::Dev1L => "dev1-l", - NodeType::Dev1Xl => "dev1-xl", - NodeType::RenderS => "render-s", + ScwInstancesType::Gp1Xs => "gp1-xs", + ScwInstancesType::Gp1S => "gp1-s", + ScwInstancesType::Gp1M => "gp1-m", + ScwInstancesType::Gp1L => "gp1-l", + ScwInstancesType::Gp1Xl => "gp1-xl", + ScwInstancesType::Dev1M => "dev1-m", + ScwInstancesType::Dev1L => "dev1-l", + ScwInstancesType::Dev1Xl => "dev1-xl", + ScwInstancesType::RenderS => "render-s", } } } -impl fmt::Display for NodeType { +impl fmt::Display for ScwInstancesType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - NodeType::Gp1Xs => write!(f, "gp1-xs"), - NodeType::Gp1S => write!(f, "gp1-s"), - NodeType::Gp1M => write!(f, "gp1-m"), - NodeType::Gp1L => write!(f, "gp1-l"), - NodeType::Gp1Xl => write!(f, "gp1-xl"), - NodeType::Dev1M => write!(f, "dev1-m"), - NodeType::Dev1L => write!(f, "dev1-l"), - NodeType::Dev1Xl => write!(f, "dev1-xl"), - NodeType::RenderS => write!(f, "render-s"), + ScwInstancesType::Gp1Xs => write!(f, "gp1-xs"), + ScwInstancesType::Gp1S => write!(f, "gp1-s"), + ScwInstancesType::Gp1M => write!(f, "gp1-m"), + ScwInstancesType::Gp1L => write!(f, "gp1-l"), + ScwInstancesType::Gp1Xl => write!(f, "gp1-xl"), + ScwInstancesType::Dev1M => write!(f, "dev1-m"), + ScwInstancesType::Dev1L => write!(f, "dev1-l"), + ScwInstancesType::Dev1Xl => write!(f, "dev1-xl"), + ScwInstancesType::RenderS => write!(f, "render-s"), } } } -impl FromStr for NodeType { +impl FromStr for ScwInstancesType { type Err = (); - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { match s { - "gp1-xs" => Ok(NodeType::Gp1Xs), - "gp1-s" => Ok(NodeType::Gp1S), - "gp1-m" => Ok(NodeType::Gp1M), - "gp1-l" => Ok(NodeType::Gp1L), - "gp1-xl" => Ok(NodeType::Gp1Xl), - "dev1-m" => Ok(NodeType::Dev1M), - "dev1-l" => Ok(NodeType::Dev1L), - "dev1-xl" => Ok(NodeType::Dev1Xl), - "render-s" => Ok(NodeType::RenderS), + "gp1-xs" => Ok(ScwInstancesType::Gp1Xs), + "gp1-s" => Ok(ScwInstancesType::Gp1S), + "gp1-m" => Ok(ScwInstancesType::Gp1M), + "gp1-l" => Ok(ScwInstancesType::Gp1L), + "gp1-xl" => Ok(ScwInstancesType::Gp1Xl), + "dev1-m" => Ok(ScwInstancesType::Dev1M), + "dev1-l" => Ok(ScwInstancesType::Dev1L), + "dev1-xl" => Ok(ScwInstancesType::Dev1Xl), + "render-s" => Ok(ScwInstancesType::RenderS), _ => Err(()), } } } -#[derive(Clone)] -pub struct Node { - node_type: NodeType, -} +#[cfg(test)] +mod tests { + #[cfg(test)] + mod tests { + use crate::cloud_provider::models::NodeGroups; -impl Node { - pub fn new(node_type: NodeType) -> Node { - Node { - node_type: node_type.clone(), + #[test] + fn test_groups_nodes() { + assert!(NodeGroups::new("".to_string(), 2, 1, "dev1-l".to_string()).is_err()); + assert!(NodeGroups::new("".to_string(), 2, 2, "dev1-l".to_string()).is_ok()); + assert!(NodeGroups::new("".to_string(), 2, 3, "dev1-l".to_string()).is_ok()); + + assert_eq!( + NodeGroups::new("".to_string(), 2, 2, "dev1-l".to_string()).unwrap(), + NodeGroups { + name: "".to_string(), + min_nodes: 2, + max_nodes: 2, + instance_type: "dev1-l".to_string() + } + ); } } } - -impl KubernetesNode for Node { - fn instance_type(&self) -> &str { - self.node_type.as_str() - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -#[cfg(test)] -mod tests { - use crate::cloud_provider::kubernetes::KubernetesNode; - use crate::cloud_provider::scaleway::kubernetes::node::{Node, NodeType}; - - #[test] - fn test_node_types() { - assert_eq!(Node::new(NodeType::Dev1M).instance_type(), "dev1-m"); - assert_eq!(Node::new(NodeType::Dev1L).instance_type(), "dev1-l"); - assert_eq!(Node::new(NodeType::Dev1Xl).instance_type(), "dev1-xl"); - assert_eq!(Node::new(NodeType::Gp1Xs).instance_type(), "gp1-xs"); - assert_eq!(Node::new(NodeType::Gp1S).instance_type(), "gp1-s"); - assert_eq!(Node::new(NodeType::Gp1M).instance_type(), "gp1-m"); - assert_eq!(Node::new(NodeType::Gp1L).instance_type(), "gp1-l"); - assert_eq!(Node::new(NodeType::Gp1Xl).instance_type(), "gp1-xl"); - assert_eq!(Node::new(NodeType::RenderS).instance_type(), "render-s"); - } -} diff --git a/test_utilities/src/aws.rs b/test_utilities/src/aws.rs index 0e91b3eb..3ef57bae 100644 --- a/test_utilities/src/aws.rs +++ b/test_utilities/src/aws.rs @@ -1,10 +1,12 @@ extern crate serde; extern crate serde_derive; + use tracing::error; -use qovery_engine::cloud_provider::aws::kubernetes::node::Node; use qovery_engine::cloud_provider::aws::kubernetes::{Options, VpcQoveryNetworkMode, EKS}; use qovery_engine::cloud_provider::aws::AWS; +use qovery_engine::cloud_provider::models::NodeGroups; +use qovery_engine::cloud_provider::qovery::EngineLocation::ClientSide; use qovery_engine::cloud_provider::TerraformStateCredentials; use qovery_engine::container_registry::docker_hub::DockerHub; use qovery_engine::container_registry::ecr::ECR; @@ -14,7 +16,6 @@ use qovery_engine::models::Context; use crate::cloudflare::dns_provider_cloudflare; use crate::utilities::{build_platform_local_docker, FuncTestsSecrets}; -use qovery_engine::cloud_provider::qovery::EngineLocation::ClientSide; pub const AWS_QOVERY_ORGANIZATION_ID: &str = "u8nb94c7fwxzr2jt"; pub const AWS_REGION_FOR_S3: &str = "eu-west-3"; @@ -53,19 +54,9 @@ pub fn container_registry_docker_hub(context: &Context) -> DockerHub { ) } -pub fn aws_kubernetes_nodes() -> Vec { - vec![ - Node::new_with_cpu_and_mem(2, 8), - Node::new_with_cpu_and_mem(2, 8), - Node::new_with_cpu_and_mem(2, 8), - Node::new_with_cpu_and_mem(2, 8), - Node::new_with_cpu_and_mem(2, 8), - Node::new_with_cpu_and_mem(2, 8), - Node::new_with_cpu_and_mem(2, 8), - Node::new_with_cpu_and_mem(2, 8), - Node::new_with_cpu_and_mem(2, 8), - Node::new_with_cpu_and_mem(2, 8), - ] +pub fn aws_kubernetes_nodes() -> Vec { + vec![NodeGroups::new("groupeks0".to_string(), 5, 10, "t3a.large".to_string()) + .expect("Problem while setup EKS nodes")] } pub fn cloud_provider_aws(context: &Context) -> AWS { @@ -173,7 +164,7 @@ pub fn aws_kubernetes_eks<'a>( context: &Context, cloud_provider: &'a AWS, dns_provider: &'a dyn DnsProvider, - nodes: Vec, + nodes_groups: Vec, ) -> EKS<'a> { let secrets = FuncTestsSecrets::new(); EKS::<'a>::new( @@ -186,8 +177,9 @@ pub fn aws_kubernetes_eks<'a>( cloud_provider, dns_provider, eks_options(secrets), - nodes, + nodes_groups, ) + .unwrap() } pub fn docker_ecr_aws_engine(context: &Context) -> Engine { diff --git a/test_utilities/src/digitalocean.rs b/test_utilities/src/digitalocean.rs index aa459b12..6b993d28 100644 --- a/test_utilities/src/digitalocean.rs +++ b/test_utilities/src/digitalocean.rs @@ -1,9 +1,9 @@ use qovery_engine::build_platform::Image; -use qovery_engine::cloud_provider::digitalocean::kubernetes::node::Node; use qovery_engine::cloud_provider::digitalocean::kubernetes::DoksOptions; use qovery_engine::cloud_provider::digitalocean::kubernetes::DOKS; use qovery_engine::cloud_provider::digitalocean::network::vpc::VpcInitKind; use qovery_engine::cloud_provider::digitalocean::DO; +use qovery_engine::cloud_provider::models::NodeGroups; use qovery_engine::cloud_provider::TerraformStateCredentials; use qovery_engine::container_registry::docr::DOCR; use qovery_engine::dns_provider::DnsProvider; @@ -61,7 +61,7 @@ pub fn do_kubernetes_ks<'a>( context: &Context, cloud_provider: &'a DO, dns_provider: &'a dyn DnsProvider, - nodes: Vec, + nodes_groups: Vec, region: Region, ) -> DOKS<'a> { let secrets = FuncTestsSecrets::new(); @@ -74,17 +74,17 @@ pub fn do_kubernetes_ks<'a>( region, cloud_provider, dns_provider, - nodes, + nodes_groups, do_kubernetes_cluster_options(secrets, DO_KUBE_TEST_CLUSTER_ID.to_string()), ) + .unwrap() } -pub fn do_kubernetes_nodes() -> Vec { - scw_kubernetes_custom_nodes(10, Node::new_with_cpu_and_mem(4, 8)) -} - -pub fn scw_kubernetes_custom_nodes(count: usize, node: Node) -> Vec { - vec![node.clone(); count] +pub fn do_kubernetes_nodes() -> Vec { + vec![ + NodeGroups::new("groupdoks0".to_string(), 5, 10, "s-4vcpu-8gb".to_string()) + .expect("Problem while setup DOKS nodes"), + ] } pub fn cloud_provider_digitalocean(context: &Context) -> DO { diff --git a/test_utilities/src/scaleway.rs b/test_utilities/src/scaleway.rs index 56cbccbc..13fcfedf 100644 --- a/test_utilities/src/scaleway.rs +++ b/test_utilities/src/scaleway.rs @@ -1,6 +1,5 @@ use qovery_engine::build_platform::Image; use qovery_engine::cloud_provider::scaleway::application::Zone; -use qovery_engine::cloud_provider::scaleway::kubernetes::node::{Node, NodeType}; use qovery_engine::cloud_provider::scaleway::kubernetes::{Kapsule, KapsuleOptions}; use qovery_engine::cloud_provider::scaleway::Scaleway; use qovery_engine::cloud_provider::TerraformStateCredentials; @@ -15,6 +14,7 @@ use qovery_engine::transaction::{DeploymentOption, TransactionResult}; use crate::cloudflare::dns_provider_cloudflare; use crate::utilities::{build_platform_local_docker, generate_id, FuncTestsSecrets}; +use qovery_engine::cloud_provider::models::NodeGroups; use qovery_engine::cloud_provider::qovery::EngineLocation; use tracing::error; @@ -147,13 +147,9 @@ pub fn scw_object_storage(context: Context, region: Zone) -> ScalewayOS { ) } -pub fn scw_kubernetes_nodes() -> Vec { +pub fn scw_kubernetes_nodes() -> Vec { // Note: Dev1M is a bit too small to handle engine + local docker, hence using Dev1L - scw_kubernetes_custom_nodes(10, NodeType::Dev1L) -} - -pub fn scw_kubernetes_custom_nodes(count: usize, node_type: NodeType) -> Vec { - vec![Node::new(node_type); count] + vec![NodeGroups::new("groupscw0".to_string(), 5, 10, "dev1-l".to_string()).expect("Problem while setup SCW nodes")] } pub fn docker_scw_cr_engine(context: &Context) -> Engine { @@ -181,7 +177,7 @@ pub fn scw_kubernetes_kapsule<'a>( context: &Context, cloud_provider: &'a Scaleway, dns_provider: &'a dyn DnsProvider, - nodes: Vec, + nodes_groups: Vec, zone: Zone, ) -> Kapsule<'a> { let secrets = FuncTestsSecrets::new(); @@ -194,9 +190,10 @@ pub fn scw_kubernetes_kapsule<'a>( zone, cloud_provider, dns_provider, - nodes, + nodes_groups, scw_kubernetes_cluster_options(secrets), ) + .unwrap() } pub fn deploy_environment(context: &Context, environment_action: EnvironmentAction, zone: Zone) -> TransactionResult { diff --git a/tests/aws/aws_kubernetes.rs b/tests/aws/aws_kubernetes.rs index 7c91c513..830c1932 100644 --- a/tests/aws/aws_kubernetes.rs +++ b/tests/aws/aws_kubernetes.rs @@ -45,7 +45,8 @@ fn create_upgrade_and_destroy_eks_cluster( &cloudflare, eks_options(secrets.clone()), nodes.clone(), - ); + ) + .unwrap(); // Deploy if let Err(err) = tx.create_kubernetes(&kubernetes) { @@ -69,7 +70,8 @@ fn create_upgrade_and_destroy_eks_cluster( &cloudflare, eks_options(secrets), nodes, - ); + ) + .unwrap(); if let Err(err) = tx.create_kubernetes(&kubernetes) { panic!("{:?}", err) } @@ -130,7 +132,8 @@ fn create_and_destroy_eks_cluster( &cloudflare, eks_options, nodes, - ); + ) + .unwrap(); // Deploy if let Err(err) = tx.create_kubernetes(&kubernetes) { diff --git a/tests/digitalocean/do_kubernetes.rs b/tests/digitalocean/do_kubernetes.rs index cb672c1b..4de16754 100644 --- a/tests/digitalocean/do_kubernetes.rs +++ b/tests/digitalocean/do_kubernetes.rs @@ -47,7 +47,8 @@ fn create_upgrade_and_destroy_doks_cluster( &cloudflare, nodes, test_utilities::digitalocean::do_kubernetes_cluster_options(secrets, cluster_id), - ); + ) + .unwrap(); // Deploy if let Err(err) = tx.create_kubernetes(&kubernetes) { @@ -115,7 +116,8 @@ fn create_and_destroy_doks_cluster(region: Region, secrets: FuncTestsSecrets, te &cloudflare, nodes, test_utilities::digitalocean::do_kubernetes_cluster_options(secrets, cluster_id), - ); + ) + .unwrap(); // Deploy if let Err(err) = tx.create_kubernetes(&kubernetes) { diff --git a/tests/digitalocean/do_utility_kubernetes_doks_test_cluster.rs b/tests/digitalocean/do_utility_kubernetes_doks_test_cluster.rs index 832ba7f8..d516b55e 100644 --- a/tests/digitalocean/do_utility_kubernetes_doks_test_cluster.rs +++ b/tests/digitalocean/do_utility_kubernetes_doks_test_cluster.rs @@ -48,7 +48,8 @@ fn create_digitalocean_kubernetes_doks_test_cluster() { secrets, test_utilities::digitalocean::DO_KUBE_TEST_CLUSTER_NAME.to_string(), ), - ); + ) + .unwrap(); // Deploy if let Err(err) = tx.create_kubernetes(&kubernetes) { @@ -104,7 +105,8 @@ fn destroy_digitalocean_kubernetes_doks_test_cluster() { secrets, test_utilities::digitalocean::DO_KUBE_TEST_CLUSTER_NAME.to_string(), ), - ); + ) + .unwrap(); // Destroy if let Err(err) = tx.delete_kubernetes(&kubernetes) { diff --git a/tests/scaleway/scw_kubernetes.rs b/tests/scaleway/scw_kubernetes.rs index 395064ad..34329815 100644 --- a/tests/scaleway/scw_kubernetes.rs +++ b/tests/scaleway/scw_kubernetes.rs @@ -47,7 +47,8 @@ fn create_upgrade_and_destroy_kapsule_cluster( &cloudflare, nodes, test_utilities::scaleway::scw_kubernetes_cluster_options(secrets), - ); + ) + .unwrap(); // Deploy if let Err(err) = tx.create_kubernetes(&kubernetes) { @@ -115,7 +116,8 @@ fn create_and_destroy_kapsule_cluster(zone: Zone, secrets: FuncTestsSecrets, tes &cloudflare, nodes, test_utilities::scaleway::scw_kubernetes_cluster_options(secrets), - ); + ) + .unwrap(); // Deploy if let Err(err) = tx.create_kubernetes(&kubernetes) { diff --git a/tests/scaleway/scw_utility_kubernetes_kapsule_test_cluster.rs b/tests/scaleway/scw_utility_kubernetes_kapsule_test_cluster.rs index 82ee1d25..50f65ced 100644 --- a/tests/scaleway/scw_utility_kubernetes_kapsule_test_cluster.rs +++ b/tests/scaleway/scw_utility_kubernetes_kapsule_test_cluster.rs @@ -5,7 +5,6 @@ use self::test_utilities::utilities::{context, engine_run_test, init, FuncTestsS use ::function_name::named; use tracing::{span, Level}; -use qovery_engine::cloud_provider::scaleway::kubernetes::node::NodeType; use qovery_engine::cloud_provider::scaleway::kubernetes::Kapsule; use qovery_engine::transaction::TransactionResult; @@ -32,7 +31,7 @@ fn create_scaleway_kubernetes_kapsule_test_cluster() { let mut tx = session.transaction(); let scw_cluster = test_utilities::scaleway::cloud_provider_scaleway(&context); - let nodes = test_utilities::scaleway::scw_kubernetes_custom_nodes(10, NodeType::Gp1S); + let nodes = test_utilities::scaleway::scw_kubernetes_nodes(); let cloudflare = dns_provider_cloudflare(&context); let kubernetes = Kapsule::new( @@ -46,7 +45,8 @@ fn create_scaleway_kubernetes_kapsule_test_cluster() { &cloudflare, nodes, test_utilities::scaleway::scw_kubernetes_cluster_options(secrets), - ); + ) + .unwrap(); // Deploy if let Err(err) = tx.create_kubernetes(&kubernetes) { @@ -99,7 +99,8 @@ fn destroy_scaleway_kubernetes_kapsule_test_cluster() { &cloudflare, nodes, test_utilities::scaleway::scw_kubernetes_cluster_options(secrets), - ); + ) + .unwrap(); // Destroy if let Err(err) = tx.delete_kubernetes(&kubernetes) {