Skip to content

New resource/datasource: SSL Policy #1247

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

Merged
merged 22 commits into from
Mar 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7857711
Add SSL Policy to provider
nickjacques Mar 21, 2018
697f803
Add resource for SSL Policy
nickjacques Mar 21, 2018
7364017
Add documentation for SSL Policy resource
nickjacques Mar 22, 2018
e68b281
Add SSL Policy data source
nickjacques Mar 21, 2018
df7dc62
Add SSL Policy datasource docs
nickjacques Mar 22, 2018
1de363e
Add test for SSL Policy datasource
nickjacques Mar 22, 2018
a6ebbdc
Add tests for SSL Policy resource
nickjacques Mar 21, 2018
825efb9
Update SSL Policy datasource docs
nickjacques Mar 23, 2018
1b0c44c
Make full update for SSL Policy resource
nickjacques Mar 23, 2018
efe226c
SSL Policy resource test multi-attrib update
nickjacques Mar 23, 2018
9a50864
Clean up SSL Policy datasource
nickjacques Mar 23, 2018
aaf6a86
Set-ify custom_features in SSL Policy resource
nickjacques Mar 23, 2018
2ed3f53
Document description ForceNew rationale
nickjacques Mar 23, 2018
e0d6ab3
Remove refs to TLS_1_3
nickjacques Mar 26, 2018
59072b5
Update docs: plural -> singular
nickjacques Mar 26, 2018
4b2513b
Remove extraneous attrs from datasource
nickjacques Mar 26, 2018
650553a
Fix update logic for custom_features and add enabled_features
nickjacques Mar 26, 2018
d7fb0b7
Update docs to include enabled_features
nickjacques Mar 26, 2018
98d06c0
Add test for updating to/from custom_features
nickjacques Mar 26, 2018
3a9f2c3
Add TLS 1.3 bug link
nickjacques Mar 26, 2018
bd84ef4
Add import between multi-step test configs
nickjacques Mar 26, 2018
5c9ff2e
Move Profile and minTlsVersion back into sslPolicy struct
nickjacques Mar 26, 2018
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
29 changes: 29 additions & 0 deletions google/data_source_google_compute_ssl_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package google

import (
"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceGoogleComputeSslPolicy() *schema.Resource {
// Generate datasource schema from resource
dsSchema := datasourceSchemaFromResourceSchema(resourceComputeSslPolicy().Schema)

// Set 'Required' schema elements
addRequiredFieldsToSchema(dsSchema, "name")

// Set 'Optional' schema elements
addOptionalFieldsToSchema(dsSchema, "project")

return &schema.Resource{
Read: datasourceComputeSslPolicyRead,
Schema: dsSchema,
}
}

func datasourceComputeSslPolicyRead(d *schema.ResourceData, meta interface{}) error {
policyName := d.Get("name").(string)

d.SetId(policyName)

return resourceComputeSslPolicyRead(d, meta)
}
83 changes: 83 additions & 0 deletions google/data_source_google_compute_ssl_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package google

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

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

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDataSourceGoogleSslPolicy(),
Check: resource.ComposeTestCheckFunc(
testAccDataSourceGoogleSslPolicyCheck("data.google_compute_ssl_policy.ssl_policy", "google_compute_ssl_policy.foobar"),
),
},
},
})
}

func testAccDataSourceGoogleSslPolicyCheck(data_source_name string, resource_name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
ds, ok := s.RootModule().Resources[data_source_name]
if !ok {
return fmt.Errorf("root module has no resource called %s", data_source_name)
}

rs, ok := s.RootModule().Resources[resource_name]
if !ok {
return fmt.Errorf("can't find %s in state", resource_name)
}

ds_attr := ds.Primary.Attributes
rs_attr := rs.Primary.Attributes

ssl_policy_attrs_to_test := []string{
"id",
"self_link",
"name",
"description",
"min_tls_version",
"profile",
"custom_features",
}

for _, attr_to_check := range ssl_policy_attrs_to_test {
if ds_attr[attr_to_check] != rs_attr[attr_to_check] {
return fmt.Errorf(
"%s is %s; want %s",
attr_to_check,
ds_attr[attr_to_check],
rs_attr[attr_to_check],
)
}
}

return nil
}
}

func testAccDataSourceGoogleSslPolicy() string {
return fmt.Sprintf(`

resource "google_compute_ssl_policy" "foobar" {
name = "%s"
description = "my-description"
min_tls_version = "TLS_1_2"
profile = "MODERN"
}

data "google_compute_ssl_policy" "ssl_policy" {
name = "${google_compute_ssl_policy.foobar.name}"
}
`, acctest.RandomWithPrefix("test-ssl-policy"))
}
2 changes: 2 additions & 0 deletions google/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func Provider() terraform.ResourceProvider {
"google_compute_region_instance_group": dataSourceGoogleComputeRegionInstanceGroup(),
"google_compute_vpn_gateway": dataSourceGoogleComputeVpnGateway(),
"google_compute_forwarding_rule": dataSourceGoogleComputeForwardingRule(),
"google_compute_ssl_policy": dataSourceGoogleComputeSslPolicy(),
"google_container_cluster": dataSourceGoogleContainerCluster(),
"google_container_engine_versions": dataSourceGoogleContainerEngineVersions(),
"google_container_registry_repository": dataSourceGoogleContainerRepo(),
Expand Down Expand Up @@ -130,6 +131,7 @@ func Provider() terraform.ResourceProvider {
"google_compute_shared_vpc_host_project": resourceComputeSharedVpcHostProject(),
"google_compute_shared_vpc_service_project": resourceComputeSharedVpcServiceProject(),
"google_compute_ssl_certificate": resourceComputeSslCertificate(),
"google_compute_ssl_policy": resourceComputeSslPolicy(),
"google_compute_subnetwork": resourceComputeSubnetwork(),
"google_compute_target_http_proxy": resourceComputeTargetHttpProxy(),
"google_compute_target_https_proxy": resourceComputeTargetHttpsProxy(),
Expand Down
239 changes: 239 additions & 0 deletions google/resource_compute_ssl_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
package google

import (
"fmt"
"time"

"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
computeBeta "google.golang.org/api/compute/v0.beta"
)

func resourceComputeSslPolicy() *schema.Resource {
return &schema.Resource{
Create: resourceComputeSslPolicyCreate,
Read: resourceComputeSslPolicyRead,
Update: resourceComputeSslPolicyUpdate,
Delete: resourceComputeSslPolicyDelete,

Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(2 * time.Minute),
Update: schema.DefaultTimeout(2 * time.Minute),
Delete: schema.DefaultTimeout(2 * time.Minute),
},

Schema: map[string]*schema.Schema{

"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"custom_features": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},

"description": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true, // currently, the beta patch API call does not allow updating the description
},

"min_tls_version": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "TLS_1_0",
// Although compute-gen.go says that TLS_1_3 is a valid value, the API currently (26 Mar 2018)
// responds with an HTTP 200 but doesn't actually create/update the policy. Open bug for this:
// https://issuetracker.google.com/issues/76433946
ValidateFunc: validation.StringInSlice([]string{"TLS_1_0", "TLS_1_1", "TLS_1_2"}, false),
},

"profile": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "COMPATIBLE",
ValidateFunc: validation.StringInSlice([]string{"COMPATIBLE", "MODERN", "RESTRICTED", "CUSTOM"}, false),
},

"project": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},

"enabled_features": &schema.Schema{
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},

"fingerprint": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},

"self_link": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},

CustomizeDiff: func(diff *schema.ResourceDiff, v interface{}) error {
profile := diff.Get("profile")
customFeaturesCount := diff.Get("custom_features.#")

// Validate that policy configs aren't incompatible during all phases
// CUSTOM profile demands non-zero custom_features, and other profiles (i.e., not CUSTOM) demand zero custom_features
if diff.HasChange("profile") || diff.HasChange("custom_features") {
if profile.(string) == "CUSTOM" {
if customFeaturesCount.(int) == 0 {
return fmt.Errorf("Error in SSL Policy %s: the profile is set to %s but no custom_features are set.", diff.Get("name"), profile.(string))
}
} else {
if customFeaturesCount != 0 {
return fmt.Errorf("Error in SSL Policy %s: the profile is set to %s but using custom_features requires the profile to be CUSTOM.", diff.Get("name"), profile.(string))
}
}
return nil
}
return nil
},
}
}

func resourceComputeSslPolicyCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

project, err := getProject(d, config)
if err != nil {
return err
}

sslPolicy := &computeBeta.SslPolicy{
Name: d.Get("name").(string),
Description: d.Get("description").(string),
Profile: d.Get("profile").(string),
MinTlsVersion: d.Get("min_tls_version").(string),
CustomFeatures: convertStringSet(d.Get("custom_features").(*schema.Set)),
}

op, err := config.clientComputeBeta.SslPolicies.Insert(project, sslPolicy).Do()
if err != nil {
return fmt.Errorf("Error creating SSL Policy: %s", err)
}

d.SetId(sslPolicy.Name)

err = computeSharedOperationWaitTime(config.clientCompute, op, project, int(d.Timeout(schema.TimeoutCreate).Minutes()), "Creating SSL Policy")
if err != nil {
d.SetId("") // if insert fails, remove from state
return err
}

return resourceComputeSslPolicyRead(d, meta)
}

func resourceComputeSslPolicyRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

project, err := getProject(d, config)
if err != nil {
return err
}

name := d.Id()

sslPolicy, err := config.clientComputeBeta.SslPolicies.Get(project, name).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("SSL Policy %q", name))
}

d.Set("name", sslPolicy.Name)
d.Set("description", sslPolicy.Description)
d.Set("min_tls_version", sslPolicy.MinTlsVersion)
d.Set("profile", sslPolicy.Profile)
d.Set("fingerprint", sslPolicy.Fingerprint)
d.Set("project", project)
d.Set("self_link", ConvertSelfLinkToV1(sslPolicy.SelfLink))
d.Set("enabled_features", convertStringArrToInterface(sslPolicy.EnabledFeatures))
d.Set("custom_features", convertStringArrToInterface(sslPolicy.CustomFeatures))

d.SetId(sslPolicy.Name)

return nil
}

func resourceComputeSslPolicyUpdate(d *schema.ResourceData, meta interface{}) error {

config := meta.(*Config)

project, err := getProject(d, config)
if err != nil {
return err
}

name := d.Get("name").(string)

sslPolicy := &computeBeta.SslPolicy{
Fingerprint: d.Get("fingerprint").(string),
Profile: d.Get("profile").(string),
MinTlsVersion: d.Get("min_tls_version").(string),
}

if v, ok := d.Get("custom_features").(*schema.Set); ok {
if v.Len() > 0 {
sslPolicy.CustomFeatures = convertStringSet(v)
} else {
sslPolicy.NullFields = append(sslPolicy.NullFields, "CustomFeatures")
}
}

op, err := config.clientComputeBeta.SslPolicies.Patch(project, name, sslPolicy).Do()
if err != nil {
return fmt.Errorf("Error updating SSL Policy: %s", err)
}

err = computeSharedOperationWaitTime(config.clientCompute, op, project, int(d.Timeout(schema.TimeoutUpdate).Minutes()), "Updating SSL Policy")
if err != nil {
return err
}

return resourceComputeSslPolicyRead(d, meta)
}

func resourceComputeSslPolicyDelete(d *schema.ResourceData, meta interface{}) error {

config := meta.(*Config)

project, err := getProject(d, config)
if err != nil {
return err
}

name := d.Get("name").(string)

op, err := config.clientComputeBeta.SslPolicies.Delete(project, name).Do()
if err != nil {
return fmt.Errorf("Error deleting SSL Policy: %s", err)
}

err = computeSharedOperationWaitTime(config.clientCompute, op, project, int(d.Timeout(schema.TimeoutDelete).Minutes()), "Deleting Subnetwork")
if err != nil {
return err
}

d.SetId("")

return nil
}
Loading