From b3bcb2ed5136700b88f875df2a4056f20719fd38 Mon Sep 17 00:00:00 2001 From: Daniel Hu Date: Mon, 2 Dec 2024 07:23:00 +0000 Subject: [PATCH] fix: Add new way to create cluster, create cluster from yaml file, to fix previously wrong ipFamily issue This is the body of the commit: this fix addressed the issue of when create clusters, the ipv6 cluster always has a ipFamily of ipv4 which is wrong. In this commit, a new way of creating cluster is added which is using created yaml file in a certain path. That way we can definite the ipFamily for whether it is ipv6 or ipv4. Fixed feedbacks fixed build --- .../bin/eks-resource-agent/eks_provider.rs | 183 ++++++++++++++---- 1 file changed, 142 insertions(+), 41 deletions(-) diff --git a/bottlerocket/agents/src/bin/eks-resource-agent/eks_provider.rs b/bottlerocket/agents/src/bin/eks-resource-agent/eks_provider.rs index eb34664c..7ca91a58 100644 --- a/bottlerocket/agents/src/bin/eks-resource-agent/eks_provider.rs +++ b/bottlerocket/agents/src/bin/eks-resource-agent/eks_provider.rs @@ -20,16 +20,19 @@ use resource_agent::provider::{ use serde::{Deserialize, Serialize}; use serde_json::Value; use std::env::temp_dir; -use std::fs::write; use std::path::Path; use std::process::Command; use testsys_model::{Configuration, SecretName}; +use std::fs::File; +use std::io::Write; + /// The default region for the cluster. const DEFAULT_REGION: &str = "us-west-2"; /// The default cluster version. const DEFAULT_VERSION: &str = "1.24"; const TEST_CLUSTER_CONFIG_PATH: &str = "/local/eksctl_config.yaml"; +const CLUSTER_CONFIG_PATH: &str = "/local/cluster_config.yaml"; #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -115,7 +118,6 @@ impl AwsClients { } } } - enum ClusterConfig { Args { cluster_name: String, @@ -128,6 +130,123 @@ enum ClusterConfig { region: String, }, } +enum IPFamily { + IPv4, + IPv6, +} + +fn get_family_string(family: IPFamily) -> &'static str { + match family { + IPFamily::IPv4 => "IPv4", + IPFamily::IPv6 => "IPv6", + } +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct Config { + api_version: String, + kind: String, + metadata: Metadata, + availability_zones: Vec, + kubernetes_network_config: KubernetesNetworkConfig, + addons: Vec, + iam: IAMConfig, + managed_node_groups: Vec, +} + +#[derive(Serialize)] +struct Metadata { + name: String, + region: String, + version: String, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct KubernetesNetworkConfig { + ip_family: String, +} + +#[derive(Serialize)] +struct Addon { + name: String, + version: String, +} + +#[derive(Serialize)] +#[allow(non_snake_case)] +struct IAMConfig { + withOIDC: bool, +} + +#[derive(Serialize)] +struct ManagedNodeGroup { + name: String, +} + +#[allow(clippy::unwrap_or_default)] +fn create_yaml( + cluster_name: &str, + region: &str, + version: &str, + zones: &Option>, +) -> ProviderResult<()> { + let ip_family = if cluster_name.ends_with("ipv6") { + get_family_string(IPFamily::IPv6) + } else { + get_family_string(IPFamily::IPv4) + }; + + let cluster = Config { + api_version: "eksctl.io/v1alpha5".to_string(), + kind: "ClusterConfig".to_string(), + metadata: Metadata { + name: cluster_name.to_string(), + region: region.to_string(), + version: version.to_string(), + }, + availability_zones: zones.clone().unwrap_or_else(Vec::new), + kubernetes_network_config: KubernetesNetworkConfig { + ip_family: ip_family.to_string(), + }, + addons: vec![ + Addon { + name: "vpc-cni".to_string(), + version: "latest".to_string(), + }, + Addon { + name: "coredns".to_string(), + version: "latest".to_string(), + }, + Addon { + name: "kube-proxy".to_string(), + version: "latest".to_string(), + }, + ], + iam: IAMConfig { withOIDC: true }, + managed_node_groups: vec![ManagedNodeGroup { + name: "mng-1".to_string(), + }], + }; + + let yaml = + serde_yaml::to_string(&cluster).context(Resources::Clear, "Failed to serialize YAML"); + + let mut file = File::create(CLUSTER_CONFIG_PATH) + .context(Resources::Clear, "Failed to create yaml file")?; + + file.write_all(yaml.unwrap().as_bytes()).context( + Resources::Clear, + format!( + "Unable to write eksctl configuration to '{}'", + CLUSTER_CONFIG_PATH + ), + )?; + info!("YAML file has been created at /local/cluster_config.yaml"); + + Ok(()) +} impl ClusterConfig { pub fn new(eksctl_config: EksctlConfig) -> ProviderResult { @@ -144,15 +263,6 @@ impl ClusterConfig { )?) .context(Resources::Clear, "Unable to serialize eksctl config.")?; - let config_path = Path::new(TEST_CLUSTER_CONFIG_PATH); - write(config_path, decoded_config).context( - Resources::Clear, - format!( - "Unable to write eksctl configuration to '{}'", - config_path.display() - ), - )?; - let (cluster_name, region) = config .get("metadata") .map(|metadata| { @@ -193,9 +303,9 @@ impl ClusterConfig { Ok(config) } - /// Create a cluster with the given config. + // Create a cluster with the given config. pub fn create_cluster(&self) -> ProviderResult<()> { - let status = match self { + let cluster_config_path = match self { Self::Args { cluster_name, region, @@ -206,41 +316,32 @@ impl ClusterConfig { .as_ref() .map(|version| version.major_minor_without_v()) .unwrap_or_else(|| DEFAULT_VERSION.to_string()); - trace!("Calling eksctl create cluster"); - let status = Command::new("eksctl") - .args([ - "create", - "cluster", - "-r", - region, - "--zones", - &zones.clone().unwrap_or_default().join(","), - "--version", - &version_arg, - "-n", - cluster_name, - "--nodes", - "0", - "--managed=false", - ]) - .status() - .context(Resources::Clear, "Failed create cluster")?; - trace!("eksctl create cluster has completed"); - status + + create_yaml(cluster_name, region, &version_arg, zones)?; + info!( + "assigned create cluster yaml file path is {}", + CLUSTER_CONFIG_PATH + ); + CLUSTER_CONFIG_PATH } Self::ConfigPath { cluster_name: _, region: _, } => { - trace!("Calling eksctl create cluster with config file"); - let status = Command::new("eksctl") - .args(["create", "cluster", "-f", TEST_CLUSTER_CONFIG_PATH]) - .status() - .context(Resources::Clear, "Failed create cluster")?; - trace!("eksctl create cluster has completed"); - status + info!( + "assigned create cluster yaml file path is {}", + TEST_CLUSTER_CONFIG_PATH + ); + TEST_CLUSTER_CONFIG_PATH } }; + + trace!("Calling eksctl create cluster with config file"); + let status = Command::new("eksctl") + .args(["create", "cluster", "-f", cluster_config_path]) + .status() + .context(Resources::Clear, "Failed create cluster")?; + trace!("eksctl create cluster has completed"); if !status.success() { return Err(ProviderError::new_with_context( Resources::Clear,