Skip to content

Commit 0c4ba59

Browse files
committed
feat: provision all ressources to schedule purge
1 parent 90896aa commit 0c4ba59

File tree

5 files changed

+170
-0
lines changed

5 files changed

+170
-0
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,20 @@ module "my_registry" {
2323
| Name | Version |
2424
|------|---------|
2525
| <a name="requirement_terraform"></a> [terraform](#requirement_terraform) | >= 0.13 |
26+
| <a name="requirement_archive"></a> [archive](#requirement_archive) | >= 2.0.0 |
2627
| <a name="requirement_scaleway"></a> [scaleway](#requirement_scaleway) | >= 2.0.0 |
2728

2829
## Resources
2930

3031
| Name | Type |
3132
|------|------|
33+
| [archive_file.registry_purge](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/resources/file) | resource |
34+
| [scaleway_function.registry_purge](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/function) | resource |
35+
| [scaleway_function_cron.registry_purge](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/function_cron) | resource |
36+
| [scaleway_function_namespace.maintenance](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/function_namespace) | resource |
37+
| [scaleway_iam_api_key.registry_purge](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/iam_api_key) | resource |
38+
| [scaleway_iam_application.registry_purge](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/iam_application) | resource |
39+
| [scaleway_iam_policy.registry_purge](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/iam_policy) | resource |
3240
| [scaleway_registry_namespace.this](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/registry_namespace) | resource |
3341

3442
## Inputs
@@ -39,14 +47,25 @@ module "my_registry" {
3947
| <a name="input_description"></a> [description](#input_description) | Description of the namespace. | `string` | `null` | no |
4048
| <a name="input_is_public"></a> [is_public](#input_is_public) | Whether the images stored in the namespace should be downloadable publicly (docker pull). | `bool` | `false` | no |
4149
| <a name="input_project_id"></a> [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 |
50+
| <a name="input_purge_dry_run"></a> [purge_dry_run](#input_purge_dry_run) | Prevent deletion of tags & images. | `bool` | `true` | no |
51+
| <a name="input_purge_log_level"></a> [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 |
52+
| <a name="input_purge_preserve_tag_patterns"></a> [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 |
53+
| <a name="input_purge_retention_days"></a> [purge_retention_days](#input_purge_retention_days) | Number of days to keep images before deletion. | `number` | `30` | no |
54+
| <a name="input_purge_schedule"></a> [purge_schedule](#input_purge_schedule) | Cron schedule for the cleanup function. Set to empty string to disable scheduled cleanup. | `string` | `"0 0 * * *"` | no |
55+
| <a name="input_purge_timeout"></a> [purge_timeout](#input_purge_timeout) | Timeout for the cleanup function in seconds. | `number` | `300` | no |
4256
| <a name="input_region"></a> [region](#input_region) | Region in which the namespace should be created. Ressource will be created in the region set at the provider level if null. | `string` | `null` | no |
4357

4458
## Outputs
4559

4660
| Name | Description |
4761
|------|-------------|
62+
| <a name="output_cleanup_application_id"></a> [cleanup_application_id](#output_cleanup_application_id) | ID of the IAM application for the cleanup function. |
63+
| <a name="output_cleanup_cron_id"></a> [cleanup_cron_id](#output_cleanup_cron_id) | ID of the cron trigger for the cleanup function. |
64+
| <a name="output_cleanup_function_endpoint"></a> [cleanup_function_endpoint](#output_cleanup_function_endpoint) | Endpoint URL of the cleanup function. |
4865
| <a name="output_endpoint"></a> [endpoint](#output_endpoint) | URL of the namespace. |
4966
| <a name="output_id"></a> [id](#output_id) | ID of the namespace. |
67+
| <a name="output_maintenance_namespace_id"></a> [maintenance_namespace_id](#output_maintenance_namespace_id) | ID of the maintenance function namespace. |
68+
| <a name="output_purge_function_id"></a> [purge_function_id](#output_purge_function_id) | ID of the cleanup function. |
5069
<!-- END_TF_DOCS -->
5170

5271
## Authors

functions.tf

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Create a serverless namespace for maintenance functions
2+
resource "scaleway_function_namespace" "maintenance" {
3+
name = format("%s-maintenance", var.name)
4+
description = format("Namespace for maintenance functions for %s registry", var.name)
5+
project_id = scaleway_registry_namespace.this.project_id
6+
region = scaleway_registry_namespace.this.region
7+
}
8+
9+
# Create an IAM application for the function
10+
resource "scaleway_iam_application" "registry_purge" {
11+
name = format("%s-registry-cleanup", var.name)
12+
description = "Application for registry cleanup function"
13+
}
14+
15+
# Create an IAM policy to allow the function to access the registry
16+
resource "scaleway_iam_policy" "registry_purge" {
17+
name = format("%s-registry-cleanup-policy", var.name)
18+
description = "Policy for registry cleanup function"
19+
application_id = scaleway_iam_application.registry_purge.id
20+
21+
# Rule to allow the function to read and delete images in the registry namespace
22+
rule {
23+
project_ids = [scaleway_registry_namespace.this.project_id]
24+
permission_set_names = ["ContainerRegistryFullAccess"]
25+
}
26+
}
27+
28+
# Create an API key for the function
29+
resource "scaleway_iam_api_key" "registry_purge" {
30+
application_id = scaleway_iam_application.registry_purge.id
31+
description = "API key for registry cleanup function"
32+
default_project_id = scaleway_registry_namespace.this.project_id
33+
}
34+
35+
# Archive the function code
36+
resource "archive_file" "registry_purge" {
37+
type = "zip"
38+
source_dir = "${path.module}/functions/purge"
39+
output_path = "${path.module}/functions/purge.zip"
40+
excludes = [".git", ".gitignore", "README.md", "vendor"]
41+
}
42+
43+
# Deploy the function
44+
resource "scaleway_function" "registry_purge" {
45+
name = "purge-old-images"
46+
description = "Purges old images from the container registry namespace"
47+
deploy = true
48+
namespace_id = scaleway_function_namespace.maintenance.id
49+
handler = "Handle"
50+
http_option = "redirected"
51+
privacy = "private"
52+
runtime = "go123"
53+
timeout = var.purge_timeout
54+
55+
memory_limit = 128
56+
max_scale = 1
57+
min_scale = 0
58+
59+
zip_file = archive_file.registry_purge.output_path
60+
zip_hash = archive_file.registry_purge.output_sha256
61+
62+
environment_variables = {
63+
REGISTRY_NAMESPACE = var.name
64+
RETENTION_DAYS = var.purge_retention_days
65+
PRESERVE_TAG_PATTERNS = join(",", var.purge_preserve_tag_patterns)
66+
DRY_RUN = var.purge_dry_run
67+
LOG_LEVEL = var.purge_log_level
68+
}
69+
70+
secret_environment_variables = {
71+
REGISTRY_ACCESS_KEY = scaleway_iam_api_key.registry_purge.access_key
72+
REGISTRY_SECRET_KEY = scaleway_iam_api_key.registry_purge.secret_key
73+
REGISTRY_PROJECT_ID = scaleway_registry_namespace.this.project_id
74+
REGISTRY_REGION = scaleway_registry_namespace.this.region
75+
}
76+
}
77+
78+
# Create a cron trigger for the function only if cleanup_schedule is not empty
79+
resource "scaleway_function_cron" "registry_purge" {
80+
count = var.purge_schedule != "" ? 1 : 0
81+
function_id = scaleway_function.registry_purge.id
82+
schedule = var.purge_schedule
83+
args = "{}"
84+
}

outputs.tf

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,29 @@ output "endpoint" {
77
description = "URL of the namespace."
88
value = scaleway_registry_namespace.this.endpoint
99
}
10+
11+
output "maintenance_namespace_id" {
12+
description = "ID of the maintenance function namespace."
13+
value = scaleway_function_namespace.maintenance.id
14+
}
15+
16+
# Cleanup function outputs
17+
output "purge_function_id" {
18+
description = "ID of the cleanup function."
19+
value = scaleway_function.registry_purge.id
20+
}
21+
22+
output "cleanup_function_endpoint" {
23+
description = "Endpoint URL of the cleanup function."
24+
value = scaleway_function.registry_purge.domain_name
25+
}
26+
27+
output "cleanup_application_id" {
28+
description = "ID of the IAM application for the cleanup function."
29+
value = scaleway_iam_application.registry_purge.id
30+
}
31+
32+
output "cleanup_cron_id" {
33+
description = "ID of the cron trigger for the cleanup function."
34+
value = var.purge_schedule != "" ? scaleway_function_cron.registry_purge[0].id : null
35+
}

variables.tf

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,40 @@ variable "project_id" {
2626
type = string
2727
default = null
2828
}
29+
30+
# Purge function variables
31+
variable "purge_retention_days" {
32+
description = "Number of days to keep images before deletion."
33+
type = number
34+
default = 30
35+
}
36+
37+
variable "purge_preserve_tag_patterns" {
38+
description = "List of regex patterns for tags to preserve. By default, preserves semantic versioning tags."
39+
type = list(string)
40+
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-]+)*))?$"]
41+
}
42+
43+
variable "purge_schedule" {
44+
description = "Cron schedule for the cleanup function. Set to empty string to disable scheduled cleanup."
45+
type = string
46+
default = "0 0 * * *"
47+
}
48+
49+
variable "purge_timeout" {
50+
description = "Timeout for the cleanup function in seconds."
51+
type = number
52+
default = 300
53+
}
54+
55+
variable "purge_dry_run" {
56+
description = "Prevent deletion of tags & images."
57+
type = bool
58+
default = true
59+
}
60+
61+
variable "purge_log_level" {
62+
description = "Log Level of the purge function. Refer to the Go [slog package documentation](https://pkg.go.dev/log/slog#Level) for accepted values"
63+
type = number
64+
default = 0
65+
}

versions.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,9 @@ terraform {
55
source = "scaleway/scaleway"
66
version = ">= 2.0.0"
77
}
8+
archive = {
9+
source = "hashicorp/archive"
10+
version = ">= 2.0.0"
11+
}
812
}
913
}

0 commit comments

Comments
 (0)