Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for ip aliasing in google_container_cluster #654

Merged
merged 4 commits into from
Nov 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions google/resource_container_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,27 @@ func resourceContainerCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},

"ip_allocation_policy": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cluster_secondary_range_name": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"services_secondary_range_name": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
},
},
},
}
}
Expand Down Expand Up @@ -473,6 +494,13 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er
cluster.NodePools = nodePools
}

if v, ok := d.GetOk("ip_allocation_policy"); ok {
cluster.IpAllocationPolicy, err = expandIPAllocationPolicy(v)
if err != nil {
return err
}
}

req := &container.CreateClusterRequest{
Cluster: cluster,
}
Expand Down Expand Up @@ -589,6 +617,12 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro
}
d.Set("node_pool", nps)

if cluster.IpAllocationPolicy != nil {
if err := d.Set("ip_allocation_policy", flattenIPAllocationPolicy(cluster.IpAllocationPolicy)); err != nil {
return err
}
}

if igUrls, err := getInstanceGroupUrlsFromManagerUrls(config, cluster.InstanceGroupUrls); err != nil {
return err
} else {
Expand Down Expand Up @@ -925,6 +959,30 @@ func expandClusterAddonsConfig(configured interface{}) *container.AddonsConfig {
return ac
}

func expandIPAllocationPolicy(configured interface{}) (*container.IPAllocationPolicy, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you accidentally got rid of the call to this function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yikes, yeah... Fixed!

ap := &container.IPAllocationPolicy{}
if len(configured.([]interface{})) > 0 {
if config, ok := configured.([]interface{})[0].(map[string]interface{}); ok {
ap.UseIpAliases = true
if v, ok := config["cluster_secondary_range_name"]; ok {
ap.ClusterSecondaryRangeName = v.(string)
}

if v, ok := config["services_secondary_range_name"]; ok {
ap.ServicesSecondaryRangeName = v.(string)
}

if ap.UseIpAliases &&
(ap.ClusterSecondaryRangeName == "" || ap.ServicesSecondaryRangeName == "") {

return nil, fmt.Errorf("clusters using IP aliases must specify secondary ranges.")
}
}
}

return ap, nil
}

func expandMasterAuthorizedNetworksConfig(configured interface{}) *container.MasterAuthorizedNetworksConfig {
result := &container.MasterAuthorizedNetworksConfig{}
if len(configured.([]interface{})) > 0 {
Expand Down Expand Up @@ -985,6 +1043,15 @@ func flattenClusterNodePools(d *schema.ResourceData, config *Config, c []*contai
return nodePools, nil
}

func flattenIPAllocationPolicy(c *container.IPAllocationPolicy) []map[string]interface{} {
return []map[string]interface{}{
{
"cluster_secondary_range_name": c.ClusterSecondaryRangeName,
"services_secondary_range_name": c.ServicesSecondaryRangeName,
},
}
}

func flattenMasterAuthorizedNetworksConfig(c *container.MasterAuthorizedNetworksConfig) []map[string]interface{} {
result := make(map[string]interface{})
if c.Enabled && len(c.CidrBlocks) > 0 {
Expand Down
111 changes: 110 additions & 1 deletion google/resource_container_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,64 @@ func TestAccContainerCluster_withMaintenanceWindow(t *testing.T) {
})
}

func TestAccContainerCluster_withIPAllocationPolicy(t *testing.T) {
t.Parallel()

cluster := 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_withIPAllocationPolicy(
cluster,
map[string]string{
"pods": "10.1.0.0/16",
"services": "10.2.0.0/20",
},
map[string]string{
"cluster_secondary_range_name": "pods",
"services_secondary_range_name": "services",
},
),
Check: resource.ComposeTestCheckFunc(
testAccCheckContainerCluster(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add checks for ip_allocation_policy into testAccCheckContainerCluster? I also wouldn't mind seeing some resource.TestCheckResourceAttrs but I won't block on those

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done and done

"google_container_cluster.with_ip_allocation_policy"),
resource.TestCheckResourceAttr("google_container_cluster.with_ip_allocation_policy",
"ip_allocation_policy.0.cluster_secondary_range_name", "pods"),
resource.TestCheckResourceAttr("google_container_cluster.with_ip_allocation_policy",
"ip_allocation_policy.0.services_secondary_range_name", "services"),
),
},
{
Config: testAccContainerCluster_withIPAllocationPolicy(
cluster,
map[string]string{
"pods": "10.1.0.0/16",
"services": "10.2.0.0/20",
},
map[string]string{},
),
ExpectError: regexp.MustCompile("clusters using IP aliases must specify secondary ranges"),
},
{
Config: testAccContainerCluster_withIPAllocationPolicy(
cluster,
map[string]string{
"pods": "10.1.0.0/16",
},
map[string]string{
"cluster_secondary_range_name": "pods",
"services_secondary_range_name": "services",
},
),
ExpectError: regexp.MustCompile("services secondary range \"pods\" not found in subnet"),
},
},
})
}

func testAccCheckContainerClusterDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)

Expand Down Expand Up @@ -709,6 +767,11 @@ func testAccCheckContainerCluster(n string) resource.TestCheckFunc {
clusterTests = append(clusterTests, clusterTestField{"maintenance_policy.0.daily_maintenance_window.0.duration", cluster.MaintenancePolicy.Window.DailyMaintenanceWindow.Duration})
}

if cluster.IpAllocationPolicy != nil && cluster.IpAllocationPolicy.UseIpAliases {
clusterTests = append(clusterTests, clusterTestField{"ip_allocation_policy.0.cluster_secondary_range_name", cluster.IpAllocationPolicy.ClusterSecondaryRangeName})
clusterTests = append(clusterTests, clusterTestField{"ip_allocation_policy.0.services_secondary_range_name", cluster.IpAllocationPolicy.ServicesSecondaryRangeName})
}

for i, np := range cluster.NodePools {
prefix := fmt.Sprintf("node_pool.%d.", i)
clusterTests = append(clusterTests, clusterTestField{prefix + "name", np.Name})
Expand Down Expand Up @@ -1472,11 +1535,57 @@ resource "google_container_cluster" "with_maintenance_window" {
name = "cluster-test-%s"
zone = "us-central1-a"
initial_node_count = 1

maintenance_policy {
daily_maintenance_window {
start_time = "%s"
}
}
}`, acctest.RandString(10), startTime)
}

func testAccContainerCluster_withIPAllocationPolicy(cluster string, ranges, policy map[string]string) string {

var secondaryRanges bytes.Buffer
for rangeName, cidr := range ranges {
secondaryRanges.WriteString(fmt.Sprintf(`
secondary_ip_range {
range_name = "%s"
ip_cidr_range = "%s"
}`, rangeName, cidr))
}

var ipAllocationPolicy bytes.Buffer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine leaving this as is, but a potential alternative would be just passing in the configuration block as a string that looked like:

  ip_allocation_policy {
    use_ip_aliases                = "true"
    cluster_secondary_range_name  = "pods"
    services_secondary_range_name = "services"
  }

for key, value := range policy {
ipAllocationPolicy.WriteString(fmt.Sprintf(`
%s = "%s"`, key, value))
}

return fmt.Sprintf(`
resource "google_compute_network" "container_network" {
name = "container-net-%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.0.0/24"
region = "us-central1"

%s
}

resource "google_container_cluster" "with_ip_allocation_policy" {
name = "%s"
zone = "us-central1-a"

network = "${google_compute_network.container_network.name}"
subnetwork = "${google_compute_subnetwork.container_subnetwork.name}"

initial_node_count = 1
ip_allocation_policy {
%s
}
}`, acctest.RandString(10), secondaryRanges.String(), cluster, ipAllocationPolicy.String())
}
22 changes: 18 additions & 4 deletions website/docs/r/container_cluster.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,14 @@ output "cluster_ca_certificate" {
* `initial_node_count` - (Optional) The number of nodes to create in this
cluster (not including the Kubernetes master). Must be set if `node_pool` is not set.

* `ip_allocation_policy` - (Optional) Configuration for cluster IP allocation. As of now, only pre-allocated subnetworks (custom type with secondary ranges) are supported.

* `logging_service` - (Optional) The logging service that the cluster should
write logs to. Available options include `logging.googleapis.com` and
`none`. Defaults to `logging.googleapis.com`

* `maintenance_policy` - (Optional) The maintenance policy to use for the cluster. Structure is
documented below.
* `maintenance_policy` - (Optional) The maintenance policy to use for the cluster. Structure is
documented below.

* `master_auth` - (Optional) The authentication information for accessing the
Kubernetes master. Structure is documented below.
Expand Down Expand Up @@ -173,7 +175,7 @@ addons_config {
The `maintenance_policy` block supports:

* `daily_maintenance_window` - (Required) Time window specified for daily maintenance operations.
Specify `start_time` in [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) format "HH:MM”,
Specify `start_time` in [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) format "HH:MM”,
where HH : \[00-23\] and MM : \[00-59\] GMT. For example:

```
Expand All @@ -184,6 +186,18 @@ maintenance_policy {
}
```

The `ip_allocation_policy` block supports:

* `cluster_secondary_range_name` - (Optional) The name of the secondary range to be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last sentence of this (and the next) are no longer applicable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

used as for the cluster CIDR block. The secondary range will be used for pod IP
addresses. This must be an existing secondary range associated with the cluster
subnetwork.

* `services_secondary_range_name` - (Optional) The name of the secondary range to be
used as for the services CIDR block. The secondary range will be used for service
ClusterIPs. This must be an existing secondary range associated with the cluster
subnetwork.

The `master_auth` block supports:

* `password` - (Required) The password to use for HTTP basic authentication when accessing
Expand Down Expand Up @@ -261,7 +275,7 @@ exported:
to the cluster.

* `maintenance_policy.0.daily_maintenance_window.0.duration` - Duration of the time window, automatically chosen to be
smallest possible in the given scenario.
smallest possible in the given scenario.
Duration will be in [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) format "PTnHnMnS".

* `master_auth.0.client_certificate` - Base64 encoded public certificate
Expand Down