feature: support additional ingress host for service exposition

This commit is contained in:
RouxAntoine 2024-09-25 22:06:35 +02:00
parent 7a9d1d9eb1
commit 5dcccbaf01
Signed by: antoine
GPG Key ID: 098FB66FC0475E70
4 changed files with 107 additions and 36 deletions

View File

@ -19,6 +19,10 @@ module "image-uploader-mock" {
} }
] ]
} }
``` ```
## running test
```shell
$ tf test
```

View File

@ -1,5 +1,5 @@
locals { locals {
service_hostname = format("%s.localdomain", var.application_name) service_hostname = format("%s.localdomain", var.application_name)
at_least_one_port = length(var.ports) > 0 ? 1 : 0 at_least_one_port = length(var.ports) > 0 ? 1 : 0
ports_map = { ports_map = {
for index, port in var.ports : format("port-%s", index) => port for index, port in var.ports : format("port-%s", index) => port
@ -9,15 +9,16 @@ locals {
format("port-%s", index) => port if port.expose == true format("port-%s", index) => port if port.expose == true
} }
certificate_secret_name = format("%s-certificate", var.application_name) certificate_secret_name = format("%s-certificate", var.application_name)
at_least_one_port_exposed = length(local.exposed_ports_map) > 0 ? 1 : 0 at_least_one_port_exposed = length(local.exposed_ports_map) > 0
} }
resource "kubernetes_service_v1" "service" { resource "kubernetes_service_v1" "service" {
count = local.at_least_one_port count = local.at_least_one_port
metadata { metadata {
name = var.application_name name = var.application_name
namespace = var.namespace namespace = var.namespace
labels = { labels = {
"app.kubernetes.io/part-of" = var.application_name "app.kubernetes.io/part-of" = var.application_name
"app.kubernetes.io/managed-by" = "terraform" "app.kubernetes.io/managed-by" = "terraform"
} }
@ -28,7 +29,7 @@ resource "kubernetes_service_v1" "service" {
dynamic port { dynamic port {
for_each = local.ports_map for_each = local.ports_map
content { content {
name = format("service-%s", port.key) name = format("service-%s", port.key)
port = port.value.container_port port = port.value.container_port
target_port = port.key target_port = port.key
} }
@ -40,22 +41,27 @@ resource "kubernetes_service_v1" "service" {
} }
resource "kubernetes_manifest" "certificate" { resource "kubernetes_manifest" "certificate" {
count = local.at_least_one_port_exposed # at_least_one_port_exposed is_test result
# 0 0 0
# 0 1 0
# 1 0 1
# 1 1 0
count = local.at_least_one_port_exposed && !var.is_test ? 1 : 0
manifest = { manifest = {
apiVersion = "cert-manager.io/v1" apiVersion = "cert-manager.io/v1"
kind = "Certificate" kind = "Certificate"
metadata = { metadata = {
name = var.application_name name = var.application_name
namespace = var.namespace namespace = var.namespace
labels = { labels = {
"app.kubernetes.io/part-of" = var.application_name "app.kubernetes.io/part-of" = var.application_name
"app.kubernetes.io/managed-by" = "terraform" "app.kubernetes.io/managed-by" = "terraform"
} }
} }
spec = { spec = {
secretName = local.certificate_secret_name secretName = local.certificate_secret_name
dnsNames = [ dnsNames = [
local.service_hostname, local.service_hostname,
format("*.%s", local.service_hostname) format("*.%s", local.service_hostname)
] ]
@ -74,7 +80,7 @@ resource "kubernetes_ingress_v1" "ingress" {
metadata { metadata {
name = var.application_name name = var.application_name
namespace = var.namespace namespace = var.namespace
labels = { labels = {
"app.kubernetes.io/part-of" = var.application_name "app.kubernetes.io/part-of" = var.application_name
"app.kubernetes.io/managed-by" = "terraform" "app.kubernetes.io/managed-by" = "terraform"
} }
@ -84,16 +90,21 @@ resource "kubernetes_ingress_v1" "ingress" {
} }
} }
spec { spec {
rule { dynamic rule {
host = local.service_hostname for_each = concat(
http { var.additional_ingress_host, [local.service_hostname]
path { )
path = "/" content {
backend { host = rule.value
service { http {
name = kubernetes_service_v1.service[0].metadata.0.name path {
port { path = "/"
name = format("service-%s", each.key) backend {
service {
name = kubernetes_service_v1.service[0].metadata.0.name
port {
name = format("service-%s", each.key)
}
} }
} }
} }
@ -101,7 +112,9 @@ resource "kubernetes_ingress_v1" "ingress" {
} }
} }
tls { tls {
hosts = [local.service_hostname] hosts = concat(
var.additional_ingress_host, [local.service_hostname]
)
secret_name = local.certificate_secret_name secret_name = local.certificate_secret_name
} }
} }
@ -109,15 +122,20 @@ resource "kubernetes_ingress_v1" "ingress" {
# {{ application_name }}.localdomain IN CNAME internal-lb # {{ application_name }}.localdomain IN CNAME internal-lb
resource "kubernetes_manifest" "record" { resource "kubernetes_manifest" "record" {
count = local.at_least_one_port_exposed # at_least_one_port_exposed is_test result
# 0 0 0
# 0 1 0
# 1 0 1
# 1 1 0
count = local.at_least_one_port_exposed && !var.is_test ? 1 : 0
manifest = { manifest = {
apiVersion = "externaldns.k8s.io/v1alpha1" apiVersion = "externaldns.k8s.io/v1alpha1"
kind = "DNSEndpoint" kind = "DNSEndpoint"
metadata = { metadata = {
name = var.application_name name = var.application_name
namespace = var.namespace namespace = var.namespace
labels = { labels = {
"app.kubernetes.io/part-of" = var.application_name "app.kubernetes.io/part-of" = var.application_name
"app.kubernetes.io/managed-by" = "terraform" "app.kubernetes.io/managed-by" = "terraform"
} }
@ -128,7 +146,7 @@ resource "kubernetes_manifest" "record" {
dnsName = local.service_hostname dnsName = local.service_hostname
recordTTL = "180" recordTTL = "180"
recordType = "CNAME" recordType = "CNAME"
targets = [ targets = [
"internal-lb.localdomain" "internal-lb.localdomain"
] ]
} }

View File

@ -58,4 +58,16 @@ variable "replicas" {
type = number type = number
default = 1 default = 1
description = "number of replicas for the application's pod" description = "number of replicas for the application's pod"
}
variable "additional_ingress_host" {
type = list(string)
default = []
description = "list of additional ingress host allowed for this service"
}
variable "is_test" {
type = bool
default = false
description = "mode to declare if the module is run in terraform test mode or in classical mode"
} }

View File

@ -1,14 +1,14 @@
run "terraform-plan" { variables {
command = plan application_name = "test-application"
namespace = "test-namespace"
variables { image = {
application_name = "test-application" name = "container.localdomain/test-image"
namespace = "test-namespace"
image = {
name = "container.localdomain/test-image"
}
replicas = 2
} }
replicas = 2
}
run "test_deployment_classic" {
command = plan
assert { assert {
condition = var.application_name == "test-application" condition = var.application_name == "test-application"
@ -16,7 +16,44 @@ run "terraform-plan" {
} }
assert { assert {
condition = kubernetes_deployment_v1.deployment.spec[0].replicas == "2" condition = kubernetes_deployment_v1.deployment.spec[0].replicas == "2"
error_message = "invalid number of replicas" error_message = "invalid number of replicas"
} }
} }
run "test_deployment_custom_additional_ingress_host" {
command = plan
variables {
is_test = true
ports = [
{
container_port = 8083
expose = true
}
]
additional_ingress_host = ["additional-hostname.localdomain"]
}
assert {
condition = alltrue(flatten([
for ingress in values(kubernetes_ingress_v1.ingress) : [
for ingressSpec in ingress.spec :
contains(ingressSpec.rule.*.host, "additional-hostname.localdomain")
]
]))
error_message = "additional dns not add in ingress host rule"
}
assert {
condition = anytrue(flatten([
for ingress in values(kubernetes_ingress_v1.ingress) : [
for ingressSpec in ingress.spec : [
for ingressSpecTls in ingressSpec.tls :
contains(ingressSpecTls.hosts, "additional-hostname.localdomain")
]
]
]))
error_message = "additional dns not add in ingress tls hosts"
}
}