diff --git a/google/resource_container_cluster.go b/google/resource_container_cluster.go index 0830ea67..7e50c4df 100644 --- a/google/resource_container_cluster.go +++ b/google/resource_container_cluster.go @@ -292,6 +292,28 @@ func resourceContainerCluster() *schema.Resource { StateFunc: StoreResourceName, }, + "network_policy": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "provider": { + Type: schema.TypeString, + Default: "PROVIDER_UNSPECIFIED", + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"PROVIDER_UNSPECIFIED", "CALICO"}, false), + }, + }, + }, + }, + "node_config": schemaNodeConfig, "node_pool": { @@ -443,6 +465,10 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er cluster.Network = network } + if v, ok := d.GetOk("network_policy"); ok && len(v.([]interface{})) > 0 { + cluster.NetworkPolicy = expandNetworkPolicy(v) + } + if v, ok := d.GetOk("subnetwork"); ok { cluster.Subnetwork = v.(string) } @@ -525,6 +551,9 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro } d.Set("name", cluster.Name) + + d.Set("network_policy", flattenNetworkPolicy(cluster.NetworkPolicy)) + d.Set("zone", cluster.Zone) locations := []string{} @@ -802,6 +831,29 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er d.SetPartial("monitoring_service") } + if d.HasChange("network_policy") { + np, _ := d.GetOk("network_policy") + + req := &container.SetNetworkPolicyRequest{ + NetworkPolicy: expandNetworkPolicy(np), + } + op, err := config.clientContainer.Projects.Zones.Clusters.SetNetworkPolicy( + project, zoneName, clusterName, req).Do() + if err != nil { + return err + } + + // Wait until it's updated + waitErr := containerOperationWait(config, op, project, zoneName, "updating GKE cluster network policy", timeoutInMinutes, 2) + if waitErr != nil { + return waitErr + } + log.Printf("[INFO] Network policy for GKE cluster %s has been updated", d.Id()) + + d.SetPartial("network_policy") + + } + if n, ok := d.GetOk("node_pool.#"); ok { for i := 0; i < n.(int); i++ { if err := nodePoolUpdate(d, meta, clusterName, fmt.Sprintf("node_pool.%d.", i), timeoutInMinutes); err != nil { @@ -945,6 +997,31 @@ func expandMasterAuthorizedNetworksConfig(configured interface{}) *container.Mas return result } +func expandNetworkPolicy(configured interface{}) *container.NetworkPolicy { + result := &container.NetworkPolicy{} + if configured != nil && len(configured.([]interface{})) > 0 { + config := configured.([]interface{})[0].(map[string]interface{}) + if enabled, ok := config["enabled"]; ok && enabled.(bool) { + result.Enabled = true + if provider, ok := config["provider"]; ok { + result.Provider = provider.(string) + } + } + } + return result +} + +func flattenNetworkPolicy(c *container.NetworkPolicy) []map[string]interface{} { + result := []map[string]interface{}{} + if c != nil { + result = append(result, map[string]interface{}{ + "enabled": c.Enabled, + "provider": c.Provider, + }) + } + return result +} + func flattenClusterAddonsConfig(c *container.AddonsConfig) []map[string]interface{} { result := make(map[string]interface{}) if c.HorizontalPodAutoscaling != nil { diff --git a/google/resource_container_cluster_test.go b/google/resource_container_cluster_test.go index e064d339..6316af4d 100644 --- a/google/resource_container_cluster_test.go +++ b/google/resource_container_cluster_test.go @@ -107,6 +107,38 @@ func TestAccContainerCluster_withMasterAuth(t *testing.T) { }) } +func TestAccContainerCluster_withNetworkPolicyEnabled(t *testing.T) { + t.Parallel() + + clusterName := fmt.Sprintf("cluster-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccContainerCluster_withNetworkPolicyEnabled(clusterName), + Check: resource.ComposeTestCheckFunc( + testAccCheckContainerCluster( + "google_container_cluster.with_network_policy_enabled"), + resource.TestCheckResourceAttr("google_container_cluster.with_network_policy_enabled", + "network_policy.#", "1"), + ), + }, + { + Config: testAccContainerCluster_removeNetworkPolicy(clusterName), + Check: resource.ComposeTestCheckFunc( + testAccCheckContainerCluster( + "google_container_cluster.with_network_policy_enabled"), + resource.TestCheckNoResourceAttr("google_container_cluster.with_network_policy_enabled", + "network_policy"), + ), + }, + }, + }) +} + func TestAccContainerCluster_withMasterAuthorizedNetworksConfig(t *testing.T) { t.Parallel() @@ -678,6 +710,12 @@ func testAccCheckContainerCluster(n string) resource.TestCheckFunc { {"node_version", cluster.CurrentNodeVersion}, } + if cluster.NetworkPolicy != nil { + clusterTests = append(clusterTests, + clusterTestField{"network_policy.0.enabled", cluster.NetworkPolicy.Enabled}, + clusterTestField{"network_policy.0.provider", cluster.NetworkPolicy.Provider}, + ) + } // Remove Zone from additional_zones since that's what the resource writes in state additionalZones := []string{} for _, location := range cluster.Locations { @@ -947,6 +985,29 @@ resource "google_container_cluster" "with_master_auth" { } }`, acctest.RandString(10)) +func testAccContainerCluster_withNetworkPolicyEnabled(clusterName string) string { + return fmt.Sprintf(` +resource "google_container_cluster" "with_network_policy_enabled" { + name = "%s" + zone = "us-central1-a" + initial_node_count = 1 + + network_policy { + enabled = true + provider = "CALICO" + } +}`, clusterName) +} + +func testAccContainerCluster_removeNetworkPolicy(clusterName string) string { + return fmt.Sprintf(` +resource "google_container_cluster" "with_network_policy_enabled" { + name = "%s" + zone = "us-central1-a" + initial_node_count = 1 +}`, clusterName) +} + func testAccContainerCluster_withMasterAuthorizedNetworksConfig(clusterName string, cidrs []string) string { cidrBlocks := "" diff --git a/website/docs/r/container_cluster.html.markdown b/website/docs/r/container_cluster.html.markdown index 0ca6f91c..41719322 100644 --- a/website/docs/r/container_cluster.html.markdown +++ b/website/docs/r/container_cluster.html.markdown @@ -126,6 +126,10 @@ output "cluster_ca_certificate" { * `network` - (Optional) The name or self_link of the Google Compute Engine network to which the cluster is connected. +* `network_policy` - (Optional) Configuration options for the + [NetworkPolicy](https://kubernetes.io/docs/concepts/services-networking/networkpolicies/) + feature. Structure is documented below. + * `node_config` - (Optional) Parameters used in creating the cluster's nodes. Structure is documented below. @@ -204,6 +208,12 @@ The `master_authorized_networks_config.cidr_blocks` block supports: * `display_name` - (Optional) Field for users to identify CIDR blocks. +The `network_policy` block supports: + +* `provider` - (Optional) The selected network policy provider. Defaults to PROVIDER_UNSPECIFIED. + +* `enabled` - (Optional) Whether network policy is enabled on the cluster. Defaults to false. + The `node_config` block supports: * `disk_size_gb` - (Optional) Size of the disk attached to each node, specified