Skip to content

Commit 859ba00

Browse files
feat: add single zone configuration
Before this change, there was no way to set up a specific zone for EC2 instance. This feature allows configuring a specific zone in Test.toml for a certain variant when launching its EC2 instance(s). Even though a minimum of two zones are needed when creating an EKS cluster, after the cluster is created this feature can limit one specific zone before launching the EC2 instances.
1 parent 56aecba commit 859ba00

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed

bottlerocket/agents/src/bin/ec2-resource-agent/ec2_provider.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,15 @@ where
235235
for instance_type in instance_types {
236236
info!("Using instance type '{}'", instance_type);
237237

238+
let mut flex_subnet_ids = spec.configuration.subnet_ids.clone();
239+
240+
// Remove the first element in the Vec to make sure EC2 instance will deploy in the target zone which input in Test.tom in twoliter
241+
if flex_subnet_ids.len() <= 2 {
242+
flex_subnet_ids.remove(0);
243+
}
244+
238245
// Run the ec2 instances
239-
for subnet_id in &spec.configuration.subnet_ids {
246+
for subnet_id in flex_subnet_ids {
240247
info!("Launching '{}' in '{}'", instance_type, subnet_id);
241248
memo.current_status = format!("Launching '{}' in '{}'", instance_type, subnet_id);
242249
client
@@ -247,7 +254,7 @@ where
247254
.run_instances()
248255
.min_count(instance_count)
249256
.max_count(instance_count)
250-
.subnet_id(subnet_id)
257+
.subnet_id(subnet_id.clone())
251258
.set_security_group_ids(if spec.configuration.security_groups.is_empty() {
252259
None
253260
} else {

bottlerocket/agents/src/bin/eks-resource-agent/eks_provider.rs

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ use serde_json::Value;
2222
use std::env::temp_dir;
2323
use std::path::Path;
2424
use std::process::Command;
25+
use std::str::FromStr;
2526
use testsys_model::{Configuration, SecretName};
2627

2728
use std::fs::File;
2829
use std::io::Write;
29-
use strum_macros::EnumString;
30+
use strum_macros::{AsRefStr, EnumString};
3031

3132
/// The default region for the cluster.
3233
const DEFAULT_REGION: &str = "us-west-2";
@@ -142,6 +143,17 @@ enum IPFamily {
142143
IPv4,
143144
}
144145

146+
#[derive(Debug, EnumString, AsRefStr)]
147+
#[strum(serialize_all = "kebab-case")]
148+
enum AvailabilityZones {
149+
#[strum(serialize = "us-west-2a")]
150+
UsWest2a,
151+
#[strum(serialize = "us-west-2b")]
152+
UsWest2b,
153+
#[strum(serialize = "us-west-2c")]
154+
UsWest2c,
155+
}
156+
145157
/// Configuration for setting up an EKS cluster using eksctl yaml file.
146158
///
147159
/// # Fields:
@@ -239,10 +251,23 @@ struct ManagedNodeGroup {
239251
min_size: i32,
240252
/// The maximum number of nodes in the managed node group.
241253
max_size: i32,
242-
// The desired number of nodes in the managed node group.
254+
/// The desired number of nodes in the managed node group.
243255
desired_capacity: i32,
244256
}
245257

258+
fn zone_to_exclude(exclude: String) -> Vec<AvailabilityZones> {
259+
let all_zones = vec![
260+
AvailabilityZones::UsWest2a,
261+
AvailabilityZones::UsWest2b,
262+
AvailabilityZones::UsWest2c,
263+
];
264+
265+
all_zones
266+
.into_iter()
267+
.filter(|zone| zone.as_ref() != exclude)
268+
.collect()
269+
}
270+
246271
#[allow(clippy::unwrap_or_default)]
247272
fn create_yaml(
248273
cluster_name: &str,
@@ -256,6 +281,35 @@ fn create_yaml(
256281
IPFamily::IPv4
257282
};
258283

284+
let mut eks_zones: Vec<String> = zones.clone().context(
285+
Resources::Clear,
286+
"Failed to get input availability zones for EKS cluster",
287+
)?;
288+
289+
if zones.is_some() && zones.iter().len() < 2 {
290+
let zone_vec = zones.clone().context(
291+
Resources::Clear,
292+
"Failed to get input availability zones Vec",
293+
)?;
294+
295+
let zone_input = zone_vec
296+
.first()
297+
.context(Resources::Clear, "Failed to get input zone")?;
298+
299+
if AvailabilityZones::from_str(&zone_input).is_err() {
300+
return Err(ProviderError::new_with_context(
301+
Resources::Clear,
302+
format!("Input zone of {} in Test.toml is invalid", zone_input),
303+
));
304+
}
305+
let remain_zone = zone_to_exclude(zone_input.to_string())
306+
.first()
307+
.unwrap()
308+
.as_ref()
309+
.to_string();
310+
eks_zones.insert(0, remain_zone);
311+
}
312+
259313
let cluster = EksctlYamlConfig {
260314
api_version: "eksctl.io/v1alpha5".to_string(),
261315
kind: "ClusterConfig".to_string(),
@@ -264,7 +318,7 @@ fn create_yaml(
264318
region: region.to_string(),
265319
version: version.to_string(),
266320
},
267-
availability_zones: zones.clone().unwrap_or_else(Vec::new),
321+
availability_zones: eks_zones,
268322
kubernetes_network_config: KubernetesNetworkConfig {
269323
ip_family: set_ip_family,
270324
},

0 commit comments

Comments
 (0)