Skip to content

Commit e071937

Browse files
authored
aws: Add regex pattern matching to cleanup-ssm tool (#6870)
I had noticed that some of the things we were deleting might be useful like: ``` Would delete: pytorch-labs-cloudwatch_agent_config_runner_linux_nvidia ``` So I added pattern matching to only delete things related to runner spin-up. --------- Signed-off-by: Eli Uriegas <[email protected]>
1 parent 5f86d76 commit e071937

File tree

4 files changed

+109
-13
lines changed

4 files changed

+109
-13
lines changed

aws/tools/cleanup-ssm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ chrono = "0.4"
1212
aws-smithy-types = "1.3"
1313
humantime = "2.1"
1414
indicatif = "0.17"
15+
regex = "1.0"
1516

1617
[dev-dependencies]
1718
mockall = "0.12"

aws/tools/cleanup-ssm/src/filter.rs

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
use crate::TimeProvider;
22
use aws_sdk_ssm::types::ParameterMetadata;
33
use chrono::{DateTime, Duration};
4+
use regex::Regex;
45

56
pub fn filter_old_parameters<T: TimeProvider>(
67
parameters: &[ParameterMetadata],
78
time_provider: &T,
89
older_than_seconds: f64,
9-
) -> Vec<String> {
10+
pattern: &str,
11+
) -> Result<Vec<String>, regex::Error> {
1012
let threshold = time_provider.now() - Duration::seconds(older_than_seconds as i64);
13+
let regex = Regex::new(pattern)?;
1114
let mut parameters_to_delete = Vec::new();
1215

1316
for parameter in parameters {
@@ -17,13 +20,15 @@ pub fn filter_old_parameters<T: TimeProvider>(
1720

1821
if last_modified_time < threshold {
1922
if let Some(name) = parameter.name() {
20-
parameters_to_delete.push(name.to_string());
23+
if regex.is_match(name) {
24+
parameters_to_delete.push(name.to_string());
25+
}
2126
}
2227
}
2328
}
2429
}
2530

26-
parameters_to_delete
31+
Ok(parameters_to_delete)
2732
}
2833

2934
#[cfg(test)]
@@ -54,7 +59,7 @@ mod tests {
5459
let parameters = vec![];
5560
let time_provider = MockTimeProvider::new(Utc::now());
5661

57-
let result = filter_old_parameters(&parameters, &time_provider, 86400.0); // 1 day in seconds
62+
let result = filter_old_parameters(&parameters, &time_provider, 86400.0, ".*").unwrap(); // 1 day in seconds
5863

5964
assert_eq!(result.len(), 0);
6065
}
@@ -72,7 +77,7 @@ mod tests {
7277
let time_provider = MockTimeProvider::new(now);
7378
let parameters = vec![parameter];
7479

75-
let result = filter_old_parameters(&parameters, &time_provider, 86400.0); // 1 day in seconds
80+
let result = filter_old_parameters(&parameters, &time_provider, 86400.0, ".*").unwrap(); // 1 day in seconds
7681

7782
assert_eq!(result.len(), 0);
7883
}
@@ -90,7 +95,7 @@ mod tests {
9095
let time_provider = MockTimeProvider::new(now);
9196
let parameters = vec![parameter];
9297

93-
let result = filter_old_parameters(&parameters, &time_provider, 86400.0); // 1 day in seconds
98+
let result = filter_old_parameters(&parameters, &time_provider, 86400.0, ".*").unwrap(); // 1 day in seconds
9499

95100
assert_eq!(result.len(), 1);
96101
assert_eq!(result[0], "old-param");
@@ -115,7 +120,7 @@ mod tests {
115120
let time_provider = MockTimeProvider::new(now);
116121
let parameters = vec![old_parameter, recent_parameter];
117122

118-
let result = filter_old_parameters(&parameters, &time_provider, 172800.0); // 2 days in seconds
123+
let result = filter_old_parameters(&parameters, &time_provider, 172800.0, ".*").unwrap(); // 2 days in seconds
119124

120125
assert_eq!(result.len(), 1);
121126
assert_eq!(result[0], "old-param");
@@ -130,7 +135,7 @@ mod tests {
130135
let time_provider = MockTimeProvider::new(Utc::now());
131136
let parameters = vec![parameter];
132137

133-
let result = filter_old_parameters(&parameters, &time_provider, 86400.0); // 1 day in seconds
138+
let result = filter_old_parameters(&parameters, &time_provider, 86400.0, ".*").unwrap(); // 1 day in seconds
134139

135140
assert_eq!(result.len(), 0);
136141
}
@@ -147,7 +152,51 @@ mod tests {
147152
let time_provider = MockTimeProvider::new(now);
148153
let parameters = vec![parameter];
149154

150-
let result = filter_old_parameters(&parameters, &time_provider, 86400.0); // 1 day in seconds
155+
let result = filter_old_parameters(&parameters, &time_provider, 86400.0, ".*").unwrap(); // 1 day in seconds
156+
157+
assert_eq!(result.len(), 0);
158+
}
159+
160+
#[test]
161+
fn test_filter_old_parameters_with_pattern_match() {
162+
let now = Utc::now();
163+
let old_time = now - Duration::days(5);
164+
165+
let matching_parameter = ParameterMetadata::builder()
166+
.name("gh-ci-i-test-param")
167+
.last_modified_date(AwsDateTime::from_secs(old_time.timestamp()))
168+
.build();
169+
170+
let non_matching_parameter = ParameterMetadata::builder()
171+
.name("other-param")
172+
.last_modified_date(AwsDateTime::from_secs(old_time.timestamp()))
173+
.build();
174+
175+
let time_provider = MockTimeProvider::new(now);
176+
let parameters = vec![matching_parameter, non_matching_parameter];
177+
178+
let result =
179+
filter_old_parameters(&parameters, &time_provider, 86400.0, "gh-ci-i-.*").unwrap(); // 1 day in seconds
180+
181+
assert_eq!(result.len(), 1);
182+
assert_eq!(result[0], "gh-ci-i-test-param");
183+
}
184+
185+
#[test]
186+
fn test_filter_old_parameters_with_pattern_no_match() {
187+
let now = Utc::now();
188+
let old_time = now - Duration::days(5);
189+
190+
let parameter = ParameterMetadata::builder()
191+
.name("other-param")
192+
.last_modified_date(AwsDateTime::from_secs(old_time.timestamp()))
193+
.build();
194+
195+
let time_provider = MockTimeProvider::new(now);
196+
let parameters = vec![parameter];
197+
198+
let result =
199+
filter_old_parameters(&parameters, &time_provider, 86400.0, "gh-ci-i-.*").unwrap(); // 1 day in seconds
151200

152201
assert_eq!(result.len(), 0);
153202
}

aws/tools/cleanup-ssm/src/lib.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,42 @@
11
use aws_sdk_ssm::types::ParameterMetadata;
22
use chrono::{DateTime, Utc};
33

4+
#[derive(Debug)]
5+
pub enum CleanupError {
6+
Aws(aws_sdk_ssm::Error),
7+
Regex(regex::Error),
8+
}
9+
10+
impl From<aws_sdk_ssm::Error> for CleanupError {
11+
fn from(err: aws_sdk_ssm::Error) -> Self {
12+
CleanupError::Aws(err)
13+
}
14+
}
15+
16+
impl From<regex::Error> for CleanupError {
17+
fn from(err: regex::Error) -> Self {
18+
CleanupError::Regex(err)
19+
}
20+
}
21+
22+
impl std::fmt::Display for CleanupError {
23+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24+
match self {
25+
CleanupError::Aws(err) => write!(f, "AWS error: {}", err),
26+
CleanupError::Regex(err) => write!(f, "Regex error: {}", err),
27+
}
28+
}
29+
}
30+
31+
impl std::error::Error for CleanupError {
32+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
33+
match self {
34+
CleanupError::Aws(err) => Some(err),
35+
CleanupError::Regex(err) => Some(err),
36+
}
37+
}
38+
}
39+
440
#[cfg(test)]
541
use mockall::automock;
642

@@ -13,6 +49,7 @@ pub struct CleanupConfig {
1349
pub region: String,
1450
pub dry_run: bool,
1551
pub older_than_seconds: f64,
52+
pub pattern: String,
1653
}
1754

1855
#[derive(Debug)]
@@ -49,11 +86,15 @@ pub async fn cleanup_ssm_parameters<C: SsmClient, T: TimeProvider>(
4986
client: &C,
5087
time_provider: &T,
5188
config: &CleanupConfig,
52-
) -> Result<CleanupResult, aws_sdk_ssm::Error> {
89+
) -> Result<CleanupResult, CleanupError> {
5390
let parameters = client.describe_parameters().await?;
5491

55-
let parameters_to_delete =
56-
filter::filter_old_parameters(&parameters, time_provider, config.older_than_seconds);
92+
let parameters_to_delete = filter::filter_old_parameters(
93+
&parameters,
94+
time_provider,
95+
config.older_than_seconds,
96+
&config.pattern,
97+
)?;
5798

5899
println!("Found {} parameters to delete", parameters_to_delete.len());
59100
let parameters_found = parameters_to_delete.len();
@@ -126,6 +167,7 @@ mod tests {
126167
region: "us-east-1".to_string(),
127168
dry_run: true,
128169
older_than_seconds: 86400.0, // 1 day in seconds
170+
pattern: ".*".to_string(),
129171
};
130172

131173
let result = cleanup_ssm_parameters(&mock_client, &time_provider, &config)

aws/tools/cleanup-ssm/src/main.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@ struct Args {
1313
// time duration older than which to delete parameters (e.g., "1d", "2h", "30m")
1414
#[clap(long, default_value = "1d")]
1515
older_than: String,
16+
// regex pattern to match parameter names for deletion
17+
#[clap(long, default_value = "gh-ci-i-.*")]
18+
pattern: String,
1619
}
1720

1821
#[tokio::main]
19-
async fn main() -> Result<(), Box<aws_sdk_ssm::Error>> {
22+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
2023
let args = Args::parse();
2124

2225
// Parse the human-readable time string into a Duration
@@ -36,6 +39,7 @@ async fn main() -> Result<(), Box<aws_sdk_ssm::Error>> {
3639
region: args.region,
3740
dry_run: args.dry_run,
3841
older_than_seconds,
42+
pattern: args.pattern,
3943
};
4044

4145
let result = cleanup_ssm_parameters(&client, &time_provider, &config).await?;

0 commit comments

Comments
 (0)