From cff3966c56b4e3673fac1383b2cf18aed0c8d29c Mon Sep 17 00:00:00 2001 From: Joseph Page Date: Tue, 26 Sep 2023 11:38:50 +0200 Subject: [PATCH] feat: add automatic log drains for addons (#10) --- README.md | 7 ++++--- log_drains.tf | 28 ++++++++++++++++++++++++++-- upgrade_to_v0.3.0.tf | 35 +++++++++++++++++++++++++++++++++++ variables.tf | 13 +++++++++++-- 4 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 upgrade_to_v0.3.0.tf diff --git a/README.md b/README.md index 66868bc..c44e489 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,8 @@ Used in production by : | [scalingo_container_type.containers](https://registry.terraform.io/providers/scalingo/scalingo/latest/docs/resources/container_type) | resource | | [scalingo_domain.canonical_domain](https://registry.terraform.io/providers/scalingo/scalingo/latest/docs/resources/domain) | resource | | [scalingo_domain.domain_aliases](https://registry.terraform.io/providers/scalingo/scalingo/latest/docs/resources/domain) | resource | -| [scalingo_log_drain.log_drain](https://registry.terraform.io/providers/scalingo/scalingo/latest/docs/resources/log_drain) | resource | +| [scalingo_log_drain.addons](https://registry.terraform.io/providers/scalingo/scalingo/latest/docs/resources/log_drain) | resource | +| [scalingo_log_drain.app](https://registry.terraform.io/providers/scalingo/scalingo/latest/docs/resources/log_drain) | resource | | [scalingo_scm_repo_link.scm_repo_link](https://registry.terraform.io/providers/scalingo/scalingo/latest/docs/resources/scm_repo_link) | resource | ## Inputs @@ -74,8 +75,8 @@ Used in production by : | [environment](#input\_environment) | Map of environment variables to set on the application. Note that value of environment variables can be null or empty. | `map(string)` | `null` | no | | [github\_integration](#input\_github\_integration) | Configuration of the GitHub integration of the application. Only one of github\_integration or gitlab\_integration can be set. |
object({
repo_url = string
integration_uuid = optional(string)
branch = optional(string, "main")
auto_deploy_enabled = optional(bool, true)
})
| `null` | no | | [gitlab\_integration](#input\_gitlab\_integration) | Configuration of the GitLab integration of the application. Only one of github\_integration or gitlab\_integration can be set. |
object({
repo_url = string
integration_uuid = optional(string)
branch = optional(string, "main")
auto_deploy_enabled = optional(bool, true)
})
| `null` | no | -| [log\_drains](#input\_log\_drains) | n/a |
list(object({
type = string
url = optional(string, "")
drain_region = optional(string, "")
addon = optional(string, "")
host = optional(string, "")
port = optional(string, "")
token = optional(string, "")
}))
| `[]` | no | -| [name](#input\_name) | n/a | `string` | n/a | yes | +| [log\_drains](#input\_log\_drains) | List of log\_drain configuration to redirect logs from the application and addons to a log management service. Each configuration is automatically associated to the application and to every eligible addons. |
list(object({
type = string
url = optional(string, "")
drain_region = optional(string, "")
host = optional(string, "")
port = optional(string, "")
token = optional(string, "")
}))
| `[]` | no | +| [name](#input\_name) | Name of the application. Must be unique on Scalingo. | `string` | n/a | yes | | [review\_apps](#input\_review\_apps) | Configuration of the review apps of the application. |
object({
enabled = optional(bool, false)

# By default: delete review apps 0 hours after closing the PR
delete_on_close_enabled = optional(bool, true)
hours_before_delete_on_close = optional(string, "0")

# By default: delete review apps after 5 days of inactivity (= no new deployment)
delete_stale_enabled = optional(bool, true)
hours_before_delete_stale = optional(string, "168")

# By default: do not create review apps for PRs from forks
automatic_creation_from_forks_allowed = optional(bool, false)
})
| `{}` | no | | [router\_logs](#input\_router\_logs) | When true, the router logs are included in the application logs. (default: `false`) | `bool` | `false` | no | | [stack](#input\_stack) | The stack to use for the app (default: "scalingo-22"). | `string` | `"scalingo-22"` | no | diff --git a/log_drains.tf b/log_drains.tf index ee2dbc1..65cfcc6 100644 --- a/log_drains.tf +++ b/log_drains.tf @@ -1,7 +1,9 @@ # Log drains # How it works :https://doc.scalingo.com/platform/app/log-drain # API Docs : https://developers.scalingo.com/log_drains -resource "scalingo_log_drain" "log_drain" { + +# Log drains for applications +resource "scalingo_log_drain" "app" { for_each = { for log_drain in var.log_drains : log_drain.type => log_drain } app = scalingo_app.app.id @@ -11,7 +13,29 @@ resource "scalingo_log_drain" "log_drain" { # Log drain parameters are different depending on the type url = sensitive(each.value.url) drain_region = each.value.drain_region - addon = each.value.addon + host = each.value.host + port = each.value.port + token = sensitive(each.value.token) +} + +# Log drains for addons +resource "scalingo_log_drain" "addons" { + # Create a map of log_drain for each addon and log_drain combination : + # e.g. { "redis-elk" = { addon_id = "xxxx", type = "elk", url = "https://elk.example.com/xxxx" } } + for_each = { for log_drain in setproduct(var.log_drains, values(scalingo_addon.addons)) : + "${log_drain[1].provider_id}-${log_drain[0].type}" + => merge(log_drain[0], { addon_id = log_drain[1].id }) + } + + # Associate the log drain to app AND addon + app = scalingo_app.app.id + addon = each.value.addon_id + + type = each.value.type + + # Log drain parameters are different depending on the type + url = sensitive(each.value.url) + drain_region = each.value.drain_region host = each.value.host port = each.value.port token = sensitive(each.value.token) diff --git a/upgrade_to_v0.3.0.tf b/upgrade_to_v0.3.0.tf new file mode 100644 index 0000000..3fc1108 --- /dev/null +++ b/upgrade_to_v0.3.0.tf @@ -0,0 +1,35 @@ +### Migration from v0.2.0 of the module +### REMOVE when releasing v1.0.0 + +moved { + from = scalingo_log_drain.log_drain["elk"] + to = scalingo_log_drain.app["elk"] +} +moved { + from = scalingo_log_drain.log_drain["appsignal"] + to = scalingo_log_drain.app["appsignal"] +} +moved { + from = scalingo_log_drain.log_drain["logtail"] + to = scalingo_log_drain.app["logtail"] +} +moved { + from = scalingo_log_drain.log_drain["datadog"] + to = scalingo_log_drain.app["datadog"] +} +moved { + from = scalingo_log_drain.log_drain["ovh-graylog"] + to = scalingo_log_drain.app["ovh-graylog"] +} +moved { + from = scalingo_log_drain.log_drain["papertrail"] + to = scalingo_log_drain.app["papertrail"] +} +moved { + from = scalingo_log_drain.log_drain["logtail"] + to = scalingo_log_drain.app["logtail"] +} +moved { + from = scalingo_log_drain.log_drain["syslog"] + to = scalingo_log_drain.app["syslog"] +} diff --git a/variables.tf b/variables.tf index 6610b49..855fc06 100644 --- a/variables.tf +++ b/variables.tf @@ -1,5 +1,6 @@ variable "name" { - type = string + description = "Name of the application. Must be unique on Scalingo." + type = string } variable "stack" { @@ -183,11 +184,11 @@ variable "domain_aliases" { } variable "log_drains" { + description = "List of log_drain configuration to redirect logs from the application and addons to a log management service. Each configuration is automatically associated to the application and to every eligible addons." type = list(object({ type = string url = optional(string, "") drain_region = optional(string, "") - addon = optional(string, "") host = optional(string, "") port = optional(string, "") token = optional(string, "") @@ -202,4 +203,12 @@ variable "log_drains" { ]) == 0 error_message = "The list of log drains must contain only valid log drains type (elk/appsignal/logtail/datadog/ovh-graylog/papertrail/logtail/syslog)." } + + validation { + condition = length([ + for drain in var.log_drains : + drain if drain.type == "elk" && can(length(regex("^https?://([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$", drain.url)) == 0) + ]) == 0 + error_message = "Log drains of type \"elk\" must have a valid url." + } }