Skip to content

Commit

Permalink
feat: Support enabled flag for EKS Storage Classes (#1173)
Browse files Browse the repository at this point in the history
  • Loading branch information
milldr authored Oct 31, 2024
1 parent 29f90e0 commit fba6cde
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 5 deletions.
4 changes: 2 additions & 2 deletions modules/eks/storage-class/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ eks/storage-class:
| <a name="input_context"></a> [context](#input\_context) | Single object for setting entire context at once.<br>See description of individual variables for details.<br>Leave string and numeric variables as `null` to use default value.<br>Individual variable settings (non-null) override settings in context object,<br>except for attributes, tags, and additional\_tag\_map, which are merged. | `any` | <pre>{<br> "additional_tag_map": {},<br> "attributes": [],<br> "delimiter": null,<br> "descriptor_formats": {},<br> "enabled": true,<br> "environment": null,<br> "id_length_limit": null,<br> "label_key_case": null,<br> "label_order": [],<br> "label_value_case": null,<br> "labels_as_tags": [<br> "unset"<br> ],<br> "name": null,<br> "namespace": null,<br> "regex_replace_chars": null,<br> "stage": null,<br> "tags": {},<br> "tenant": null<br>}</pre> | no |
| <a name="input_delimiter"></a> [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.<br>Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no |
| <a name="input_descriptor_formats"></a> [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.<br>Map of maps. Keys are names of descriptors. Values are maps of the form<br>`{<br> format = string<br> labels = list(string)<br>}`<br>(Type is `any` so the map values can later be enhanced to provide additional options.)<br>`format` is a Terraform format string to be passed to the `format()` function.<br>`labels` is a list of labels, in order, to pass to `format()` function.<br>Label values will be normalized before being passed to `format()` so they will be<br>identical to how they appear in `id`.<br>Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no |
| <a name="input_ebs_storage_classes"></a> [ebs\_storage\_classes](#input\_ebs\_storage\_classes) | A map of storage class name to EBS parameters to create | <pre>map(object({<br> make_default_storage_class = optional(bool, false)<br> include_tags = optional(bool, true) # If true, StorageClass will set our tags on created EBS volumes<br> labels = optional(map(string), null)<br> reclaim_policy = optional(string, "Delete")<br> volume_binding_mode = optional(string, "WaitForFirstConsumer")<br> mount_options = optional(list(string), null)<br> # Allowed topologies are poorly documented, and poorly implemented.<br> # According to the API spec https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#storageclass-v1-storage-k8s-io<br> # it should be a list of objects with a `matchLabelExpressions` key, which is a list of objects with `key` and `values` keys.<br> # However, the Terraform resource only allows a single object in a matchLabelExpressions block, not a list,<br> # the EBS driver appears to only allow a single matchLabelExpressions block, and it is entirely unclear<br> # what should happen if either of the lists has more than one element.<br> # So we simplify it here to be singletons, not lists, and allow for a future change to the resource to support lists,<br> # and a future replacement for this flattened object which can maintain backward compatibility.<br> allowed_topologies_match_label_expressions = optional(object({<br> key = optional(string, "topology.ebs.csi.aws.com/zone")<br> values = list(string)<br> }), null)<br> allow_volume_expansion = optional(bool, true)<br> # parameters, see https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/docs/parameters.md<br> parameters = object({<br> fstype = optional(string, "ext4") # "csi.storage.k8s.io/fstype"<br> type = optional(string, "gp3")<br> iopsPerGB = optional(string, null)<br> allowAutoIOPSPerGBIncrease = optional(string, null) # "true" or "false"<br> iops = optional(string, null)<br> throughput = optional(string, null)<br><br> encrypted = optional(string, "true")<br> kmsKeyId = optional(string, null) # ARN of the KMS key to use for encryption. If not specified, the default key is used.<br> blockExpress = optional(string, null) # "true" or "false"<br> blockSize = optional(string, null)<br> })<br> provisioner = optional(string, "ebs.csi.aws.com")<br><br> # TODO: support tags<br> # https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/docs/tagging.md<br> }))</pre> | `{}` | no |
| <a name="input_efs_storage_classes"></a> [efs\_storage\_classes](#input\_efs\_storage\_classes) | A map of storage class name to EFS parameters to create | <pre>map(object({<br> make_default_storage_class = optional(bool, false)<br> labels = optional(map(string), null)<br> efs_component_name = optional(string, "eks/efs")<br> reclaim_policy = optional(string, "Delete")<br> volume_binding_mode = optional(string, "Immediate")<br> # Mount options are poorly documented.<br> # TLS is now the default and need not be specified. https://github.com/kubernetes-sigs/aws-efs-csi-driver/tree/master/docs#encryption-in-transit<br> # Other options include `lookupcache` and `iam`.<br> mount_options = optional(list(string), null)<br> parameters = optional(object({<br> basePath = optional(string, "/efs_controller")<br> directoryPerms = optional(string, "700")<br> provisioningMode = optional(string, "efs-ap")<br> gidRangeStart = optional(string, null)<br> gidRangeEnd = optional(string, null)<br> # Support for cross-account EFS mounts<br> # See https://github.com/kubernetes-sigs/aws-efs-csi-driver/tree/master/examples/kubernetes/cross_account_mount<br> # and for gritty details on secrets: https://kubernetes-csi.github.io/docs/secrets-and-credentials-storage-class.html<br> az = optional(string, null)<br> provisioner-secret-name = optional(string, null) # "csi.storage.k8s.io/provisioner-secret-name"<br> provisioner-secret-namespace = optional(string, null) # "csi.storage.k8s.io/provisioner-secret-namespace"<br> }), {})<br> provisioner = optional(string, "efs.csi.aws.com")<br> }))</pre> | `{}` | no |
| <a name="input_ebs_storage_classes"></a> [ebs\_storage\_classes](#input\_ebs\_storage\_classes) | A map of storage class name to EBS parameters to create | <pre>map(object({<br> enabled = optional(bool, true)<br> make_default_storage_class = optional(bool, false)<br> include_tags = optional(bool, true) # If true, StorageClass will set our tags on created EBS volumes<br> labels = optional(map(string), null)<br> reclaim_policy = optional(string, "Delete")<br> volume_binding_mode = optional(string, "WaitForFirstConsumer")<br> mount_options = optional(list(string), null)<br> # Allowed topologies are poorly documented, and poorly implemented.<br> # According to the API spec https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#storageclass-v1-storage-k8s-io<br> # it should be a list of objects with a `matchLabelExpressions` key, which is a list of objects with `key` and `values` keys.<br> # However, the Terraform resource only allows a single object in a matchLabelExpressions block, not a list,<br> # the EBS driver appears to only allow a single matchLabelExpressions block, and it is entirely unclear<br> # what should happen if either of the lists has more than one element.<br> # So we simplify it here to be singletons, not lists, and allow for a future change to the resource to support lists,<br> # and a future replacement for this flattened object which can maintain backward compatibility.<br> allowed_topologies_match_label_expressions = optional(object({<br> key = optional(string, "topology.ebs.csi.aws.com/zone")<br> values = list(string)<br> }), null)<br> allow_volume_expansion = optional(bool, true)<br> # parameters, see https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/docs/parameters.md<br> parameters = object({<br> fstype = optional(string, "ext4") # "csi.storage.k8s.io/fstype"<br> type = optional(string, "gp3")<br> iopsPerGB = optional(string, null)<br> allowAutoIOPSPerGBIncrease = optional(string, null) # "true" or "false"<br> iops = optional(string, null)<br> throughput = optional(string, null)<br><br> encrypted = optional(string, "true")<br> kmsKeyId = optional(string, null) # ARN of the KMS key to use for encryption. If not specified, the default key is used.<br> blockExpress = optional(string, null) # "true" or "false"<br> blockSize = optional(string, null)<br> })<br> provisioner = optional(string, "ebs.csi.aws.com")<br><br> # TODO: support tags<br> # https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/docs/tagging.md<br> }))</pre> | `{}` | no |
| <a name="input_efs_storage_classes"></a> [efs\_storage\_classes](#input\_efs\_storage\_classes) | A map of storage class name to EFS parameters to create | <pre>map(object({<br> enabled = optional(bool, true)<br> make_default_storage_class = optional(bool, false)<br> labels = optional(map(string), null)<br> efs_component_name = optional(string, "eks/efs")<br> reclaim_policy = optional(string, "Delete")<br> volume_binding_mode = optional(string, "Immediate")<br> # Mount options are poorly documented.<br> # TLS is now the default and need not be specified. https://github.com/kubernetes-sigs/aws-efs-csi-driver/tree/master/docs#encryption-in-transit<br> # Other options include `lookupcache` and `iam`.<br> mount_options = optional(list(string), null)<br> parameters = optional(object({<br> basePath = optional(string, "/efs_controller")<br> directoryPerms = optional(string, "700")<br> provisioningMode = optional(string, "efs-ap")<br> gidRangeStart = optional(string, null)<br> gidRangeEnd = optional(string, null)<br> # Support for cross-account EFS mounts<br> # See https://github.com/kubernetes-sigs/aws-efs-csi-driver/tree/master/examples/kubernetes/cross_account_mount<br> # and for gritty details on secrets: https://kubernetes-csi.github.io/docs/secrets-and-credentials-storage-class.html<br> az = optional(string, null)<br> provisioner-secret-name = optional(string, null) # "csi.storage.k8s.io/provisioner-secret-name"<br> provisioner-secret-namespace = optional(string, null) # "csi.storage.k8s.io/provisioner-secret-namespace"<br> }), {})<br> provisioner = optional(string, "efs.csi.aws.com")<br> }))</pre> | `{}` | no |
| <a name="input_eks_component_name"></a> [eks\_component\_name](#input\_eks\_component\_name) | The name of the EKS component for the cluster in which to create the storage classes | `string` | `"eks/cluster"` | no |
| <a name="input_enabled"></a> [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no |
| <a name="input_environment"></a> [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
Expand Down
12 changes: 9 additions & 3 deletions modules/eks/storage-class/main.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
locals {
enabled = module.this.enabled

efs_components = local.enabled ? toset([for k, v in var.efs_storage_classes : v.efs_component_name]) : []
efs_storage_classes = {
for k, v in var.efs_storage_classes : k => v if v.enabled
}
efs_components = local.enabled ? toset([for k, v in local.efs_storage_classes : v.efs_component_name]) : []

ebs_storage_classes = {
for k, v in var.ebs_storage_classes : k => v if v.enabled
}
# In order to use `optional()`, the variable must be an object, but
# object keys must be valid identifiers and cannot be like "csi.storage.k8s.io/fstype"
# See https://github.com/hashicorp/terraform/issues/22681
Expand All @@ -24,7 +30,7 @@ locals {
}

resource "kubernetes_storage_class_v1" "ebs" {
for_each = local.enabled ? var.ebs_storage_classes : {}
for_each = local.enabled ? local.ebs_storage_classes : {}

metadata {
name = each.key
Expand Down Expand Up @@ -69,7 +75,7 @@ resource "kubernetes_storage_class_v1" "ebs" {
}

resource "kubernetes_storage_class_v1" "efs" {
for_each = local.enabled ? var.efs_storage_classes : {}
for_each = local.enabled ? local.efs_storage_classes : {}

metadata {
name = each.key
Expand Down
2 changes: 2 additions & 0 deletions modules/eks/storage-class/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ variable "eks_component_name" {

variable "ebs_storage_classes" {
type = map(object({
enabled = optional(bool, true)
make_default_storage_class = optional(bool, false)
include_tags = optional(bool, true) # If true, StorageClass will set our tags on created EBS volumes
labels = optional(map(string), null)
Expand Down Expand Up @@ -57,6 +58,7 @@ variable "ebs_storage_classes" {

variable "efs_storage_classes" {
type = map(object({
enabled = optional(bool, true)
make_default_storage_class = optional(bool, false)
labels = optional(map(string), null)
efs_component_name = optional(string, "eks/efs")
Expand Down

0 comments on commit fba6cde

Please sign in to comment.