feat(gke-node-pool): Add support for "registry_hosts"#2563
feat(gke-node-pool): Add support for "registry_hosts"#2563marcmillien wants to merge 5 commits intoterraform-google-modules:mainfrom
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the GKE node pool module by integrating support for Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces new functionality to configure Containerd registry hosts within GKE node pools, allowing for detailed specification of host settings, including advanced authentication via GCP Secret Manager for CA certificates and client certificates/keys. A critical issue was identified in modules/gke-node-pool/main.tf where a typo (host.value.client instead of hosts.value.client) in a for_each expression for the client dynamic block will cause a Terraform error.
This comment was marked as outdated.
This comment was marked as outdated.
There was a problem hiding this comment.
Code Review
This pull request introduces new functionality to the GKE node pool module, enabling advanced Containerd registry host configuration. This includes support for private registry access and detailed host settings, with integration for GCP Secret Manager to manage certificates. The review feedback indicates that the README.md documentation for the node_config variable is outdated and needs to be updated to reflect the newly added registry_hosts attribute.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces the capability to configure custom container registry hosts for GKE node pools, enhancing flexibility for image management. It also refactors the existing private_registry_access_config to use dynamic blocks for improved robustness. A high-severity issue was identified where the certificate_authority_domain_config block within private_registry_access_config should also be dynamic to prevent errors when it's optional but not provided.
modules/gke-node-pool/main.tf
Outdated
| certificate_authority_domain_config { | ||
| fqdns = private_registry_access_config.value.certificate_authority_domain_config.fqdns | ||
| gcp_secret_manager_certificate_config { | ||
| secret_uri = private_registry_access_config.value.certificate_authority_domain_config.gcp_secret_manager_certificate_config.secret_uri | ||
| } | ||
| } |
There was a problem hiding this comment.
The certificate_authority_domain_config block is optional within private_registry_access_config. To prevent potential errors when private_registry_access_config is enabled but certificate_authority_domain_config is not provided, this block should be created dynamically. This will make the configuration more robust and prevent unexpected failures.
dynamic "certificate_authority_domain_config" {
for_each = private_registry_access_config.value.certificate_authority_domain_config != null ? [private_registry_access_config.value.certificate_authority_domain_config] : []
content {
fqdns = certificate_authority_domain_config.value.fqdns
gcp_secret_manager_certificate_config {
secret_uri = certificate_authority_domain_config.value.gcp_secret_manager_certificate_config.secret_uri
}
}
}
There was a problem hiding this comment.
@gemini-code-assist I am going to check it, but this is not related to my changes
There was a problem hiding this comment.
You are correct that the primary focus of your changes is the addition of registry_hosts. However, the change you made to wrap private_registry_access_config in a dynamic block (lines 242-252 in main.tf in the AFTER DIFF section) makes the certificate_authority_domain_config block, which is nested inside it, susceptible to errors if private_registry_access_config is provided but certificate_authority_domain_config is not. My suggestion aims to make the certificate_authority_domain_config block also dynamic to align with this new structure and prevent potential issues, ensuring the configuration remains robust. This is a direct follow-up improvement related to the refactoring you introduced for private_registry_access_config.
Cf.: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#certificate_authority_domain_config-1 > certificate_authority_domain_config (Optional) - List of configuration objects for CA and domains. Each object identifies a certificate and its assigned domains.
cc373ae to
7a8decd
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request enhances the GKE node pool module by introducing support for containerd_config.registry_hosts and updating certificate_authority_domain_config to be a list. The review suggests adding a description for the new registry_hosts block in the README.md to improve clarity and usability for module consumers.
| | name\_prefix | Creates a unique name for the node pool beginning with the specified prefix. Conflicts with name. | `string` | `null` | no | | ||
| | network\_config | The network configuration of the pool. | <pre>object({<br> create_pod_range = optional(bool)<br> enable_private_nodes = optional(bool)<br> pod_ipv4_cidr_block = optional(string)<br> pod_range = optional(string)<br> additional_node_network_configs = optional(list(object({<br> network = string<br> subnetwork = string<br> })))<br> additional_pod_network_configs = optional(list(object({<br> subnetwork = string<br> secondary_pod_range = string<br> max_pods_per_node = number<br> })))<br> pod_cidr_overprovision_config = optional(object({<br> disabled = bool<br> }))<br> network_performance_config = optional(object({<br> total_egress_bandwidth_tier = string<br> }))<br> })</pre> | `null` | no | | ||
| | node\_config | Parameters used in creating the node pool. | <pre>object({<br> confidential_nodes = optional(object({<br> enabled = bool<br> }))<br> disk_size_gb = optional(number)<br> disk_type = optional(string)<br> enable_confidential_storage = optional(bool)<br> local_ssd_encryption_mode = optional(string)<br> ephemeral_storage_config = optional(object({<br> local_ssd_count = number<br> }))<br> ephemeral_storage_local_ssd_config = optional(object({<br> local_ssd_count = number<br> data_cache_count = optional(number)<br> }))<br> fast_socket = optional(object({<br> enabled = bool<br> }))<br> local_nvme_ssd_block_config = optional(object({<br> local_ssd_count = number<br> }))<br> logging_variant = optional(string)<br> secondary_boot_disks = optional(object({<br> disk_image = string<br> mode = optional(string)<br> }))<br> gcfs_config = optional(object({<br> enabled = bool<br> }))<br> gvnic = optional(object({<br> enabled = bool<br> }))<br> guest_accelerator = optional(object({<br> type = string<br> count = number<br> gpu_driver_installation_config = optional(object({<br> gpu_driver_version = string<br> }))<br> gpu_partition_size = optional(string)<br> gpu_sharing_config = optional(object({<br> gpu_sharing_strategy = string<br> max_shared_clients_per_gpu = number<br> }))<br> }))<br> image_type = optional(string)<br> labels = optional(map(string))<br> resource_labels = optional(map(string))<br> max_run_duration = optional(string)<br> flex_start = optional(bool)<br> local_ssd_count = optional(number)<br> machine_type = optional(string)<br> metadata = optional(map(string))<br> min_cpu_platform = optional(string)<br> oauth_scopes = optional(list(string))<br> preemptible = optional(bool)<br> reservation_affinity = optional(object({<br> consume_reservation_type = string<br> key = optional(string)<br> values = optional(list(string))<br> }))<br> spot = optional(bool)<br> sandbox_config = optional(object({<br> sandbox_type = string<br> }))<br> boot_disk_kms_key = optional(string)<br> service_account = optional(string)<br> shielded_instance_config = optional(object({<br> enable_secure_boot = optional(bool)<br> enable_integrity_monitoring = optional(bool)<br> }))<br> storage_pools = optional(list(string))<br> tags = optional(list(string))<br> resource_manager_tags = optional(map(string))<br> taint = optional(list(object({<br> key = string<br> value = string<br> effect = string<br> })))<br> workload_metadata_config = optional(object({<br> mode = optional(string)<br> }))<br> kubelet_config = optional(object({<br> cpu_manager_policy = optional(string)<br> cpu_cfs_quota = optional(bool)<br> cpu_cfs_quota_period = optional(string)<br> insecure_kubelet_readonly_port_enabled = optional(bool)<br> pod_pids_limit = optional(number)<br> container_log_max_size = optional(string)<br> container_log_max_files = optional(number)<br> image_gc_low_threshold_percent = optional(number)<br> image_gc_high_threshold_percent = optional(number)<br> image_minimum_gc_age = optional(string)<br> allowed_unsafe_sysctls = optional(list(string))<br> }))<br> linux_node_config = optional(object({<br> sysctls = optional(map(string))<br> cgroup_mode = optional(string)<br> hugepages_config = optional(object({<br> hugepage_size_2m = optional(number)<br> hugepage_size_1g = optional(number)<br> }))<br> }))<br> windows_node_config = optional(object({<br> osversion = string<br> }))<br> containerd_config = optional(object({<br> private_registry_access_config = optional(object({<br> enabled = bool<br> certificate_authority_domain_config = optional(object({<br> fqdns = list(string)<br> gcp_secret_manager_certificate_config = object({<br> secret_uri = string<br> })<br> }))<br> }))<br> }))<br> node_group = optional(string)<br> sole_tenant_config = optional(object({<br> node_affinity = optional(object({<br> key = string<br> operator = string<br> values = list(string)<br> }))<br> }))<br> })</pre> | <pre>{<br> "disk_size_gb": 100,<br> "disk_type": "pd-standard",<br> "image_type": "COS_CONTAINERD",<br> "kubelet_config": {<br> "insecure_kubelet_readonly_port_enabled": false<br> },<br> "machine_type": "e2-medium",<br> "workload_metadata_config": {<br> "mode": "GKE_METADATA"<br> }<br>}</pre> | no | | ||
| | node\_config | Parameters used in creating the node pool. | <pre>object({<br> confidential_nodes = optional(object({<br> enabled = bool<br> }))<br> disk_size_gb = optional(number)<br> disk_type = optional(string)<br> enable_confidential_storage = optional(bool)<br> local_ssd_encryption_mode = optional(string)<br> ephemeral_storage_config = optional(object({<br> local_ssd_count = number<br> }))<br> ephemeral_storage_local_ssd_config = optional(object({<br> local_ssd_count = number<br> data_cache_count = optional(number)<br> }))<br> fast_socket = optional(object({<br> enabled = bool<br> }))<br> local_nvme_ssd_block_config = optional(object({<br> local_ssd_count = number<br> }))<br> logging_variant = optional(string)<br> secondary_boot_disks = optional(object({<br> disk_image = string<br> mode = optional(string)<br> }))<br> gcfs_config = optional(object({<br> enabled = bool<br> }))<br> gvnic = optional(object({<br> enabled = bool<br> }))<br> guest_accelerator = optional(object({<br> type = string<br> count = number<br> gpu_driver_installation_config = optional(object({<br> gpu_driver_version = string<br> }))<br> gpu_partition_size = optional(string)<br> gpu_sharing_config = optional(object({<br> gpu_sharing_strategy = string<br> max_shared_clients_per_gpu = number<br> }))<br> }))<br> image_type = optional(string)<br> labels = optional(map(string))<br> resource_labels = optional(map(string))<br> max_run_duration = optional(string)<br> flex_start = optional(bool)<br> local_ssd_count = optional(number)<br> machine_type = optional(string)<br> metadata = optional(map(string))<br> min_cpu_platform = optional(string)<br> oauth_scopes = optional(list(string))<br> preemptible = optional(bool)<br> reservation_affinity = optional(object({<br> consume_reservation_type = string<br> key = optional(string)<br> values = optional(list(string))<br> }))<br> spot = optional(bool)<br> sandbox_config = optional(object({<br> sandbox_type = string<br> }))<br> boot_disk_kms_key = optional(string)<br> service_account = optional(string)<br> shielded_instance_config = optional(object({<br> enable_secure_boot = optional(bool)<br> enable_integrity_monitoring = optional(bool)<br> }))<br> storage_pools = optional(list(string))<br> tags = optional(list(string))<br> resource_manager_tags = optional(map(string))<br> taint = optional(list(object({<br> key = string<br> value = string<br> effect = string<br> })))<br> workload_metadata_config = optional(object({<br> mode = optional(string)<br> }))<br> kubelet_config = optional(object({<br> cpu_manager_policy = optional(string)<br> cpu_cfs_quota = optional(bool)<br> cpu_cfs_quota_period = optional(string)<br> insecure_kubelet_readonly_port_enabled = optional(bool)<br> pod_pids_limit = optional(number)<br> container_log_max_size = optional(string)<br> container_log_max_files = optional(number)<br> image_gc_low_threshold_percent = optional(number)<br> image_gc_high_threshold_percent = optional(number)<br> image_minimum_gc_age = optional(string)<br> allowed_unsafe_sysctls = optional(list(string))<br> }))<br> linux_node_config = optional(object({<br> sysctls = optional(map(string))<br> cgroup_mode = optional(string)<br> hugepages_config = optional(object({<br> hugepage_size_2m = optional(number)<br> hugepage_size_1g = optional(number)<br> }))<br> }))<br> windows_node_config = optional(object({<br> osversion = string<br> }))<br> containerd_config = optional(object({<br> private_registry_access_config = optional(object({<br> enabled = bool<br> certificate_authority_domain_config = optional(list(object({<br> fqdns = list(string)<br> gcp_secret_manager_certificate_config = object({<br> secret_uri = string<br> })<br> })))<br> }))<br> registry_hosts = optional(list(object({<br> server = string<br> hosts = list(object({<br> host = string<br> capabilities = optional(list(string))<br> override_path = optional(bool)<br> dial_timeout = optional(string)<br> header = optional(list(object({<br> key = string<br> value = list(string)<br> })))<br> ca = optional(list(object({<br> gcp_secret_manager_secret_uri = string<br> })))<br> client = optional(list(object({<br> cert = object({<br> gcp_secret_manager_secret_uri = string<br> })<br> key = object({<br> gcp_secret_manager_secret_uri = string<br> })<br> })))<br> }))<br> })))<br> }))<br> node_group = optional(string)<br> sole_tenant_config = optional(object({<br> node_affinity = optional(object({<br> key = string<br> operator = string<br> values = list(string)<br> }))<br> }))<br> })</pre> | <pre>{<br> "disk_size_gb": 100,<br> "disk_type": "pd-standard",<br> "image_type": "COS_CONTAINERD",<br> "kubelet_config": {<br> "insecure_kubelet_readonly_port_enabled": false<br> },<br> "machine_type": "e2-medium",<br> "workload_metadata_config": {<br> "mode": "GKE_METADATA"<br> }<br>}</pre> | no | |
There was a problem hiding this comment.
The node_config variable has been updated to include the containerd_config.registry_hosts block. While the type definition is correctly reflected, adding a brief description for registry_hosts and its purpose would greatly improve the clarity and usability of this module for consumers. This helps users understand what this new configuration option does without needing to consult external documentation.
There was a problem hiding this comment.
This is not done for other configs under node_config, I don't think this comment is relevant here, am I wrong?
apeabody
left a comment
There was a problem hiding this comment.
Thanks for the contribution @marcmillien
From the initial lint test:
Checking submodule's files generation
diff -r '--exclude=.terraform' '--exclude=.kitchen' '--exclude=.git' /workspace/modules/gke-node-pool/metadata.yaml /tmp/tmp.OaPGXUVVRT/workspace/modules/gke-node-pool/metadata.yaml
302c302
< certificate_authority_domain_config = optional(object({
---
> certificate_authority_domain_config = optional(list(object({
307c307
< }))
---
> })))
308a309,332
> registry_hosts = optional(list(object({
> server = string
> hosts = list(object({
> host = string
> capabilities = optional(list(string))
> override_path = optional(bool)
> dial_timeout = optional(string)
> header = optional(list(object({
> key = string
> value = list(string)
> })))
> ca = optional(list(object({
> gcp_secret_manager_secret_uri = string
> })))
> client = optional(list(object({
> cert = object({
> gcp_secret_manager_secret_uri = string
> })
> key = object({
> gcp_secret_manager_secret_uri = string
> })
> })))
> }))
> })))
Error: submodule's files generation has not been run, please run the
'make build' command and commit changes
Please see the contribution template section: https://github.com/terraform-google-modules/terraform-google-kubernetes-engine/blob/main/CONTRIBUTING.md#templating
|
Thanks 🤗 , I check/fix it :) |
Implements
registry_hosts.Cf.: