From 8872d9da760888d4367de6b12b7d0bb46249bda5 Mon Sep 17 00:00:00 2001 From: Dana Hoffman Date: Mon, 20 Aug 2018 23:01:13 +0000 Subject: [PATCH] Add Policy, Attestor, and Note resources for Binary Authorization --- google/provider_binaryauthorization_gen.go | 22 + google/provider_containeranalysis_gen.go | 21 + .../resource_binaryauthorization_attestor.go | 397 +++++++++++++ ...ource_binaryauthorization_attestor_test.go | 182 ++++++ google/resource_binaryauthorization_policy.go | 556 ++++++++++++++++++ ...esource_binaryauthorization_policy_test.go | 226 +++++++ google/resource_containeranalysis_note.go | 291 +++++++++ .../resource_containeranalysis_note_test.go | 102 ++++ ...binaryauthorization_attestor.html.markdown | 158 +++++ .../binaryauthorization_policy.html.markdown | 165 ++++++ website/docs/r/compute_address.html.markdown | 1 + .../docs/r/compute_autoscaler.html.markdown | 15 +- .../r/compute_backend_bucket.html.markdown | 1 + website/docs/r/compute_disk.html.markdown | 7 +- .../r/compute_forwarding_rule.html.markdown | 1 + .../r/compute_global_address.html.markdown | 1 + .../r/compute_http_health_check.html.markdown | 1 + .../compute_https_health_check.html.markdown | 1 + .../r/compute_region_autoscaler.html.markdown | 15 +- .../docs/r/compute_region_disk.html.markdown | 5 +- website/docs/r/compute_route.html.markdown | 1 + website/docs/r/compute_router.html.markdown | 7 +- .../docs/r/compute_ssl_policy.html.markdown | 1 + .../docs/r/compute_subnetwork.html.markdown | 3 +- .../r/compute_target_http_proxy.html.markdown | 1 + .../compute_target_https_proxy.html.markdown | 1 + .../r/compute_target_ssl_proxy.html.markdown | 1 + .../r/compute_target_tcp_proxy.html.markdown | 1 + .../docs/r/compute_vpn_gateway.html.markdown | 1 + .../docs/r/compute_vpn_tunnel.html.markdown | 1 + .../r/containeranalysis_note.html.markdown | 104 ++++ website/docs/r/redis_instance.html.markdown | 1 + .../docs/r/resourcemanager_lien.html.markdown | 9 +- 33 files changed, 2276 insertions(+), 24 deletions(-) create mode 100644 google/provider_binaryauthorization_gen.go create mode 100644 google/provider_containeranalysis_gen.go create mode 100644 google/resource_binaryauthorization_attestor.go create mode 100644 google/resource_binaryauthorization_attestor_test.go create mode 100644 google/resource_binaryauthorization_policy.go create mode 100644 google/resource_binaryauthorization_policy_test.go create mode 100644 google/resource_containeranalysis_note.go create mode 100644 google/resource_containeranalysis_note_test.go create mode 100644 website/docs/r/binaryauthorization_attestor.html.markdown create mode 100644 website/docs/r/binaryauthorization_policy.html.markdown create mode 100644 website/docs/r/containeranalysis_note.html.markdown diff --git a/google/provider_binaryauthorization_gen.go b/google/provider_binaryauthorization_gen.go new file mode 100644 index 00000000000..4041d0fef74 --- /dev/null +++ b/google/provider_binaryauthorization_gen.go @@ -0,0 +1,22 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import "github.com/hashicorp/terraform/helper/schema" + +var GeneratedBinaryAuthorizationResourcesMap = map[string]*schema.Resource{ + "google_binary_authorization_attestor": resourceBinaryAuthorizationAttestor(), + "google_binary_authorization_policy": resourceBinaryAuthorizationPolicy(), +} diff --git a/google/provider_containeranalysis_gen.go b/google/provider_containeranalysis_gen.go new file mode 100644 index 00000000000..624fadbd3ac --- /dev/null +++ b/google/provider_containeranalysis_gen.go @@ -0,0 +1,21 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import "github.com/hashicorp/terraform/helper/schema" + +var GeneratedContainerAnalysisResourcesMap = map[string]*schema.Resource{ + "google_container_analysis_note": resourceContainerAnalysisNote(), +} diff --git a/google/resource_binaryauthorization_attestor.go b/google/resource_binaryauthorization_attestor.go new file mode 100644 index 00000000000..9b02f402279 --- /dev/null +++ b/google/resource_binaryauthorization_attestor.go @@ -0,0 +1,397 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "log" + "reflect" + "regexp" + + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceBinaryAuthorizationAttestor() *schema.Resource { + return &schema.Resource{ + Create: resourceBinaryAuthorizationAttestorCreate, + Read: resourceBinaryAuthorizationAttestorRead, + Update: resourceBinaryAuthorizationAttestorUpdate, + Delete: resourceBinaryAuthorizationAttestorDelete, + + Importer: &schema.ResourceImporter{ + State: resourceBinaryAuthorizationAttestorImport, + }, + + Schema: map[string]*schema.Schema{ + "attestation_authority_note": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "note_reference": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "public_keys": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ascii_armored_pgp_public_key": { + Type: schema.TypeString, + Required: true, + }, + "comment": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "delegation_service_account_email": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceBinaryAuthorizationAttestorCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandBinaryAuthorizationAttestorName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + descriptionProp, err := expandBinaryAuthorizationAttestorDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + userOwnedDrydockNoteProp, err := expandBinaryAuthorizationAttestorAttestationAuthorityNote(d.Get("attestation_authority_note"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("attestation_authority_note"); !isEmptyValue(reflect.ValueOf(userOwnedDrydockNoteProp)) && (ok || !reflect.DeepEqual(v, userOwnedDrydockNoteProp)) { + obj["userOwnedDrydockNote"] = userOwnedDrydockNoteProp + } + + url, err := replaceVars(d, config, "https://binaryauthorization.googleapis.com/v1beta1/projects/{{project}}/attestors?attestorId={{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Attestor: %#v", obj) + res, err := sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error creating Attestor: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating Attestor %q: %#v", d.Id(), res) + + return resourceBinaryAuthorizationAttestorRead(d, meta) +} + +func resourceBinaryAuthorizationAttestorRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "https://binaryauthorization.googleapis.com/v1beta1/projects/{{project}}/attestors/{{name}}") + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("BinaryAuthorizationAttestor %q", d.Id())) + } + + if err := d.Set("name", flattenBinaryAuthorizationAttestorName(res["name"])); err != nil { + return fmt.Errorf("Error reading Attestor: %s", err) + } + if err := d.Set("description", flattenBinaryAuthorizationAttestorDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading Attestor: %s", err) + } + if err := d.Set("attestation_authority_note", flattenBinaryAuthorizationAttestorAttestationAuthorityNote(res["userOwnedDrydockNote"])); err != nil { + return fmt.Errorf("Error reading Attestor: %s", err) + } + project, err := getProject(d, config) + if err != nil { + return err + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Attestor: %s", err) + } + + return nil +} + +func resourceBinaryAuthorizationAttestorUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandBinaryAuthorizationAttestorName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + descriptionProp, err := expandBinaryAuthorizationAttestorDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + userOwnedDrydockNoteProp, err := expandBinaryAuthorizationAttestorAttestationAuthorityNote(d.Get("attestation_authority_note"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("attestation_authority_note"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, userOwnedDrydockNoteProp)) { + obj["userOwnedDrydockNote"] = userOwnedDrydockNoteProp + } + + url, err := replaceVars(d, config, "https://binaryauthorization.googleapis.com/v1beta1/projects/{{project}}/attestors/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Attestor %q: %#v", d.Id(), obj) + _, err = sendRequest(config, "PUT", url, obj) + + if err != nil { + return fmt.Errorf("Error updating Attestor %q: %s", d.Id(), err) + } + + return resourceBinaryAuthorizationAttestorRead(d, meta) +} + +func resourceBinaryAuthorizationAttestorDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "https://binaryauthorization.googleapis.com/v1beta1/projects/{{project}}/attestors/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting Attestor %q", d.Id()) + res, err := sendRequest(config, "DELETE", url, obj) + if err != nil { + return handleNotFoundError(err, d, "Attestor") + } + + log.Printf("[DEBUG] Finished deleting Attestor %q: %#v", d.Id(), res) + return nil +} + +func resourceBinaryAuthorizationAttestorImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/attestors/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenBinaryAuthorizationAttestorName(v interface{}) interface{} { + if v == nil { + return v + } + return NameFromSelfLinkStateFunc(v) +} + +func flattenBinaryAuthorizationAttestorDescription(v interface{}) interface{} { + return v +} + +func flattenBinaryAuthorizationAttestorAttestationAuthorityNote(v interface{}) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + transformed := make(map[string]interface{}) + transformed["note_reference"] = + flattenBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(original["noteReference"]) + transformed["public_keys"] = + flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(original["publicKeys"]) + transformed["delegation_service_account_email"] = + flattenBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(original["delegationServiceAccountEmail"]) + return []interface{}{transformed} +} +func flattenBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(v interface{}) interface{} { + return v +} + +func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(v interface{}) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + transformed = append(transformed, map[string]interface{}{ + "comment": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(original["comment"]), + "id": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(original["id"]), + "ascii_armored_pgp_public_key": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(original["asciiArmoredPgpPublicKey"]), + }) + } + return transformed +} +func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(v interface{}) interface{} { + return v +} + +func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(v interface{}) interface{} { + return v +} + +func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(v interface{}) interface{} { + return v +} + +func flattenBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(v interface{}) interface{} { + return v +} + +func expandBinaryAuthorizationAttestorName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationAttestorDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNote(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedNoteReference, err := expandBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(original["note_reference"], d, config) + if err != nil { + return nil, err + } + transformed["noteReference"] = transformedNoteReference + transformedPublicKeys, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(original["public_keys"], d, config) + if err != nil { + return nil, err + } + transformed["publicKeys"] = transformedPublicKeys + transformedDelegationServiceAccountEmail, err := expandBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(original["delegation_service_account_email"], d, config) + if err != nil { + return nil, err + } + transformed["delegationServiceAccountEmail"] = transformedDelegationServiceAccountEmail + return transformed, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + r := regexp.MustCompile("projects/(.+)/notes/(.+)") + if r.MatchString(v.(string)) { + return v.(string), nil + } + + project, err := getProject(d, config) + if err != nil { + return nil, err + } + + return fmt.Sprintf("projects/%s/notes/%s", project, v.(string)), nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedComment, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(original["comment"], d, config) + if err != nil { + return nil, err + } + transformed["comment"] = transformedComment + transformedId, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(original["id"], d, config) + if err != nil { + return nil, err + } + transformed["id"] = transformedId + transformedAsciiArmoredPgpPublicKey, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(original["ascii_armored_pgp_public_key"], d, config) + if err != nil { + return nil, err + } + transformed["asciiArmoredPgpPublicKey"] = transformedAsciiArmoredPgpPublicKey + req = append(req, transformed) + } + return req, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google/resource_binaryauthorization_attestor_test.go b/google/resource_binaryauthorization_attestor_test.go new file mode 100644 index 00000000000..01cbde01ab2 --- /dev/null +++ b/google/resource_binaryauthorization_attestor_test.go @@ -0,0 +1,182 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccBinaryAuthorizationAttestor_basic(t *testing.T) { + t.Parallel() + + name := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckBinaryAuthorizationAttestorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccBinaryAuthorizationAttestorBasic(name), + }, + { + ResourceName: "google_binary_authorization_attestor.attestor", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccBinaryAuthorizationAttestor_full(t *testing.T) { + t.Parallel() + + name := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckBinaryAuthorizationAttestorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccBinaryAuthorizationAttestorFull(name), + }, + { + ResourceName: "google_binary_authorization_attestor.attestor", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccBinaryAuthorizationAttestor_update(t *testing.T) { + t.Parallel() + + name := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckBinaryAuthorizationAttestorDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccBinaryAuthorizationAttestorBasic(name), + }, + { + ResourceName: "google_binary_authorization_attestor.attestor", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBinaryAuthorizationAttestorFull(name), + }, + { + ResourceName: "google_binary_authorization_attestor.attestor", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBinaryAuthorizationAttestorBasic(name), + }, + { + ResourceName: "google_binary_authorization_attestor.attestor", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckBinaryAuthorizationAttestorDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_binary_authorization_attestor" { + continue + } + + project, err := getTestProject(rs.Primary, config) + if err != nil { + return err + } + + name := rs.Primary.Attributes["name"] + + url := fmt.Sprintf("https://binaryauthorization.googleapis.com/v1beta1/projects/%s/attestors/%s", project, name) + _, err = sendRequest(config, "GET", url, nil) + + if err == nil { + return fmt.Errorf("Error, attestor %s still exists", name) + } + } + + return nil +} + +func testAccBinaryAuthorizationAttestorBasic(name string) string { + return fmt.Sprintf(` +resource "google_container_analysis_note" "note" { + name = "tf-test-%s" + attestation_authority { + hint { + human_readable_name = "My Attestor" + } + } +} + +resource "google_binary_authorization_attestor" "attestor" { + name = "tf-test-%s" + attestation_authority_note { + note_reference = "${google_container_analysis_note.note.name}" + } +} +`, name, name) +} + +func testAccBinaryAuthorizationAttestorFull(name string) string { + return fmt.Sprintf(` +resource "google_container_analysis_note" "note" { + name = "tf-test-%s" + attestation_authority { + hint { + human_readable_name = "My Attestor" + } + } +} + +resource "google_binary_authorization_attestor" "attestor" { + name = "tf-test-%s" + description = "my description" + attestation_authority_note { + note_reference = "${google_container_analysis_note.note.name}" + public_keys { + ascii_armored_pgp_public_key = <[^/]+)", "(?P[^/]+)"}, d, config) + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{project}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenBinaryAuthorizationPolicyDescription(v interface{}) interface{} { + return v +} + +func flattenBinaryAuthorizationPolicyAdmissionWhitelistPatterns(v interface{}) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + transformed = append(transformed, map[string]interface{}{ + "name_pattern": flattenBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(original["namePattern"]), + }) + } + return transformed +} +func flattenBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(v interface{}) interface{} { + return v +} + +func flattenBinaryAuthorizationPolicyClusterAdmissionRules(v interface{}) interface{} { + if v == nil { + return v + } + l := v.(map[string]interface{}) + transformed := make([]interface{}, 0, len(l)) + for k, raw := range l { + original := raw.(map[string]interface{}) + transformed = append(transformed, map[string]interface{}{ + "cluster": k, + "evaluation_mode": flattenBinaryAuthorizationPolicyClusterAdmissionRulesEvaluationMode(original["evaluationMode"]), + "require_attestations_by": flattenBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(original["requireAttestationsBy"]), + "enforcement_mode": flattenBinaryAuthorizationPolicyClusterAdmissionRulesEnforcementMode(original["enforcementMode"]), + }) + } + return transformed +} +func flattenBinaryAuthorizationPolicyClusterAdmissionRulesEvaluationMode(v interface{}) interface{} { + return v +} + +func flattenBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(v interface{}) interface{} { + if v == nil { + return v + } + return schema.NewSet(selfLinkNameHash, v.([]interface{})) +} + +func flattenBinaryAuthorizationPolicyClusterAdmissionRulesEnforcementMode(v interface{}) interface{} { + return v +} + +func flattenBinaryAuthorizationPolicyDefaultAdmissionRule(v interface{}) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + transformed := make(map[string]interface{}) + transformed["evaluation_mode"] = + flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(original["evaluationMode"]) + transformed["require_attestations_by"] = + flattenBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(original["requireAttestationsBy"]) + transformed["enforcement_mode"] = + flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(original["enforcementMode"]) + return []interface{}{transformed} +} +func flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(v interface{}) interface{} { + return v +} + +func flattenBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(v interface{}) interface{} { + if v == nil { + return v + } + return schema.NewSet(selfLinkNameHash, v.([]interface{})) +} + +func flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(v interface{}) interface{} { + return v +} + +func expandBinaryAuthorizationPolicyDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationPolicyAdmissionWhitelistPatterns(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedNamePattern, err := expandBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(original["name_pattern"], d, config) + if err != nil { + return nil, err + } + transformed["namePattern"] = transformedNamePattern + req = append(req, transformed) + } + return req, nil +} + +func expandBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationPolicyClusterAdmissionRules(v interface{}, d *schema.ResourceData, config *Config) (map[string]interface{}, error) { + if v == nil { + return map[string]interface{}{}, nil + } + m := make(map[string]interface{}) + for _, raw := range v.(*schema.Set).List() { + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedEvaluationMode, err := expandBinaryAuthorizationPolicyClusterAdmissionRulesEvaluationMode(original["evaluation_mode"], d, config) + if err != nil { + return nil, err + } + transformed["evaluationMode"] = transformedEvaluationMode + transformedRequireAttestationsBy, err := expandBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(original["require_attestations_by"], d, config) + if err != nil { + return nil, err + } + transformed["requireAttestationsBy"] = transformedRequireAttestationsBy + transformedEnforcementMode, err := expandBinaryAuthorizationPolicyClusterAdmissionRulesEnforcementMode(original["enforcement_mode"], d, config) + if err != nil { + return nil, err + } + transformed["enforcementMode"] = transformedEnforcementMode + + m[original["cluster"].(string)] = transformed + } + return m, nil +} + +func expandBinaryAuthorizationPolicyClusterAdmissionRulesEvaluationMode(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + r := regexp.MustCompile("projects/(.+)/attestors/(.+)") + + // It's possible that all entries in the list will specify a project, in + // which case the user wouldn't necessarily have to specify a provider + // project. + var project string + var err error + for _, s := range v.(*schema.Set).List() { + if !r.MatchString(s.(string)) { + project, err = getProject(d, config) + if err != nil { + return []interface{}{}, err + } + break + } + } + + return convertAndMapStringArr(v.(*schema.Set).List(), func(s string) string { + if r.MatchString(s) { + return s + } + + return fmt.Sprintf("projects/%s/attestors/%s", project, s) + }), nil +} + +func expandBinaryAuthorizationPolicyClusterAdmissionRulesEnforcementMode(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationPolicyDefaultAdmissionRule(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedEvaluationMode, err := expandBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(original["evaluation_mode"], d, config) + if err != nil { + return nil, err + } + transformed["evaluationMode"] = transformedEvaluationMode + transformedRequireAttestationsBy, err := expandBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(original["require_attestations_by"], d, config) + if err != nil { + return nil, err + } + transformed["requireAttestationsBy"] = transformedRequireAttestationsBy + transformedEnforcementMode, err := expandBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(original["enforcement_mode"], d, config) + if err != nil { + return nil, err + } + transformed["enforcementMode"] = transformedEnforcementMode + return transformed, nil +} + +func expandBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + r := regexp.MustCompile("projects/(.+)/attestors/(.+)") + + // It's possible that all entries in the list will specify a project, in + // which case the user wouldn't necessarily have to specify a provider + // project. + var project string + var err error + for _, s := range v.(*schema.Set).List() { + if !r.MatchString(s.(string)) { + project, err = getProject(d, config) + if err != nil { + return []interface{}{}, err + } + break + } + } + + return convertAndMapStringArr(v.(*schema.Set).List(), func(s string) string { + if r.MatchString(s) { + return s + } + + return fmt.Sprintf("projects/%s/attestors/%s", project, s) + }), nil +} + +func expandBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google/resource_binaryauthorization_policy_test.go b/google/resource_binaryauthorization_policy_test.go new file mode 100644 index 00000000000..3547e7088cd --- /dev/null +++ b/google/resource_binaryauthorization_policy_test.go @@ -0,0 +1,226 @@ +package google + +import ( + "fmt" + "reflect" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccBinaryAuthorizationPolicy_basic(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + pid := "tf-test-" + acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccBinaryAuthorizationPolicyBasic(pid, pname, org), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + // Destroy the policy without destroying the project so we can check + // that it was restored to the default. + { + Config: testAccBinaryAuthorizationPolicyDefault(pid, pname, org), + Check: testAccCheckBinaryAuthorizationPolicyDefault(pid), + }, + }, + }) +} + +func TestAccBinaryAuthorizationPolicy_full(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + pid := "tf-test-" + acctest.RandString(10) + note := acctest.RandString(10) + attestor := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccBinaryAuthorizationPolicyFull(pid, pname, org, note, attestor), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + // Destroy the policy without destroying the project so we can check + // that it was restored to the default. + { + Config: testAccBinaryAuthorizationPolicyDefault(pid, pname, org), + Check: testAccCheckBinaryAuthorizationPolicyDefault(pid), + }, + }, + }) +} + +func TestAccBinaryAuthorizationPolicy_update(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + pid := "tf-test-" + acctest.RandString(10) + note := acctest.RandString(10) + attestor := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccBinaryAuthorizationPolicyBasic(pid, pname, org), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBinaryAuthorizationPolicyFull(pid, pname, org, note, attestor), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBinaryAuthorizationPolicyBasic(pid, pname, org), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + // Destroy the policy without destroying the project so we can check + // that it was restored to the default. + { + Config: testAccBinaryAuthorizationPolicyDefault(pid, pname, org), + Check: testAccCheckBinaryAuthorizationPolicyDefault(pid), + }, + }, + }) +} + +func testAccCheckBinaryAuthorizationPolicyDefault(pid string) resource.TestCheckFunc { + return func(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + url := fmt.Sprintf("https://binaryauthorization.googleapis.com/v1beta1/projects/%s/policy", pid) + pol, err := sendRequest(config, "GET", url, nil) + if err != nil { + return err + } + delete(pol, "updateTime") + + defaultPol := defaultBinaryAuthorizationPolicy(pid) + if !reflect.DeepEqual(pol, defaultPol) { + return fmt.Errorf("Policy for project %s was %v, expected default policy %v", pid, pol, defaultPol) + } + return nil + } +} + +func testAccBinaryAuthorizationPolicyDefault(pid, pname, org string) string { + return fmt.Sprintf(` +// Use a separate project since each project can only have one policy +resource "google_project" "project" { + project_id = "%s" + name = "%s" + org_id = "%s" +} +`, pid, pname, org) +} + +func testAccBinaryAuthorizationPolicyBasic(pid, pname, org string) string { + return fmt.Sprintf(` +// Use a separate project since each project can only have one policy +resource "google_project" "project" { + project_id = "%s" + name = "%s" + org_id = "%s" +} + +resource "google_binary_authorization_policy" "policy" { + project = "${google_project.project.project_id}" + + admission_whitelist_patterns { + name_pattern= "gcr.io/google_containers/*" + } + + default_admission_rule { + evaluation_mode = "ALWAYS_DENY" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + } +} +`, pid, pname, org) +} + +func testAccBinaryAuthorizationPolicyFull(pid, pname, org, note, attestor string) string { + return fmt.Sprintf(` +// Use a separate project since each project can only have one policy +resource "google_project" "project" { + project_id = "%s" + name = "%s" + org_id = "%s" +} + +resource "google_project_service" "binauthz" { + project = "${google_project.project.project_id}" + service = "binaryauthorization.googleapis.com" +} + +resource "google_container_analysis_note" "note" { + project = "${google_project.project.project_id}" + + name = "tf-test-%s" + attestation_authority { + hint { + human_readable_name = "My attestor" + } + } + + depends_on = ["google_project_service.binauthz"] +} + +resource "google_binary_authorization_attestor" "attestor" { + project = "${google_project.project.project_id}" + + name = "tf-test-%s" + description = "my description" + attestation_authority_note { + note_reference = "${google_container_analysis_note.note.name}" + } + + depends_on = ["google_project_service.binauthz"] +} + +resource "google_binary_authorization_policy" "policy" { + project = "${google_project.project.project_id}" + + admission_whitelist_patterns { + name_pattern= "gcr.io/google_containers/*" + } + + default_admission_rule { + evaluation_mode = "ALWAYS_ALLOW" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + } + + cluster_admission_rules { + cluster = "us-central1-a.prod-cluster" + evaluation_mode = "REQUIRE_ATTESTATION" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + require_attestations_by = ["${google_binary_authorization_attestor.attestor.name}"] + } +} +`, pid, pname, org, note, attestor) +} diff --git a/google/resource_containeranalysis_note.go b/google/resource_containeranalysis_note.go new file mode 100644 index 00000000000..e9c26de94a1 --- /dev/null +++ b/google/resource_containeranalysis_note.go @@ -0,0 +1,291 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "log" + "reflect" + "strings" + + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceContainerAnalysisNote() *schema.Resource { + return &schema.Resource{ + Create: resourceContainerAnalysisNoteCreate, + Read: resourceContainerAnalysisNoteRead, + Update: resourceContainerAnalysisNoteUpdate, + Delete: resourceContainerAnalysisNoteDelete, + + Importer: &schema.ResourceImporter{ + State: resourceContainerAnalysisNoteImport, + }, + + Schema: map[string]*schema.Schema{ + "attestation_authority": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hint": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "human_readable_name": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceContainerAnalysisNoteCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandContainerAnalysisNoteName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + attestationAuthorityProp, err := expandContainerAnalysisNoteAttestationAuthority(d.Get("attestation_authority"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("attestation_authority"); !isEmptyValue(reflect.ValueOf(attestationAuthorityProp)) && (ok || !reflect.DeepEqual(v, attestationAuthorityProp)) { + obj["attestationAuthority"] = attestationAuthorityProp + } + + url, err := replaceVars(d, config, "https://containeranalysis.googleapis.com/v1alpha1/projects/{{project}}/notes?noteId={{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Note: %#v", obj) + res, err := sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error creating Note: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating Note %q: %#v", d.Id(), res) + + return resourceContainerAnalysisNoteRead(d, meta) +} + +func resourceContainerAnalysisNoteRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "https://containeranalysis.googleapis.com/v1alpha1/projects/{{project}}/notes/{{name}}") + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ContainerAnalysisNote %q", d.Id())) + } + + if err := d.Set("name", flattenContainerAnalysisNoteName(res["name"])); err != nil { + return fmt.Errorf("Error reading Note: %s", err) + } + if err := d.Set("attestation_authority", flattenContainerAnalysisNoteAttestationAuthority(res["attestationAuthority"])); err != nil { + return fmt.Errorf("Error reading Note: %s", err) + } + project, err := getProject(d, config) + if err != nil { + return err + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Note: %s", err) + } + + return nil +} + +func resourceContainerAnalysisNoteUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandContainerAnalysisNoteName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + attestationAuthorityProp, err := expandContainerAnalysisNoteAttestationAuthority(d.Get("attestation_authority"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("attestation_authority"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, attestationAuthorityProp)) { + obj["attestationAuthority"] = attestationAuthorityProp + } + + url, err := replaceVars(d, config, "https://containeranalysis.googleapis.com/v1alpha1/projects/{{project}}/notes/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Note %q: %#v", d.Id(), obj) + updateMask := []string{} + if d.HasChange("attestation_authority.0.hint.0.human_readable_name") { + updateMask = append(updateMask, "attestationAuthority.hint.humanReadableName") + } + // updateMask is a URL parameter but not present in the schema, so replaceVars + // won't set it + url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + _, err = sendRequest(config, "PATCH", url, obj) + + if err != nil { + return fmt.Errorf("Error updating Note %q: %s", d.Id(), err) + } + + return resourceContainerAnalysisNoteRead(d, meta) +} + +func resourceContainerAnalysisNoteDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "https://containeranalysis.googleapis.com/v1alpha1/projects/{{project}}/notes/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting Note %q", d.Id()) + res, err := sendRequest(config, "DELETE", url, obj) + if err != nil { + return handleNotFoundError(err, d, "Note") + } + + log.Printf("[DEBUG] Finished deleting Note %q: %#v", d.Id(), res) + return nil +} + +func resourceContainerAnalysisNoteImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/notes/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenContainerAnalysisNoteName(v interface{}) interface{} { + if v == nil { + return v + } + return NameFromSelfLinkStateFunc(v) +} + +func flattenContainerAnalysisNoteAttestationAuthority(v interface{}) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + transformed := make(map[string]interface{}) + transformed["hint"] = + flattenContainerAnalysisNoteAttestationAuthorityHint(original["hint"]) + return []interface{}{transformed} +} +func flattenContainerAnalysisNoteAttestationAuthorityHint(v interface{}) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + transformed := make(map[string]interface{}) + transformed["human_readable_name"] = + flattenContainerAnalysisNoteAttestationAuthorityHintHumanReadableName(original["humanReadableName"]) + return []interface{}{transformed} +} +func flattenContainerAnalysisNoteAttestationAuthorityHintHumanReadableName(v interface{}) interface{} { + return v +} + +func expandContainerAnalysisNoteName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandContainerAnalysisNoteAttestationAuthority(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedHint, err := expandContainerAnalysisNoteAttestationAuthorityHint(original["hint"], d, config) + if err != nil { + return nil, err + } + transformed["hint"] = transformedHint + return transformed, nil +} + +func expandContainerAnalysisNoteAttestationAuthorityHint(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedHumanReadableName, err := expandContainerAnalysisNoteAttestationAuthorityHintHumanReadableName(original["human_readable_name"], d, config) + if err != nil { + return nil, err + } + transformed["humanReadableName"] = transformedHumanReadableName + return transformed, nil +} + +func expandContainerAnalysisNoteAttestationAuthorityHintHumanReadableName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google/resource_containeranalysis_note_test.go b/google/resource_containeranalysis_note_test.go new file mode 100644 index 00000000000..f1e18f1f0c8 --- /dev/null +++ b/google/resource_containeranalysis_note_test.go @@ -0,0 +1,102 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccContainerAnalysisNote_basic(t *testing.T) { + t.Parallel() + + name := acctest.RandString(10) + readableName := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerAnalysisNoteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccContainerAnalysisNoteBasic(name, readableName), + }, + { + ResourceName: "google_container_analysis_note.note", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccContainerAnalysisNote_update(t *testing.T) { + t.Parallel() + + name := acctest.RandString(10) + readableName := acctest.RandString(10) + readableName2 := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerAnalysisNoteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccContainerAnalysisNoteBasic(name, readableName), + }, + { + ResourceName: "google_container_analysis_note.note", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccContainerAnalysisNoteBasic(name, readableName2), + }, + { + ResourceName: "google_container_analysis_note.note", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckContainerAnalysisNoteDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_container_analysis_note" { + continue + } + + project, err := getTestProject(rs.Primary, config) + if err != nil { + return err + } + + name := rs.Primary.Attributes["name"] + + url := fmt.Sprintf("https://containeranalysis.googleapis.com/v1alpha1/projects/%s/notes/%s", project, name) + _, err = sendRequest(config, "GET", url, nil) + + if err == nil { + return fmt.Errorf("Error, container analysis note %s still exists", name) + } + } + + return nil +} + +func testAccContainerAnalysisNoteBasic(name, readableName string) string { + return fmt.Sprintf(` +resource "google_container_analysis_note" "note" { + name = "tf-test-%s" + attestation_authority { + hint { + human_readable_name = "My Attestor %s" + } + } +} +`, name, readableName) +} diff --git a/website/docs/r/binaryauthorization_attestor.html.markdown b/website/docs/r/binaryauthorization_attestor.html.markdown new file mode 100644 index 00000000000..f70c672f40c --- /dev/null +++ b/website/docs/r/binaryauthorization_attestor.html.markdown @@ -0,0 +1,158 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +layout: "google" +page_title: "Google: google_binary_authorization_attestor" +sidebar_current: "docs-google-binary-authorization-attestor" +description: |- + An attestor that attests to container image artifacts. +--- + +# google\_binary\_authorization\_attestor + +An attestor that attests to container image artifacts. + +To get more information about Attestor, see: + +* [API documentation](https://cloud.google.com/binary-authorization/docs/reference/rest/) +* How-to Guides + * [Official Documentation](https://cloud.google.com/binary-authorization/) + +## Example Usage + +```hcl +resource "google_container_analysis_note" "note" { + name = "test-attestor-note" + attestation_authority { + hint { + human_readable_name = "Attestor Note" + } + } +} + +resource "google_binary_authorization_attestor" "attestor" { + name = "test-attestor" + attestation_authority_note { + note_reference = "${google_container_analysis_note.note.name}" + public_keys { + ascii_armored_pgp_public_key = <