add support for security policies in backend services (#1243)

This commit is contained in:
Dana Hoffman 2018-03-22 09:53:24 -07:00 committed by GitHub
parent fde96ca9d9
commit 790711c649
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 128 additions and 14 deletions

View File

@ -62,6 +62,10 @@ func ParseInstanceGroupFieldValue(instanceGroup string, d TerraformResourceData,
return parseZonalFieldValue("instanceGroups", instanceGroup, "project", "zone", d, config, false)
}
func ParseSecurityPolicyFieldValue(securityPolicy string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
return parseGlobalFieldValue("securityPolicies", securityPolicy, "project", d, config, true)
}
// ------------------------------------------------------------
// Base helpers used to create helpers for specific fields.
// ------------------------------------------------------------

View File

@ -6,10 +6,15 @@ import (
"fmt"
"log"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/schema"
"google.golang.org/api/compute/v1"
computeBeta "google.golang.org/api/compute/v0.beta"
compute "google.golang.org/api/compute/v1"
)
var BackendServiceBaseApiVersion = v1
var BackendServiceVersionedFeatures = []Feature{Feature{Version: v0beta, Item: "security_policy"}}
func resourceComputeBackendService() *schema.Resource {
return &schema.Resource{
Create: resourceComputeBackendServiceCreate,
@ -32,7 +37,7 @@ func resourceComputeBackendService() *schema.Resource {
"health_checks": &schema.Schema{
Type: schema.TypeSet,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
Set: selfLinkRelativePathHash,
Required: true,
MinItems: 1,
MaxItems: 1,
@ -191,6 +196,12 @@ func resourceComputeBackendService() *schema.Resource {
Removed: "region has been removed as it was never used. For internal load balancing, use google_compute_region_backend_service",
},
"security_policy": &schema.Schema{
Type: schema.TypeString,
Optional: true,
DiffSuppressFunc: compareSelfLinkOrResourceName,
},
"self_link": &schema.Schema{
Type: schema.TypeString,
Computed: true,
@ -250,10 +261,26 @@ func resourceComputeBackendServiceCreate(d *schema.ResourceData, meta interface{
return waitErr
}
if v, ok := d.GetOk("security_policy"); ok {
pol, err := ParseSecurityPolicyFieldValue(v.(string), d, config)
op, err := config.clientComputeBeta.BackendServices.SetSecurityPolicy(
project, service.Name, &computeBeta.SecurityPolicyReference{
SecurityPolicy: pol.RelativeLink(),
}).Do()
if err != nil {
return errwrap.Wrapf("Error setting Backend Service security policy: {{err}}", err)
}
waitErr := computeSharedOperationWait(config.clientCompute, op, project, "Adding Backend Service Security Policy")
if waitErr != nil {
return waitErr
}
}
return resourceComputeBackendServiceRead(d, meta)
}
func resourceComputeBackendServiceRead(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersion(d, BackendServiceBaseApiVersion, BackendServiceVersionedFeatures)
config := meta.(*Config)
project, err := getProject(d, config)
@ -261,10 +288,25 @@ func resourceComputeBackendServiceRead(d *schema.ResourceData, meta interface{})
return err
}
service, err := config.clientCompute.BackendServices.Get(
project, d.Id()).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("Backend Service %q", d.Get("name").(string)))
service := &computeBeta.BackendService{}
switch computeApiVersion {
case v1:
v1Service, err := config.clientCompute.BackendServices.Get(
project, d.Id()).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("Backend Service %q", d.Get("name").(string)))
}
err = Convert(v1Service, service)
if err != nil {
return err
}
case v0beta:
var err error
service, err = config.clientComputeBeta.BackendServices.Get(
project, d.Id()).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("Backend Service %q", d.Get("name").(string)))
}
}
d.Set("name", service.Name)
@ -284,6 +326,7 @@ func resourceComputeBackendServiceRead(d *schema.ResourceData, meta interface{})
if err := d.Set("cdn_policy", flattenCdnPolicy(service.CdnPolicy)); err != nil {
return err
}
d.Set("security_policy", service.SecurityPolicy)
return nil
}
@ -309,13 +352,29 @@ func resourceComputeBackendServiceUpdate(d *schema.ResourceData, meta interface{
return fmt.Errorf("Error updating backend service: %s", err)
}
d.SetId(service.Name)
err = computeOperationWait(config.clientCompute, op, project, "Updating Backend Service")
if err != nil {
return err
}
if d.HasChange("security_policy") {
pol, err := ParseSecurityPolicyFieldValue(d.Get("security_policy").(string), d, config)
if err != nil {
return err
}
op, err := config.clientComputeBeta.BackendServices.SetSecurityPolicy(
project, service.Name, &computeBeta.SecurityPolicyReference{
SecurityPolicy: pol.RelativeLink(),
}).Do()
if err != nil {
return err
}
waitErr := computeSharedOperationWait(config.clientCompute, op, project, "Adding Backend Service Security Policy")
if waitErr != nil {
return waitErr
}
}
return resourceComputeBackendServiceRead(d, meta)
}
@ -359,7 +418,7 @@ func expandIap(configured []interface{}) *compute.BackendServiceIAP {
return nil
}
func flattenIap(iap *compute.BackendServiceIAP) []map[string]interface{} {
func flattenIap(iap *computeBeta.BackendServiceIAP) []map[string]interface{} {
result := make([]map[string]interface{}, 0, 1)
if iap == nil || !iap.Enabled {
return result
@ -421,7 +480,7 @@ func expandBackends(configured []interface{}) ([]*compute.Backend, error) {
return backends, nil
}
func flattenBackends(backends []*compute.Backend) []map[string]interface{} {
func flattenBackends(backends []*computeBeta.Backend) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(backends))
for _, b := range backends {
@ -544,7 +603,7 @@ func expandCdnPolicy(configured []interface{}) *compute.BackendServiceCdnPolicy
}
}
func flattenCdnPolicy(pol *compute.BackendServiceCdnPolicy) []map[string]interface{} {
func flattenCdnPolicy(pol *computeBeta.BackendServiceCdnPolicy) []map[string]interface{} {
result := []map[string]interface{}{}
if pol == nil || pol.CacheKeyPolicy == nil {
return result

View File

@ -2,6 +2,7 @@ package google
import (
"fmt"
"regexp"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
@ -300,6 +301,31 @@ func TestAccComputeBackendService_withCdnPolicy(t *testing.T) {
})
}
func TestAccComputeBackendService_withSecurityPolicy(t *testing.T) {
t.Parallel()
serviceName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
checkName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
polName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var svc compute.BackendService
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeBackendServiceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeBackendService_withSecurityPolicy(serviceName, checkName, polName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeBackendServiceExists(
"google_compute_backend_service.foobar", &svc),
resource.TestMatchResourceAttr("google_compute_backend_service.foobar", "security_policy", regexp.MustCompile(polName)),
),
},
},
})
}
func testAccCheckComputeBackendServiceDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
@ -715,3 +741,25 @@ resource "google_compute_http_health_check" "zero" {
}
`, serviceName, checkName)
}
func testAccComputeBackendService_withSecurityPolicy(serviceName, checkName, polName string) string {
return fmt.Sprintf(`
resource "google_compute_backend_service" "foobar" {
name = "%s"
health_checks = ["${google_compute_http_health_check.zero.self_link}"]
security_policy = "${google_compute_security_policy.policy.self_link}"
}
resource "google_compute_http_health_check" "zero" {
name = "%s"
request_path = "/"
check_interval_sec = 1
timeout_sec = 1
}
resource "google_compute_security_policy" "policy" {
name = "%s"
description = "basic security policy"
}
`, serviceName, checkName, polName)
}

View File

@ -81,6 +81,9 @@ The following arguments are supported:
* `cdn_policy` - (Optional) Cloud CDN configuration for this BackendService. Structure is documented below.
* `connection_draining_timeout_sec` - (Optional) Time for which instance will be drained (not accept new connections,
but still work to finish started ones). Defaults to `300`.
* `description` - (Optional) The textual description for the backend service.
* `enable_cdn` - (Optional) Whether or not to enable the Cloud CDN on the backend service.
@ -94,6 +97,9 @@ The following arguments are supported:
* `protocol` - (Optional) The protocol for incoming requests. Defaults to
`HTTP`.
* `security_policy` - (Optional, [Beta](/docs/providers/google/index.html#beta-features)) Name or URI of a
[security policy](https://cloud.google.com/armor/docs/security-policy-concepts) to add to the backend service.
* `session_affinity` - (Optional) How to distribute load. Options are `NONE` (no
affinity), `CLIENT_IP` (hash of the source/dest addresses / ports), and
`GENERATED_COOKIE` (distribute load using a generated session cookie).
@ -101,9 +107,6 @@ The following arguments are supported:
* `timeout_sec` - (Optional) The number of secs to wait for a backend to respond
to a request before considering the request failed. Defaults to `30`.
* `connection_draining_timeout_sec` - (Optional) Time for which instance will be drained (not accept new connections,
but still work to finish started ones). Defaults to `300`.
The `backend` block supports:
* `group` - (Required) The name or URI of a Compute Engine instance group