From ddf64d1591e0d4e1928d219f047a1180a38d48b4 Mon Sep 17 00:00:00 2001 From: Benoit Garcia Date: Mon, 14 Apr 2025 18:07:52 +0200 Subject: [PATCH 1/3] fix(purge): fix go version and toolchain in go.mod --- functions/purge/go.mod | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/functions/purge/go.mod b/functions/purge/go.mod index 2aee338..69b208d 100644 --- a/functions/purge/go.mod +++ b/functions/purge/go.mod @@ -1,6 +1,8 @@ module purge -go 1.23.8 +go 1.23 + +toolchain go1.23.8 require github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33 From 6127aee3e656fc6b2937e5cc288d6a592bae13fc Mon Sep 17 00:00:00 2001 From: Benoit Garcia Date: Mon, 14 Apr 2025 18:16:47 +0200 Subject: [PATCH 2/3] fix(purge): fix preservation pattern mechanism and default values --- README.md | 2 +- functions.tf | 2 +- functions/purge/handler.go | 2 +- variables.tf | 7 +++++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5152ea3..d06a156 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ module "my_registry" { | [project_id](#input_project_id) | ID of the project the namespace is associated with. Ressource will be created in the project set at the provider level if null. | `string` | `null` | no | | [purge_dry_run](#input_purge_dry_run) | Prevent deletion of tags & images. | `bool` | `true` | no | | [purge_log_level](#input_purge_log_level) | Log Level of the purge function. Refer to the Go [slog package documentation](https://pkg.go.dev/log/slog#Level) for accepted values | `number` | `0` | no | -| [purge_preserve_tag_patterns](#input_purge_preserve_tag_patterns) | List of regex patterns for tags to preserve. By default, preserves semantic versioning tags. | `list(string)` | ```[ "^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" ]``` | no | +| [purge_preserve_tag_patterns](#input_purge_preserve_tag_patterns) | List of regex patterns for tags to preserve. By default, preserves semantic versioning tags and `latest` tags. | `list(string)` | ```[ "^latest((-.+)?)$", "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" ]``` | no | | [purge_retention_days](#input_purge_retention_days) | Number of days to keep images before deletion. | `number` | `30` | no | | [purge_schedule](#input_purge_schedule) | Cron schedule for the cleanup function. Set to empty string to disable scheduled cleanup. | `string` | `"0 0 * * *"` | no | | [purge_timeout](#input_purge_timeout) | Timeout for the cleanup function in seconds. | `number` | `300` | no | diff --git a/functions.tf b/functions.tf index 04735dd..ae125b2 100644 --- a/functions.tf +++ b/functions.tf @@ -62,7 +62,7 @@ resource "scaleway_function" "registry_purge" { environment_variables = { REGISTRY_NAMESPACE = var.name RETENTION_DAYS = var.purge_retention_days - PRESERVE_TAG_PATTERNS = join(",", var.purge_preserve_tag_patterns) + PRESERVE_TAG_PATTERNS = join("|", var.purge_preserve_tag_patterns) DRY_RUN = var.purge_dry_run LOG_LEVEL = var.purge_log_level } diff --git a/functions/purge/handler.go b/functions/purge/handler.go index 3fd758e..3295a01 100644 --- a/functions/purge/handler.go +++ b/functions/purge/handler.go @@ -15,7 +15,7 @@ import ( ) // Default semver pattern for tag preservation -const DefaultTagPattern string = `^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` +const DefaultTagPattern string = `^latest((-.+)?)$|^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$` // Config holds the configuration for the purge function type Config struct { diff --git a/variables.tf b/variables.tf index ae2bb37..b45ccd3 100644 --- a/variables.tf +++ b/variables.tf @@ -35,9 +35,12 @@ variable "purge_retention_days" { } variable "purge_preserve_tag_patterns" { - description = "List of regex patterns for tags to preserve. By default, preserves semantic versioning tags." + description = "List of regex patterns for tags to preserve. By default, preserves semantic versioning tags and `latest` tags." type = list(string) - default = ["^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"] + default = [ + "^latest((-.+)?)$", + "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + ] } variable "purge_schedule" { From d8905de5b33e48a3dcf7dddfaf88c4933d000b0e Mon Sep 17 00:00:00 2001 From: Benoit Garcia Date: Mon, 14 Apr 2025 18:18:14 +0200 Subject: [PATCH 3/3] chore(purge): improve logging --- functions/purge/handler.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/functions/purge/handler.go b/functions/purge/handler.go index 3295a01..0fec8d3 100644 --- a/functions/purge/handler.go +++ b/functions/purge/handler.go @@ -62,7 +62,7 @@ var ( ) func init() { - slog.Info("===== Init container =====") + slog.Info("===== Runing 'init' =====") // Set log level based on environment variable var logLevel slog.Level slogLevel, err := strconv.Atoi(os.Getenv("LOG_LEVEL")) @@ -149,7 +149,7 @@ func init() { } func Handle(w http.ResponseWriter, r *http.Request) { - slog.Info("===== Starting purge =====") + slog.Info("===== Runing 'Handle' =====") // Get Retention date retentionDate := time.Now().AddDate(0, 0, -config.RetentionDays) slog.Info(fmt.Sprintf("Purging images older than: %s", retentionDate.Format(time.RFC3339))) @@ -196,15 +196,15 @@ func Handle(w http.ResponseWriter, r *http.Request) { for _, tag := range tags { // Check if tag is older than retention date if tag.UpdatedAt.Before(retentionDate) { - slog.Info(fmt.Sprintf("Tag %s:%s updated at %s is older than retention date %s", + slog.Debug(fmt.Sprintf("Tag %s:%s updated at %s is older than retention date %s", image.Name, tag.Name, tag.UpdatedAt.Format(time.RFC3339), retentionDate.Format(time.RFC3339))) // Check if tag is protected if config.PreserveTagPatterns.MatchString(tag.Name) { - slog.Info(fmt.Sprintf("Tag %s match protection pattern. Preserving", tag.Name)) + slog.Debug(fmt.Sprintf("Tag %s match protection pattern. Preserving", tag.Name)) preservedTags++ } else { - slog.Info(fmt.Sprintf("Tag %s doesn't match protection pattern.", tag.Name)) + slog.Debug(fmt.Sprintf("Tag %s doesn't match protection pattern.", tag.Name)) // Delete tag if not dry run if err := registryClient.DeleteTag(context.Background(), tag); err != nil { slog.Error(fmt.Sprintf("Failed to delete tag %s (%s): %v", tag.Name, tag.ID, err)) @@ -214,7 +214,7 @@ func Handle(w http.ResponseWriter, r *http.Request) { deletedTags++ } } else { - slog.Info(fmt.Sprintf("Tag %s updated at %s is newer than retention date %s. Skipping", + slog.Debug(fmt.Sprintf("Tag %s updated at %s is newer than retention date %s. Skipping", tag.Name, tag.UpdatedAt.Format(time.RFC3339), retentionDate.Format(time.RFC3339))) skippedTags++ } @@ -233,7 +233,7 @@ func Handle(w http.ResponseWriter, r *http.Request) { // DeleteTag deletes a tag func (r *RegistryClient) DeleteTag(ctx context.Context, tag *registry.Tag) error { if r.config.DryRun { - slog.Info(fmt.Sprintf("[DRY RUN] Would delete tag: %s (%s)", tag.Name, tag.ID)) + slog.Debug(fmt.Sprintf("[DRY RUN] Would delete tag: %s (%s)", tag.Name, tag.ID)) return nil }