diff --git a/.changelog/4790.txt b/.changelog/4790.txt new file mode 100644 index 0000000000..c75b24b4f9 --- /dev/null +++ b/.changelog/4790.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +container: added `network_config` block to `google_container_node_pool` resource (beta) +``` diff --git a/google-beta/resource_container_node_pool.go b/google-beta/resource_container_node_pool.go index 79d44b67f0..b228808434 100644 --- a/google-beta/resource_container_node_pool.go +++ b/google-beta/resource_container_node_pool.go @@ -212,6 +212,39 @@ var schemaNodePool = map[string]*schema.Schema{ Computed: true, Description: `The Kubernetes version for the nodes in this pool. Note that if this field and auto_upgrade are both specified, they will fight each other for what the node version should be, so setting both is highly discouraged. While a fuzzy version can be specified, it's recommended that you specify explicit versions as Terraform will see spurious diffs when fuzzy versions are used. See the google_container_engine_versions data source's version_prefix field to approximate fuzzy versions in a Terraform-compatible way.`, }, + + "network_config": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: `Networking configuration for this NodePool. If specified, it overrides the cluster-level defaults.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "create_pod_range": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Description: `Whether to create a new range for pod IPs in this node pool. Defaults are provided for pod_range and pod_ipv4_cidr_block if they are not specified.`, + }, + + "pod_range": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The ID of the secondary range for pod IPs. If create_pod_range is true, this ID is used for the new range. If create_pod_range is false, uses an existing secondary range with this ID.`, + }, + "pod_ipv4_cidr_block": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ValidateFunc: validateIpCidrRange, + Description: `The IP address range for pod IPs in this node pool. Only applicable if create_pod_range is true. Set to blank to have a range chosen with the default size. Set to /netmask (e.g. /14) to have a range chosen with a specific netmask. Set to a CIDR notation (e.g. 10.96.0.0/14) to pick a specific range to use.`, + }, + }, + }, + }, } type NodePoolInformation struct { @@ -678,6 +711,7 @@ func expandNodePool(d *schema.ResourceData, prefix string) (*containerBeta.NodeP Config: expandNodeConfig(d.Get(prefix + "node_config")), Locations: locations, Version: d.Get(prefix + "version").(string), + NetworkConfig: expandNodeNetworkConfig(d.Get(prefix + "network_config")), } if v, ok := d.GetOk(prefix + "autoscaling"); ok { @@ -766,6 +800,7 @@ func flattenNodePool(d *schema.ResourceData, config *Config, np *containerBeta.N "node_config": flattenNodeConfig(np.Config), "instance_group_urls": igmUrls, "version": np.Version, + "network_config": flattenNodeNetworkConfig(np.NetworkConfig, d, prefix), } if np.Autoscaling != nil { @@ -806,6 +841,44 @@ func flattenNodePool(d *schema.ResourceData, config *Config, np *containerBeta.N return nodePool, nil } +func flattenNodeNetworkConfig(c *containerBeta.NodeNetworkConfig, d *schema.ResourceData, prefix string) []map[string]interface{} { + result := []map[string]interface{}{} + if c != nil { + result = append(result, map[string]interface{}{ + "create_pod_range": d.Get(prefix + "network_config.0.create_pod_range"), // API doesn't return this value so we set the old one. Field is ForceNew + Required + "pod_ipv4_cidr_block": c.PodIpv4CidrBlock, + "pod_range": c.PodRange, + }) + } + return result +} + +func expandNodeNetworkConfig(v interface{}) *containerBeta.NodeNetworkConfig { + networkNodeConfigs := v.([]interface{}) + + nnc := &containerBeta.NodeNetworkConfig{} + + if len(networkNodeConfigs) == 0 { + return nnc + } + + networkNodeConfig := networkNodeConfigs[0].(map[string]interface{}) + + if v, ok := networkNodeConfig["create_pod_range"]; ok { + nnc.CreatePodRange = v.(bool) + } + + if v, ok := networkNodeConfig["pod_range"]; ok { + nnc.PodRange = v.(string) + } + + if v, ok := networkNodeConfig["pod_ipv4_cidr_block"]; ok { + nnc.PodIpv4CidrBlock = v.(string) + } + + return nnc +} + func nodePoolUpdate(d *schema.ResourceData, meta interface{}, nodePoolInfo *NodePoolInformation, prefix string, timeout time.Duration) error { config := meta.(*Config) name := d.Get(prefix + "name").(string) diff --git a/google-beta/resource_container_node_pool_test.go b/google-beta/resource_container_node_pool_test.go index a484ab750c..f1548ea7a0 100644 --- a/google-beta/resource_container_node_pool_test.go +++ b/google-beta/resource_container_node_pool_test.go @@ -380,6 +380,37 @@ func TestAccContainerNodePool_withLinuxNodeConfig(t *testing.T) { }) } +func TestAccContainerNodePool_withNetworkConfig(t *testing.T) { + t.Parallel() + + cluster := fmt.Sprintf("tf-test-cluster-%s", randString(t, 10)) + np := fmt.Sprintf("tf-test-np-%s", randString(t, 10)) + network := fmt.Sprintf("tf-test-net-%s", randString(t, 10)) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccContainerNodePool_withNetworkConfig(cluster, np, network), + }, + { + ResourceName: "google_container_node_pool.with_manual_pod_cidr", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"network_config.0.create_pod_range"}, + }, + { + ResourceName: "google_container_node_pool.with_auto_pod_cidr", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"network_config.0.create_pod_range"}, + }, + }, + }) +} + func TestAccContainerNodePool_withBootDiskKmsKey(t *testing.T) { // Uses generated time-based rotation time skipIfVcr(t) @@ -1617,6 +1648,95 @@ resource "google_container_node_pool" "with_linux_node_config" { `, cluster, np, maxBacklog, soMaxConn, tcpMem, tcpMem, twReuse) } +func testAccContainerNodePool_withNetworkConfig(cluster, np, network string) string { + return fmt.Sprintf(` +resource "google_compute_network" "container_network" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "container_subnetwork" { + name = google_compute_network.container_network.name + network = google_compute_network.container_network.name + ip_cidr_range = "10.0.36.0/24" + region = "us-central1" + private_ip_google_access = true + + secondary_ip_range { + range_name = "pod" + ip_cidr_range = "10.0.0.0/19" + } + + secondary_ip_range { + range_name = "svc" + ip_cidr_range = "10.0.32.0/22" + } + + secondary_ip_range { + range_name = "another-pod" + ip_cidr_range = "10.1.32.0/22" + } + + lifecycle { + ignore_changes = [ + # The auto nodepool creates a secondary range which diffs this resource. + secondary_ip_range, + ] + } +} + +resource "google_container_cluster" "cluster" { + name = "%s" + location = "us-central1" + initial_node_count = 1 + + network = google_compute_network.container_network.name + subnetwork = google_compute_subnetwork.container_subnetwork.name + ip_allocation_policy { + cluster_secondary_range_name = google_compute_subnetwork.container_subnetwork.secondary_ip_range[0].range_name + services_secondary_range_name = google_compute_subnetwork.container_subnetwork.secondary_ip_range[1].range_name + } + release_channel { + channel = "RAPID" + } +} + +resource "google_container_node_pool" "with_manual_pod_cidr" { + name = "%s-manual" + location = "us-central1" + cluster = google_container_cluster.cluster.name + node_count = 1 + network_config { + create_pod_range = false + pod_range = google_compute_subnetwork.container_subnetwork.secondary_ip_range[2].range_name + } + node_config { + oauth_scopes = [ + "https://www.googleapis.com/auth/cloud-platform", + ] + } +} + +resource "google_container_node_pool" "with_auto_pod_cidr" { + name = "%s-auto" + location = "us-central1" + cluster = google_container_cluster.cluster.name + node_count = 1 + network_config { + create_pod_range = true + pod_range = "auto-pod-range" + pod_ipv4_cidr_block = "10.2.0.0/20" + } + node_config { + oauth_scopes = [ + "https://www.googleapis.com/auth/cloud-platform", + ] + } +} + +`, network, cluster, np, np) +} + func testAccContainerNodePool_withBootDiskKmsKey(project, cluster, np string) string { return fmt.Sprintf(` data "google_container_engine_versions" "central1a" { diff --git a/google-beta/resource_gke_hub_feature_membership_test.go b/google-beta/resource_gke_hub_feature_membership_test.go index 9e1f2ea64d..32fa84c196 100644 --- a/google-beta/resource_gke_hub_feature_membership_test.go +++ b/google-beta/resource_gke_hub_feature_membership_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + dcl "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" gkehub "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/gkehub/beta" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" diff --git a/website/docs/r/container_cluster.html.markdown b/website/docs/r/container_cluster.html.markdown index 2b794c8415..e95b294822 100644 --- a/website/docs/r/container_cluster.html.markdown +++ b/website/docs/r/container_cluster.html.markdown @@ -235,6 +235,9 @@ region are guaranteed to support the same version. manages the default node pool, which isn't recommended to be used with Terraform. Structure is documented below. +* `network_config` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) Configuration for + [Adding Pod IP address ranges](https://cloud.google.com/kubernetes-engine/docs/how-to/multi-pod-cidr)) to the node pool. + * `node_pool` - (Optional) List of node pools associated with this cluster. See [google_container_node_pool](container_node_pool.html) for schema. **Warning:** node pools defined inside a cluster can't be changed (or added/removed) after @@ -693,6 +696,14 @@ linux_node_config { } ``` +The `network_config` block supports: + +* `create_pod_range` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) Whether to create a new range for pod IPs in this node pool. Defaults are provided for `pod_range` and `pod_ipv4_cidr_block` if they are not specified. + +* `pod_ipv4_cidr_block` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) The IP address range for pod IPs in this node pool. Only applicable if createPodRange is true. Set to blank to have a range chosen with the default size. Set to /netmask (e.g. /14) to have a range chosen with a specific netmask. Set to a CIDR notation (e.g. 10.96.0.0/14) to pick a specific range to use. + +* `pod_range` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) The ID of the secondary range for pod IPs. If `create_pod_range` is true, this ID is used for the new range. If `create_pod_range` is false, uses an existing secondary range with this ID. + The `ephemeral_storage_config` block supports: * `local_ssd_count` (Required) - Number of local SSDs to use to back ephemeral storage. Uses NVMe interfaces. Each local SSD is 375 GB in size. If zero, it means to disable using local SSDs as ephemeral storage. @@ -753,7 +764,7 @@ to private clusters, when `enable_private_nodes` is `true`. the hosted master network. This range will be used for assigning private IP addresses to the cluster master(s) and the ILB VIP. This range must not overlap with any other ranges in use within the cluster's network, and it must be a /28 -subnet. See [Private Cluster Limitations](https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters#limitations) +subnet. See [Private Cluster Limitations](https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters#req_res_lim) for more details. This field only applies to private clusters, when `enable_private_nodes` is `true`. diff --git a/website/docs/r/container_node_pool.html.markdown b/website/docs/r/container_node_pool.html.markdown index 947441d9d8..03ac7fd491 100644 --- a/website/docs/r/container_node_pool.html.markdown +++ b/website/docs/r/container_node_pool.html.markdown @@ -147,7 +147,10 @@ cluster. * `name_prefix` - (Optional) Creates a unique name for the node pool beginning with the specified prefix. Conflicts with `name`. -* `node_config` - (Optional) The node configuration of the pool. See +* `node_config` - (Optional) The network configuration of the pool. See + [google_container_cluster](container_cluster.html) for schema. + +* `network_config` - (Optional) The network configuration of the pool. See [google_container_cluster](container_cluster.html) for schema. * `node_count` - (Optional) The number of nodes per instance group. This field can be used to