From 1f445e8bb8e7e424eed258d3aacf2a6261583c46 Mon Sep 17 00:00:00 2001 From: magusd Date: Fri, 19 Apr 2024 17:22:04 -0300 Subject: [PATCH] mv aws module to addons, adding example usage, adding readme files with tfdocs --- README.md | 94 ++++++++++++++++++- addons_aws_s3.tf | 10 ++ aws.tf | 7 -- examples/simpleapp/README.md | 30 ++++++ examples/simpleapp/config.auto.tfvars | 9 ++ examples/simpleapp/main.tf | 68 ++++++++++++++ examples/simpleapp/providers.tf | 17 ++++ examples/simpleapp/variables.tf | 17 ++++ examples/simpleapp/versions.tf | 12 +++ locals.tf | 10 +- modules/aws/iam.tf | 21 ----- modules/aws/main.tf | 7 -- modules/aws/outputs.tf | 7 -- modules/aws/storage.tf | 24 ----- modules/aws/variables.tf | 11 --- .../README.md | 41 ++++++++ .../terraform-aws-addon-file-storage/data.tf | 0 .../examples/media_bucket/README.md | 27 ++++++ .../examples/media_bucket/main.tf | 11 +++ .../media_bucket/variables.auto.tfvars | 1 + .../examples/media_bucket/variables.tf | 3 + .../iam_user.tf | 21 +++++ .../terraform-aws-addon-file-storage/main.tf | 33 +++++++ .../output.tf | 7 ++ .../variables.tf | 11 +++ outputs.tf | 1 + variables.tf | 35 ++++--- 27 files changed, 438 insertions(+), 97 deletions(-) create mode 100644 addons_aws_s3.tf delete mode 100644 aws.tf create mode 100644 examples/simpleapp/README.md create mode 100644 examples/simpleapp/config.auto.tfvars create mode 100644 examples/simpleapp/main.tf create mode 100644 examples/simpleapp/providers.tf create mode 100644 examples/simpleapp/variables.tf create mode 100644 examples/simpleapp/versions.tf delete mode 100644 modules/aws/iam.tf delete mode 100644 modules/aws/main.tf delete mode 100644 modules/aws/outputs.tf delete mode 100644 modules/aws/storage.tf delete mode 100644 modules/aws/variables.tf create mode 100644 modules/terraform-aws-addon-file-storage/README.md create mode 100644 modules/terraform-aws-addon-file-storage/data.tf create mode 100644 modules/terraform-aws-addon-file-storage/examples/media_bucket/README.md create mode 100644 modules/terraform-aws-addon-file-storage/examples/media_bucket/main.tf create mode 100644 modules/terraform-aws-addon-file-storage/examples/media_bucket/variables.auto.tfvars create mode 100644 modules/terraform-aws-addon-file-storage/examples/media_bucket/variables.tf create mode 100644 modules/terraform-aws-addon-file-storage/iam_user.tf create mode 100644 modules/terraform-aws-addon-file-storage/main.tf create mode 100644 modules/terraform-aws-addon-file-storage/output.tf create mode 100644 modules/terraform-aws-addon-file-storage/variables.tf diff --git a/README.md b/README.md index 455957c..67d96a9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,92 @@ -# terraform-kubernetes-django -Deploy Django with Terraform to Kubernetes with optional support for AWS/EKS or GCP/GKE +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.3.0 | +| [kubernetes](#requirement\_kubernetes) | >= 2.4.0 | + +## Providers + +| Name | Version | +|------|---------| +| [kubernetes](#provider\_kubernetes) | >= 2.4.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [addons\_aws\_bucket](#module\_addons\_aws\_bucket) | ./modules/terraform-aws-addon-file-storage | n/a | +| [cloudflare](#module\_cloudflare) | ./modules/cloudflare | n/a | +| [deployment](#module\_deployment) | djangoflow/deployment/kubernetes | >=2.5.1 | +| [gcp](#module\_gcp) | ./modules/gcp | n/a | +| [postgresql](#module\_postgresql) | djangoflow/postgresql/kubernetes | 1.1.2 | +| [redis](#module\_redis) | djangoflow/redis/kubernetes | n/a | + +## Resources + +| Name | Type | +|------|------| +| [kubernetes_horizontal_pod_autoscaler_v1.hpa](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/horizontal_pod_autoscaler_v1) | resource | +| [kubernetes_ingress_v1.ingress](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/ingress_v1) | resource | +| [kubernetes_namespace_v1.namespace](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace_v1) | resource | +| [kubernetes_persistent_volume_claim_v1.pgdata](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim_v1) | resource | +| [kubernetes_pod_disruption_budget_v1.pdb](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/pod_disruption_budget_v1) | resource | +| [kubernetes_secret_v1.secrets](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret_v1) | resource | +| [kubernetes_service_account_v1.service_account](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service_account_v1) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [addons](#input\_addons) | list of addons to enable |
map(object({
addon_type = string
config = any
}))
| `{}` | no | +| [celery\_beat\_defaults](#input\_celery\_beat\_defaults) | n/a | `map` |
{
"args": [
"/start-celerybeat"
],
"command": null,
"env": {},
"hpa_max_replicas": 0,
"liveness_probe": {
"command": [],
"enabled": false
},
"name": "celery-beat",
"pdb_min_available": 0,
"port": 0,
"pre_install_command": [],
"pre_install_migrate": false,
"readiness_probe": {
"command": [],
"enabled": false
},
"replicas": 1,
"resources_limits_cpu": "250m",
"resources_limits_memory": "256Mi",
"resources_requests_cpu": "30m",
"resources_requests_memory": "90Mi"
}
| no | +| [celery\_db\_index](#input\_celery\_db\_index) | n/a | `string` | `"2"` | no | +| [celery\_enabled](#input\_celery\_enabled) | A short-hand for adding celery-beat and celery-worker deployments | `bool` | `true` | no | +| [celery\_worker\_defaults](#input\_celery\_worker\_defaults) | n/a | `map` |
{
"args": [
"/start-celeryworker"
],
"command": null,
"env": {},
"hpa_max_replicas": 0,
"liveness_probe": {
"command": [
"celery",
"-A",
"config.celery_app",
"inspect",
"ping"
],
"enabled": true
},
"name": "celery-worker",
"pdb_min_available": 0,
"port": 0,
"pre_install_command": [],
"pre_install_migrate": false,
"readiness_probe": {
"command": [],
"enabled": false
},
"replicas": 1,
"resources_limits_cpu": "900m",
"resources_limits_memory": "768Mi",
"resources_requests_cpu": "100m",
"resources_requests_memory": "128Mi"
}
| no | +| [cloud\_sa\_name](#input\_cloud\_sa\_name) | Name of the GCP/AWS service account if any | `string` | `null` | no | +| [cloudflare\_enabled](#input\_cloudflare\_enabled) | Create cloudflare records if true | `bool` | `true` | no | +| [create\_namespace](#input\_create\_namespace) | Should we create the namespace or use existing provided? | `bool` | `true` | no | +| [deployments](#input\_deployments) | Deployments |
map(object({
name = string
replicas = optional(number, 1)
command = optional(list(string))
args = optional(list(string), ["/start"])
port = optional(number)
resources_requests_cpu = optional(string, "100m")
resources_requests_memory = optional(string, "256Mi")
resources_limits_cpu = optional(string, "1000m")
resources_limits_memory = optional(string, "2Gi")
pdb_min_available = optional(number, 0)
hpa_min_replicas = optional(number, 0)
hpa_max_replicas = optional(number, 0)
hpa_target_cpu = optional(number, 80)
pre_install_migrate = optional(bool, false)
pre_install_command = optional(list(string), [])
env = optional(map(string))
liveness_probe = optional(object({
enabled = optional(bool, true)
http_get = optional(object({
path = string
port = number
scheme = string
}))
command = optional(list(string), [])
success_threshold = optional(number)
failure_threshold = optional(number)
initial_delay_seconds = optional(number)
period_seconds = optional(number)
timeout_seconds = optional(number)
}))
readiness_probe = optional(object({
enabled = optional(bool, true)
http_get = optional(object({
path = string
port = number
scheme = string
}))
command = optional(list(string), [])
success_threshold = optional(number)
failure_threshold = optional(number)
initial_delay_seconds = optional(number)
period_seconds = optional(number)
timeout_seconds = optional(number)
}))
}))
|
{
"web": {
"name": "web",
"port": 5000,
"pre_install_command": [],
"pre_install_migrate": true,
"replicas": 1
}
}
| no | +| [env](#input\_env) | A map of extra environment variables | `map(string)` | `{}` | no | +| [extra\_labels](#input\_extra\_labels) | Extra labels to add to generated objects | `map(string)` | `{}` | no | +| [gcp\_add\_aws\_s3\_env](#input\_gcp\_add\_aws\_s3\_env) | Add AWS\_ variables for the GCS bucket | `bool` | `false` | no | +| [gcp\_bucket\_location](#input\_gcp\_bucket\_location) | The location of the bucket, e.g. EU or US | `string` | n/a | yes | +| [gcp\_bucket\_name](#input\_gcp\_bucket\_name) | Create and use Google storage with this name | `string` | `null` | no | +| [gcp\_db\_instance](#input\_gcp\_db\_instance) | Create a database and a user for this installation and use them instead of DATABASE\_URL | `string` | `null` | no | +| [gcp\_sa\_extra\_roles](#input\_gcp\_sa\_extra\_roles) | Create role bindings to these roles | `list(string)` | `null` | no | +| [image\_name](#input\_image\_name) | Docker image repository and name | `string` | n/a | yes | +| [image\_pull\_policy](#input\_image\_pull\_policy) | Pull policy for the images | `string` | `"IfNotPresent"` | no | +| [image\_pull\_secrets](#input\_image\_pull\_secrets) | Image pull secrets | `list(string)` | `[]` | no | +| [image\_tag](#input\_image\_tag) | Docker image tag | `string` | n/a | yes | +| [ingress](#input\_ingress) | A map of hostnames with maps of path-names and services | `map(map(string))` | n/a | yes | +| [ingress\_annotations](#input\_ingress\_annotations) | n/a | `map(string)` | `{}` | no | +| [liveness\_probe](#input\_liveness\_probe) | Liveness probe for containers which have ports |
object({
http_get = object({
path = string
port = number
scheme = string
})
success_threshold = number
failure_threshold = number
initial_delay_seconds = number
period_seconds = number
timeout_seconds = number
})
|
{
"failure_threshold": 3,
"http_get": {
"path": "/healthz/",
"port": 5000,
"scheme": "HTTP"
},
"initial_delay_seconds": 20,
"period_seconds": 30,
"success_threshold": 1,
"timeout_seconds": 5
}
| no | +| [name](#input\_name) | The name for deployment | `string` | `"django"` | no | +| [namespace](#input\_namespace) | Kubernetes namespace to use with this installation | `string` | n/a | yes | +| [postgres\_enabled](#input\_postgres\_enabled) | Create a postgres database deployment | `bool` | `false` | no | +| [postgres\_resources\_limits\_cpu](#input\_postgres\_resources\_limits\_cpu) | n/a | `string` | `null` | no | +| [postgres\_resources\_limits\_memory](#input\_postgres\_resources\_limits\_memory) | n/a | `string` | `null` | no | +| [postgres\_resources\_requests\_cpu](#input\_postgres\_resources\_requests\_cpu) | n/a | `string` | `"250m"` | no | +| [postgres\_resources\_requests\_memory](#input\_postgres\_resources\_requests\_memory) | n/a | `string` | `"256Mi"` | no | +| [postgres\_storage\_size](#input\_postgres\_storage\_size) | n/a | `string` | `"10Gi"` | no | +| [public\_storage](#input\_public\_storage) | Make the storge GCP bucket/AWS S3 public and create a CNAME | `bool` | `true` | no | +| [readiness\_probe](#input\_readiness\_probe) | Readiness probe for containers which have ports |
object({
http_get = object({
path = string
port = number
scheme = string
})
success_threshold = number
failure_threshold = number
initial_delay_seconds = number
period_seconds = number
timeout_seconds = number
})
|
{
"failure_threshold": 3,
"http_get": {
"path": "/healthz/",
"port": 5000,
"scheme": "HTTP"
},
"initial_delay_seconds": 20,
"period_seconds": 30,
"success_threshold": 1,
"timeout_seconds": 5
}
| no | +| [redis\_db\_index](#input\_redis\_db\_index) | n/a | `string` | `"1"` | no | +| [redis\_enabled](#input\_redis\_enabled) | Create a redis database deployment | `bool` | `false` | no | +| [redis\_resources\_limits\_cpu](#input\_redis\_resources\_limits\_cpu) | n/a | `string` | `null` | no | +| [redis\_resources\_limits\_memory](#input\_redis\_resources\_limits\_memory) | n/a | `string` | `null` | no | +| [redis\_resources\_requests\_cpu](#input\_redis\_resources\_requests\_cpu) | n/a | `string` | `"50m"` | no | +| [redis\_resources\_requests\_memory](#input\_redis\_resources\_requests\_memory) | n/a | `string` | `"128Mi"` | no | +| [secret\_env](#input\_secret\_env) | A map of extra secret environment variables | `map(string)` | n/a | yes | +| [security\_context\_enabled](#input\_security\_context\_enabled) | n/a | `bool` | `false` | no | +| [security\_context\_fsgroup](#input\_security\_context\_fsgroup) | n/a | `any` | `null` | no | +| [security\_context\_gid](#input\_security\_context\_gid) | n/a | `number` | `101` | no | +| [security\_context\_uid](#input\_security\_context\_uid) | n/a | `number` | `101` | no | +| [service\_account\_name](#input\_service\_account\_name) | Name of the kubernetes service account if any | `string` | `null` | no | +| [volumes](#input\_volumes) | Volume configuration | `any` | `[]` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [database\_url](#output\_database\_url) | n/a | diff --git a/addons_aws_s3.tf b/addons_aws_s3.tf new file mode 100644 index 0000000..ac75e10 --- /dev/null +++ b/addons_aws_s3.tf @@ -0,0 +1,10 @@ +locals { + aws_buckets = {for k,v in var.addons : k => v if v.addon_type == "aws.bucket"} +} + +module "addons_aws_bucket" { + for_each = local.aws_buckets + source = "./modules/terraform-aws-addon-file-storage" + name = each.value.config.name + username = each.value.config.username +} \ No newline at end of file diff --git a/aws.tf b/aws.tf deleted file mode 100644 index 6016551..0000000 --- a/aws.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "aws" { - count = var.aws_s3_name != null ? 1 : 0 - source = "./modules/aws" - aws_s3_name = var.aws_s3_name - aws_s3_public = var.public_storage - aws_sa_name = var.cloud_sa_name -} diff --git a/examples/simpleapp/README.md b/examples/simpleapp/README.md new file mode 100644 index 0000000..47cdec4 --- /dev/null +++ b/examples/simpleapp/README.md @@ -0,0 +1,30 @@ +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.0.0 | + +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [django\_app](#module\_django\_app) | ../../ | n/a | + +## Resources + +No resources. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aws](#input\_aws) | n/a |
object({
region = string
profile = string
})
| n/a | yes | +| [cloudflare](#input\_cloudflare) | n/a |
object({
api_key = string
email = string
})
|
{
"api_key": "",
"email": ""
}
| no | + +## Outputs + +No outputs. diff --git a/examples/simpleapp/config.auto.tfvars b/examples/simpleapp/config.auto.tfvars new file mode 100644 index 0000000..4e7bf5b --- /dev/null +++ b/examples/simpleapp/config.auto.tfvars @@ -0,0 +1,9 @@ +cloudflare = { + api_key = "a9fcaab0378b7d2c4c74ab0663b25e53c5b4f" + email = "vitor.lobs@gmail.com" +} + +aws = { + region = "us-east-1" + profile = "me" +} \ No newline at end of file diff --git a/examples/simpleapp/main.tf b/examples/simpleapp/main.tf new file mode 100644 index 0000000..4952daf --- /dev/null +++ b/examples/simpleapp/main.tf @@ -0,0 +1,68 @@ +locals { + app_name = "djangoflow-apexive-magusd" +} +module "django_app" { + source = "../../" + + service_account_name = local.app_name + + gcp_bucket_location = "US" + image_name = "nginx" + image_tag = "latest" + ingress = { + "api.demo.djangoflow.com" : { + "/" : "api" + } + } + namespace = "djangoflow-test-simpleapp" + secret_env = { + "DATABASE_URL" = "127.0.0.1" + "REDIS_URL" = "127.0.0.1" + } + + deployments = { + simpleapp = { + name = "simpleapp" + port = 80 + liveness_probe = { + enabled = true + http_get = { + path = "/" + port = 80 + scheme = "HTTP" + } + success_threshold = 1 + failure_threshold = 3 + initial_delay_seconds = 5 + period_seconds = 10 + timeout_seconds = 1 + } + + readiness_probe = { + enabled = true + http_get = { + path = "/" + port = 80 + scheme = "HTTP" + } + success_threshold = 1 + failure_threshold = 3 + initial_delay_seconds = 5 + period_seconds = 10 + timeout_seconds = 1 + } + } + } + + + addons = { + media = { + addon_type = "aws.bucket" + config = { + name = local.app_name + username = local.app_name + public = true + } + } + } +} diff --git a/examples/simpleapp/providers.tf b/examples/simpleapp/providers.tf new file mode 100644 index 0000000..386c8cd --- /dev/null +++ b/examples/simpleapp/providers.tf @@ -0,0 +1,17 @@ + +provider "cloudflare" { + api_key = var.cloudflare.api_key + email = var.cloudflare.email +} + +provider "aws" { + region = var.aws.region + profile = var.aws.profile +} + +provider "google" { + # project = "apexive-magusd" + # region = "us-east1" + project = "none" + region = "none" +} diff --git a/examples/simpleapp/variables.tf b/examples/simpleapp/variables.tf new file mode 100644 index 0000000..ef0c152 --- /dev/null +++ b/examples/simpleapp/variables.tf @@ -0,0 +1,17 @@ +variable "cloudflare" { + type = object({ + api_key = string + email = string + }) + default = { + api_key = "" + email = "" + } +} + +variable "aws" { + type = object({ + region = string + profile = string + }) +} diff --git a/examples/simpleapp/versions.tf b/examples/simpleapp/versions.tf new file mode 100644 index 0000000..b64e2cb --- /dev/null +++ b/examples/simpleapp/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.0.0" + } + + cloudflare = { + source = "cloudflare/cloudflare" + } + } +} diff --git a/locals.tf b/locals.tf index 29384d8..9d4e956 100644 --- a/locals.tf +++ b/locals.tf @@ -27,11 +27,11 @@ locals { AWS_STORAGE_BUCKET_NAME : var.gcp_bucket_name AWS_S3_ENDPOINT_URL : "https://storage.googleapis.com" } - aws_env = var.aws_s3_name == null ? {} : { - AWS_ACCESS_KEY_ID : module.aws.0.aws_iam_access_key.id - AWS_SECRET_ACCESS_KEY : module.aws.0.aws_iam_access_key.secret - AWS_STORAGE_BUCKET_NAME : var.aws_s3_name - AWS_S3_ENDPOINT_URL : module.aws.0.aws_s3_endpoint_url + aws_env = length(local.aws_buckets) > 0 ? {} : { + AWS_ACCESS_KEY_ID : module.addons_aws_bucket.0.aws_iam_access_key.id + AWS_SECRET_ACCESS_KEY : module.addons_aws_bucket.0.aws_iam_access_key.secret + AWS_STORAGE_BUCKET_NAME : local.aws_buckets.0.config.name + AWS_S3_ENDPOINT_URL : module.addons_aws_bucket.0.aws_s3_endpoint_url } env = merge(local.gcp_env, local.aws_env, var.env) diff --git a/modules/aws/iam.tf b/modules/aws/iam.tf deleted file mode 100644 index ecf713b..0000000 --- a/modules/aws/iam.tf +++ /dev/null @@ -1,21 +0,0 @@ -resource "aws_iam_user" "sa" { - name = var.aws_sa_name -} - -resource "aws_iam_access_key" "sa" { - user = aws_iam_user.sa.name -} - -data "aws_iam_policy_document" "default" { - statement { - actions = ["s3:*"] - resources = [aws_s3_bucket.media-bucket.arn, "${aws_s3_bucket.media-bucket.arn}/*"] - effect = "Allow" - } -} - -resource "aws_iam_user_policy" "storage" { - name = aws_iam_user.sa.name - user = aws_iam_user.sa.name - policy = join("", data.aws_iam_policy_document.default.*.json) -} diff --git a/modules/aws/main.tf b/modules/aws/main.tf deleted file mode 100644 index f2702bf..0000000 --- a/modules/aws/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - } - } -} diff --git a/modules/aws/outputs.tf b/modules/aws/outputs.tf deleted file mode 100644 index 04b5557..0000000 --- a/modules/aws/outputs.tf +++ /dev/null @@ -1,7 +0,0 @@ -output "aws_iam_access_key" { - value = aws_iam_access_key.sa -} - -output "aws_s3_endpoint_url" { - value = "https://s3.${aws_s3_bucket.media-bucket.region}.amazonaws.com" -} diff --git a/modules/aws/storage.tf b/modules/aws/storage.tf deleted file mode 100644 index 8e9580c..0000000 --- a/modules/aws/storage.tf +++ /dev/null @@ -1,24 +0,0 @@ -# TODO: support aws_s3_public -resource "aws_s3_bucket" "media-bucket" { - bucket = var.aws_s3_name -} - -resource "aws_s3_bucket_cors_configuration" "media-bucket" { - bucket = aws_s3_bucket.media-bucket.bucket - - cors_rule { - allowed_headers = [] - allowed_methods = ["GET"] - allowed_origins = ["*"] - expose_headers = ["Content-Type"] - } -} - -resource "aws_s3_bucket_website_configuration" "media-bucket" { - bucket = aws_s3_bucket.media-bucket.bucket - - index_document { - suffix = "index.html" - } -} - diff --git a/modules/aws/variables.tf b/modules/aws/variables.tf deleted file mode 100644 index 7aa081d..0000000 --- a/modules/aws/variables.tf +++ /dev/null @@ -1,11 +0,0 @@ -variable "aws_sa_name" { - type = string -} - -variable "aws_s3_name" { - type = string -} - -variable "aws_s3_public" { - default = true -} diff --git a/modules/terraform-aws-addon-file-storage/README.md b/modules/terraform-aws-addon-file-storage/README.md new file mode 100644 index 0000000..9031e03 --- /dev/null +++ b/modules/terraform-aws-addon-file-storage/README.md @@ -0,0 +1,41 @@ +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_iam_access_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource | +| [aws_iam_user.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource | +| [aws_iam_user_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy) | resource | +| [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | +| [aws_s3_bucket_cors_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_cors_configuration) | resource | +| [aws_s3_bucket_public_access_block.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | +| [aws_s3_bucket_website_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_website_configuration) | resource | +| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [name](#input\_name) | n/a | `string` | n/a | yes | +| [public](#input\_public) | n/a | `bool` | `true` | no | +| [username](#input\_username) | n/a | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [aws\_iam\_access\_key](#output\_aws\_iam\_access\_key) | n/a | +| [aws\_s3\_endpoint\_url](#output\_aws\_s3\_endpoint\_url) | n/a | diff --git a/modules/terraform-aws-addon-file-storage/data.tf b/modules/terraform-aws-addon-file-storage/data.tf new file mode 100644 index 0000000..e69de29 diff --git a/modules/terraform-aws-addon-file-storage/examples/media_bucket/README.md b/modules/terraform-aws-addon-file-storage/examples/media_bucket/README.md new file mode 100644 index 0000000..7db0754 --- /dev/null +++ b/modules/terraform-aws-addon-file-storage/examples/media_bucket/README.md @@ -0,0 +1,27 @@ +## Requirements + +No requirements. + +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [media](#module\_media) | ../../ | n/a | + +## Resources + +No resources. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aws\_profile](#input\_aws\_profile) | n/a | `string` | n/a | yes | + +## Outputs + +No outputs. diff --git a/modules/terraform-aws-addon-file-storage/examples/media_bucket/main.tf b/modules/terraform-aws-addon-file-storage/examples/media_bucket/main.tf new file mode 100644 index 0000000..eba1233 --- /dev/null +++ b/modules/terraform-aws-addon-file-storage/examples/media_bucket/main.tf @@ -0,0 +1,11 @@ +module "media" { + source = "../../" + name = "example-media-bucket-djangoflow" + public = true + username = "example-media-user" +} + +provider "aws" { + profile = var.aws_profile + region = "us-east-1" +} \ No newline at end of file diff --git a/modules/terraform-aws-addon-file-storage/examples/media_bucket/variables.auto.tfvars b/modules/terraform-aws-addon-file-storage/examples/media_bucket/variables.auto.tfvars new file mode 100644 index 0000000..2c4aaa4 --- /dev/null +++ b/modules/terraform-aws-addon-file-storage/examples/media_bucket/variables.auto.tfvars @@ -0,0 +1 @@ +aws_profile = "me" \ No newline at end of file diff --git a/modules/terraform-aws-addon-file-storage/examples/media_bucket/variables.tf b/modules/terraform-aws-addon-file-storage/examples/media_bucket/variables.tf new file mode 100644 index 0000000..8d35a90 --- /dev/null +++ b/modules/terraform-aws-addon-file-storage/examples/media_bucket/variables.tf @@ -0,0 +1,3 @@ +variable "aws_profile" { + type = string +} diff --git a/modules/terraform-aws-addon-file-storage/iam_user.tf b/modules/terraform-aws-addon-file-storage/iam_user.tf new file mode 100644 index 0000000..239123e --- /dev/null +++ b/modules/terraform-aws-addon-file-storage/iam_user.tf @@ -0,0 +1,21 @@ +resource "aws_iam_user" "this" { + name = var.username +} + +resource "aws_iam_access_key" "this" { + user = aws_iam_user.this.name +} + +data "aws_iam_policy_document" "this" { + statement { + actions = ["s3:*"] + resources = [aws_s3_bucket.this.arn, "${aws_s3_bucket.this.arn}/*"] + effect = "Allow" + } +} + +resource "aws_iam_user_policy" "this" { + name = aws_iam_user.this.name + user = aws_iam_user.this.name + policy = join("", data.aws_iam_policy_document.this.*.json) +} diff --git a/modules/terraform-aws-addon-file-storage/main.tf b/modules/terraform-aws-addon-file-storage/main.tf new file mode 100644 index 0000000..b84578d --- /dev/null +++ b/modules/terraform-aws-addon-file-storage/main.tf @@ -0,0 +1,33 @@ + +resource "aws_s3_bucket_public_access_block" "this" { + bucket = aws_s3_bucket.this.id + + block_public_acls = ! var.public + block_public_policy = ! var.public + ignore_public_acls = ! var.public + restrict_public_buckets = ! var.public +} + +resource "aws_s3_bucket" "this" { + bucket = var.name +} + +resource "aws_s3_bucket_cors_configuration" "this" { + bucket = aws_s3_bucket.this.bucket + + cors_rule { + allowed_headers = [] + allowed_methods = ["GET"] + allowed_origins = ["*"] + expose_headers = ["Content-Type"] + } +} + +resource "aws_s3_bucket_website_configuration" "this" { + bucket = aws_s3_bucket.this.bucket + + index_document { + suffix = "index.html" + } +} + diff --git a/modules/terraform-aws-addon-file-storage/output.tf b/modules/terraform-aws-addon-file-storage/output.tf new file mode 100644 index 0000000..eeedefc --- /dev/null +++ b/modules/terraform-aws-addon-file-storage/output.tf @@ -0,0 +1,7 @@ +output "aws_iam_access_key" { + value = aws_iam_access_key.this +} + +output "aws_s3_endpoint_url" { + value = "https://s3.${aws_s3_bucket.this.region}.amazonaws.com" +} diff --git a/modules/terraform-aws-addon-file-storage/variables.tf b/modules/terraform-aws-addon-file-storage/variables.tf new file mode 100644 index 0000000..d8078f7 --- /dev/null +++ b/modules/terraform-aws-addon-file-storage/variables.tf @@ -0,0 +1,11 @@ +variable "username" { + type = string +} + +variable "name" { + type = string +} + +variable "public" { + default = true +} diff --git a/outputs.tf b/outputs.tf index 9d762a1..d86cafd 100644 --- a/outputs.tf +++ b/outputs.tf @@ -2,5 +2,6 @@ output "database_url" { value = coalesce( module.gcp != [] ? module.gcp.0.database_url : null, module.postgresql != [] ? module.postgresql.0.database_url : null, + var.secret_env["DATABASE_URL"], ) } diff --git a/variables.tf b/variables.tf index 1c2ecc0..c1dac06 100644 --- a/variables.tf +++ b/variables.tf @@ -122,8 +122,8 @@ variable "deployments" { pre_install_migrate = optional(bool, false) pre_install_command = optional(list(string), []) env = optional(map(string)) - liveness_probe = optional(object({ - enabled = optional(bool, true) + liveness_probe = optional(object({ + enabled = optional(bool, true) http_get = optional(object({ path = string port = number @@ -137,7 +137,7 @@ variable "deployments" { timeout_seconds = optional(number) })) readiness_probe = optional(object({ - enabled = optional(bool, true) + enabled = optional(bool, true) http_get = optional(object({ path = string port = number @@ -176,7 +176,7 @@ variable "readiness_probe" { timeout_seconds = number }) description = "Readiness probe for containers which have ports" - default = { + default = { http_get = { path = "/healthz/" port = 5000 @@ -204,7 +204,7 @@ variable "liveness_probe" { timeout_seconds = number }) description = "Liveness probe for containers which have ports" - default = { + default = { http_get = { path = "/healthz/" port = 5000 @@ -321,7 +321,7 @@ variable "celery_beat_defaults" { pre_install_command = [] args = ["/start-celerybeat"] port = 0 - liveness_probe = { + liveness_probe = { enabled = false command = [] } @@ -348,7 +348,7 @@ variable "celery_worker_defaults" { pre_install_command = [] args = ["/start-celeryworker"] port = 0 - liveness_probe = { + liveness_probe = { enabled = true command = ["celery", "-A", "config.celery_app", "inspect", "ping"] } @@ -366,12 +366,6 @@ variable "celery_worker_defaults" { } } -variable "aws_s3_name" { - type = string - default = null - description = "Create and use AWS S3" -} - variable "volumes" { type = any description = "Volume configuration" @@ -394,3 +388,18 @@ variable "security_context_uid" { variable "security_context_fsgroup" { default = null } + + +variable "addons" { + description = "list of addons to enable" + type = map(object({ + addon_type = string + config = any + })) + default = {} + + validation { + condition = alltrue([for k,v in var.addons : contains(["aws.bucket"], v.addon_type)]) + error_message = "The database_name must be lower cased." + } +}