diff --git a/google/logging_exclusion_billing_account.go b/google/logging_exclusion_billing_account.go new file mode 100644 index 00000000000..0c70e7e772d --- /dev/null +++ b/google/logging_exclusion_billing_account.go @@ -0,0 +1,95 @@ +package google + +import ( + "fmt" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/schema" + "google.golang.org/api/logging/v2" +) + +var BillingAccountLoggingExclusionSchema = map[string]*schema.Schema{ + "billing_account": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, +} + +type BillingAccountLoggingExclusionUpdater struct { + resourceType string + resourceId string + Config *Config +} + +func NewBillingAccountLoggingExclusionUpdater(d *schema.ResourceData, config *Config) (ResourceLoggingExclusionUpdater, error) { + billingAccount := d.Get("billing_account").(string) + + return &BillingAccountLoggingExclusionUpdater{ + resourceType: "billingAccounts", + resourceId: billingAccount, + Config: config, + }, nil +} + +func billingAccountLoggingExclusionIdParseFunc(d *schema.ResourceData, _ *Config) error { + loggingExclusionId, err := parseLoggingExclusionId(d.Id()) + if err != nil { + return err + } + + if "billingAccounts" != loggingExclusionId.resourceType { + return fmt.Errorf("Error importing logging exclusion, invalid resourceType %#v", loggingExclusionId.resourceType) + } + + d.Set("billing_account", loggingExclusionId.resourceId) + return nil +} + +func (u *BillingAccountLoggingExclusionUpdater) CreateLoggingExclusion(parent string, exclusion *logging.LogExclusion) error { + _, err := u.Config.clientLogging.BillingAccounts.Exclusions.Create(parent, exclusion).Do() + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error creating logging exclusion for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *BillingAccountLoggingExclusionUpdater) ReadLoggingExclusion(id string) (*logging.LogExclusion, error) { + exclusion, err := u.Config.clientLogging.BillingAccounts.Exclusions.Get(id).Do() + + if err != nil { + return nil, fmt.Errorf("Error retrieving logging exclusion for %s: %s", u.DescribeResource(), err) + } + + return exclusion, nil +} + +func (u *BillingAccountLoggingExclusionUpdater) UpdateLoggingExclusion(id string, exclusion *logging.LogExclusion, updateMask string) error { + _, err := u.Config.clientLogging.BillingAccounts.Exclusions.Patch(id, exclusion).UpdateMask(updateMask).Do() + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error updating logging exclusion for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *BillingAccountLoggingExclusionUpdater) DeleteLoggingExclusion(id string) error { + _, err := u.Config.clientLogging.BillingAccounts.Exclusions.Delete(id).Do() + if err != nil { + return errwrap.Wrap(fmt.Errorf("Error deleting logging exclusion for %s.", u.DescribeResource()), err) + } + + return nil +} + +func (u *BillingAccountLoggingExclusionUpdater) GetResourceType() string { + return u.resourceType +} + +func (u *BillingAccountLoggingExclusionUpdater) GetResourceId() string { + return u.resourceId +} + +func (u *BillingAccountLoggingExclusionUpdater) DescribeResource() string { + return fmt.Sprintf("%q %q", u.resourceType, u.resourceId) +} diff --git a/google/logging_exclusion_folder.go b/google/logging_exclusion_folder.go new file mode 100644 index 00000000000..1b7b51c1068 --- /dev/null +++ b/google/logging_exclusion_folder.go @@ -0,0 +1,96 @@ +package google + +import ( + "fmt" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/schema" + "google.golang.org/api/logging/v2" +) + +var FolderLoggingExclusionSchema = map[string]*schema.Schema{ + "folder": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: optionalPrefixSuppress("folders/"), + }, +} + +type FolderLoggingExclusionUpdater struct { + resourceType string + resourceId string + Config *Config +} + +func NewFolderLoggingExclusionUpdater(d *schema.ResourceData, config *Config) (ResourceLoggingExclusionUpdater, error) { + folder := parseFolderId(d.Get("folder")) + + return &FolderLoggingExclusionUpdater{ + resourceType: "folders", + resourceId: folder, + Config: config, + }, nil +} + +func folderLoggingExclusionIdParseFunc(d *schema.ResourceData, _ *Config) error { + loggingExclusionId, err := parseLoggingExclusionId(d.Id()) + if err != nil { + return err + } + + if "folders" != loggingExclusionId.resourceType { + return fmt.Errorf("Error importing logging exclusion, invalid resourceType %#v", loggingExclusionId.resourceType) + } + + d.Set("folder", loggingExclusionId.resourceId) + return nil +} + +func (u *FolderLoggingExclusionUpdater) CreateLoggingExclusion(parent string, exclusion *logging.LogExclusion) error { + _, err := u.Config.clientLogging.Folders.Exclusions.Create(parent, exclusion).Do() + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error creating logging exclusion for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *FolderLoggingExclusionUpdater) ReadLoggingExclusion(id string) (*logging.LogExclusion, error) { + exclusion, err := u.Config.clientLogging.Folders.Exclusions.Get(id).Do() + + if err != nil { + return nil, fmt.Errorf("Error retrieving logging exclusion for %s: %s", u.DescribeResource(), err) + } + + return exclusion, nil +} + +func (u *FolderLoggingExclusionUpdater) UpdateLoggingExclusion(id string, exclusion *logging.LogExclusion, updateMask string) error { + _, err := u.Config.clientLogging.Folders.Exclusions.Patch(id, exclusion).UpdateMask(updateMask).Do() + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error updating logging exclusion for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *FolderLoggingExclusionUpdater) DeleteLoggingExclusion(id string) error { + _, err := u.Config.clientLogging.Folders.Exclusions.Delete(id).Do() + if err != nil { + return errwrap.Wrap(fmt.Errorf("Error deleting logging exclusion for %s.", u.DescribeResource()), err) + } + + return nil +} + +func (u *FolderLoggingExclusionUpdater) GetResourceType() string { + return u.resourceType +} + +func (u *FolderLoggingExclusionUpdater) GetResourceId() string { + return u.resourceId +} + +func (u *FolderLoggingExclusionUpdater) DescribeResource() string { + return fmt.Sprintf("%q %q", u.resourceType, u.resourceId) +} diff --git a/google/logging_exclusion_organization.go b/google/logging_exclusion_organization.go new file mode 100644 index 00000000000..18a61499cb2 --- /dev/null +++ b/google/logging_exclusion_organization.go @@ -0,0 +1,95 @@ +package google + +import ( + "fmt" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/schema" + "google.golang.org/api/logging/v2" +) + +var OrganizationLoggingExclusionSchema = map[string]*schema.Schema{ + "org_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, +} + +type OrganizationLoggingExclusionUpdater struct { + resourceType string + resourceId string + Config *Config +} + +func NewOrganizationLoggingExclusionUpdater(d *schema.ResourceData, config *Config) (ResourceLoggingExclusionUpdater, error) { + organization := d.Get("org_id").(string) + + return &OrganizationLoggingExclusionUpdater{ + resourceType: "organizations", + resourceId: organization, + Config: config, + }, nil +} + +func organizationLoggingExclusionIdParseFunc(d *schema.ResourceData, _ *Config) error { + loggingExclusionId, err := parseLoggingExclusionId(d.Id()) + if err != nil { + return err + } + + if "organizations" != loggingExclusionId.resourceType { + return fmt.Errorf("Error importing logging exclusion, invalid resourceType %#v", loggingExclusionId.resourceType) + } + + d.Set("org_id", loggingExclusionId.resourceId) + return nil +} + +func (u *OrganizationLoggingExclusionUpdater) CreateLoggingExclusion(parent string, exclusion *logging.LogExclusion) error { + _, err := u.Config.clientLogging.Organizations.Exclusions.Create(parent, exclusion).Do() + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error creating logging exclusion for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *OrganizationLoggingExclusionUpdater) ReadLoggingExclusion(id string) (*logging.LogExclusion, error) { + exclusion, err := u.Config.clientLogging.Organizations.Exclusions.Get(id).Do() + + if err != nil { + return nil, fmt.Errorf("Error retrieving logging exclusion for %s: %s", u.DescribeResource(), err) + } + + return exclusion, nil +} + +func (u *OrganizationLoggingExclusionUpdater) UpdateLoggingExclusion(id string, exclusion *logging.LogExclusion, updateMask string) error { + _, err := u.Config.clientLogging.Organizations.Exclusions.Patch(id, exclusion).UpdateMask(updateMask).Do() + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error updating logging exclusion for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *OrganizationLoggingExclusionUpdater) DeleteLoggingExclusion(id string) error { + _, err := u.Config.clientLogging.Organizations.Exclusions.Delete(id).Do() + if err != nil { + return errwrap.Wrap(fmt.Errorf("Error deleting logging exclusion for %s.", u.DescribeResource()), err) + } + + return nil +} + +func (u *OrganizationLoggingExclusionUpdater) GetResourceType() string { + return u.resourceType +} + +func (u *OrganizationLoggingExclusionUpdater) GetResourceId() string { + return u.resourceId +} + +func (u *OrganizationLoggingExclusionUpdater) DescribeResource() string { + return fmt.Sprintf("%q %q", u.resourceType, u.resourceId) +} diff --git a/google/logging_exclusion_project.go b/google/logging_exclusion_project.go new file mode 100644 index 00000000000..eb59972b340 --- /dev/null +++ b/google/logging_exclusion_project.go @@ -0,0 +1,102 @@ +package google + +import ( + "fmt" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/schema" + "google.golang.org/api/logging/v2" +) + +var ProjectLoggingExclusionSchema = map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, +} + +type ProjectLoggingExclusionUpdater struct { + resourceType string + resourceId string + Config *Config +} + +func NewProjectLoggingExclusionUpdater(d *schema.ResourceData, config *Config) (ResourceLoggingExclusionUpdater, error) { + pid, err := getProject(d, config) + if err != nil { + return nil, err + } + + return &ProjectLoggingExclusionUpdater{ + resourceType: "projects", + resourceId: pid, + Config: config, + }, nil +} + +func projectLoggingExclusionIdParseFunc(d *schema.ResourceData, config *Config) error { + loggingExclusionId, err := parseLoggingExclusionId(d.Id()) + if err != nil { + return err + } + + if "projects" != loggingExclusionId.resourceType { + return fmt.Errorf("Error importing logging exclusion, invalid resourceType %#v", loggingExclusionId.resourceType) + } + + if config.Project != loggingExclusionId.resourceId { + d.Set("project", loggingExclusionId.resourceId) + } + + return nil +} + +func (u *ProjectLoggingExclusionUpdater) CreateLoggingExclusion(parent string, exclusion *logging.LogExclusion) error { + _, err := u.Config.clientLogging.Projects.Exclusions.Create(parent, exclusion).Do() + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error creating logging exclusion for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *ProjectLoggingExclusionUpdater) ReadLoggingExclusion(id string) (*logging.LogExclusion, error) { + exclusion, err := u.Config.clientLogging.Projects.Exclusions.Get(id).Do() + + if err != nil { + return nil, fmt.Errorf("Error retrieving logging exclusion for %s: %s", u.DescribeResource(), err) + } + + return exclusion, nil +} + +func (u *ProjectLoggingExclusionUpdater) UpdateLoggingExclusion(id string, exclusion *logging.LogExclusion, updateMask string) error { + _, err := u.Config.clientLogging.Projects.Exclusions.Patch(id, exclusion).UpdateMask(updateMask).Do() + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error updating logging exclusion for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *ProjectLoggingExclusionUpdater) DeleteLoggingExclusion(id string) error { + _, err := u.Config.clientLogging.Projects.Exclusions.Delete(id).Do() + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error deleting logging exclusion for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *ProjectLoggingExclusionUpdater) GetResourceType() string { + return u.resourceType +} + +func (u *ProjectLoggingExclusionUpdater) GetResourceId() string { + return u.resourceId +} + +func (u *ProjectLoggingExclusionUpdater) DescribeResource() string { + return fmt.Sprintf("%q %q", u.resourceType, u.resourceId) +} diff --git a/google/provider.go b/google/provider.go index 1e2e5ccc7df..3114f7fdb1f 100644 --- a/google/provider.go +++ b/google/provider.go @@ -158,9 +158,13 @@ func Provider() terraform.ResourceProvider { "google_folder_iam_policy": ResourceIamPolicyWithImport(IamFolderSchema, NewFolderIamUpdater, FolderIdParseFunc), "google_folder_organization_policy": resourceGoogleFolderOrganizationPolicy(), "google_logging_billing_account_sink": resourceLoggingBillingAccountSink(), + "google_logging_billing_account_exclusion": ResourceLoggingExclusion(BillingAccountLoggingExclusionSchema, NewBillingAccountLoggingExclusionUpdater, billingAccountLoggingExclusionIdParseFunc), "google_logging_organization_sink": resourceLoggingOrganizationSink(), + "google_logging_organization_exclusion": ResourceLoggingExclusion(OrganizationLoggingExclusionSchema, NewOrganizationLoggingExclusionUpdater, organizationLoggingExclusionIdParseFunc), "google_logging_folder_sink": resourceLoggingFolderSink(), + "google_logging_folder_exclusion": ResourceLoggingExclusion(FolderLoggingExclusionSchema, NewFolderLoggingExclusionUpdater, folderLoggingExclusionIdParseFunc), "google_logging_project_sink": resourceLoggingProjectSink(), + "google_logging_project_exclusion": ResourceLoggingExclusion(ProjectLoggingExclusionSchema, NewProjectLoggingExclusionUpdater, projectLoggingExclusionIdParseFunc), "google_kms_key_ring": resourceKmsKeyRing(), "google_kms_key_ring_iam_binding": ResourceIamBindingWithImport(IamKmsKeyRingSchema, NewKmsKeyRingIamUpdater, KeyRingIdParseFunc), "google_kms_key_ring_iam_member": ResourceIamMemberWithImport(IamKmsKeyRingSchema, NewKmsKeyRingIamUpdater, KeyRingIdParseFunc), diff --git a/google/resource_logging_billing_account_exclusion_test.go b/google/resource_logging_billing_account_exclusion_test.go new file mode 100644 index 00000000000..6ab7fe920c8 --- /dev/null +++ b/google/resource_logging_billing_account_exclusion_test.go @@ -0,0 +1,167 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "google.golang.org/api/logging/v2" +) + +func TestAccLoggingBillingAccountExclusion_basic(t *testing.T) { + t.Parallel() + + billingAccount := getTestBillingAccountFromEnv(t) + exclusionName := "tf-test-exclusion-" + acctest.RandString(10) + description := "Description " + acctest.RandString(10) + + var exclusion logging.LogExclusion + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLoggingBillingAccountExclusionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoggingBillingAccountExclusion_basic(exclusionName, description, billingAccount), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingBillingAccountExclusionExists("google_logging_billing_account_exclusion.basic", &exclusion), + testAccCheckLoggingBillingAccountExclusion(&exclusion, "google_logging_billing_account_exclusion.basic"), + ), + }, + { + ResourceName: "google_logging_billing_account_exclusion.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccLoggingBillingAccountExclusion_update(t *testing.T) { + t.Parallel() + + billingAccount := getTestBillingAccountFromEnv(t) + exclusionName := "tf-test-exclusion-" + acctest.RandString(10) + descriptionBefore := "Basic BillingAccount Logging Exclusion" + acctest.RandString(10) + descriptionAfter := "Updated Basic BillingAccount Logging Exclusion" + acctest.RandString(10) + + var exclusionBefore, exclusionAfter logging.LogExclusion + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLoggingBillingAccountExclusionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoggingBillingAccountExclusion_basic(exclusionName, descriptionBefore, billingAccount), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingBillingAccountExclusionExists("google_logging_billing_account_exclusion.basic", &exclusionBefore), + testAccCheckLoggingBillingAccountExclusion(&exclusionBefore, "google_logging_billing_account_exclusion.basic"), + ), + }, + { + Config: testAccLoggingBillingAccountExclusion_basic(exclusionName, descriptionAfter, billingAccount), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingBillingAccountExclusionExists("google_logging_billing_account_exclusion.basic", &exclusionAfter), + testAccCheckLoggingBillingAccountExclusion(&exclusionAfter, "google_logging_billing_account_exclusion.basic"), + ), + }, + { + ResourceName: "google_logging_billing_account_exclusion.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + + // Description should have changed, but Filter and Disabled should be the same + if exclusionBefore.Description == exclusionAfter.Description { + t.Errorf("Expected Description to change, but it didn't: Description = %#v", exclusionBefore.Description) + } + if exclusionBefore.Filter != exclusionAfter.Filter { + t.Errorf("Expected Filter to be the same, but it differs: before = %#v, after = %#v", + exclusionBefore.Filter, exclusionAfter.Filter) + } + if exclusionBefore.Disabled != exclusionAfter.Disabled { + t.Errorf("Expected Disabled to be the same, but it differs: before = %#v, after = %#v", + exclusionBefore.Disabled, exclusionAfter.Disabled) + } +} + +func testAccCheckLoggingBillingAccountExclusionDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_logging_billing_account_exclusion" { + continue + } + + attributes := rs.Primary.Attributes + + _, err := config.clientLogging.BillingAccounts.Exclusions.Get(attributes["id"]).Do() + if err == nil { + return fmt.Errorf("billingAccount exclusion still exists") + } + } + + return nil +} + +func testAccCheckLoggingBillingAccountExclusionExists(n string, exclusion *logging.LogExclusion) resource.TestCheckFunc { + return func(s *terraform.State) error { + attributes, err := getResourceAttributes(n, s) + if err != nil { + return err + } + config := testAccProvider.Meta().(*Config) + + si, err := config.clientLogging.BillingAccounts.Exclusions.Get(attributes["id"]).Do() + if err != nil { + return err + } + *exclusion = *si + + return nil + } +} + +func testAccCheckLoggingBillingAccountExclusion(exclusion *logging.LogExclusion, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + attributes, err := getResourceAttributes(n, s) + if err != nil { + return err + } + + if exclusion.Description != attributes["description"] { + return fmt.Errorf("mismatch on description: api has %s but client has %s", exclusion.Description, attributes["description"]) + } + + if exclusion.Filter != attributes["filter"] { + return fmt.Errorf("mismatch on filter: api has %s but client has %s", exclusion.Filter, attributes["filter"]) + } + + disabledAttribute, err := toBool(attributes["disabled"]) + if err != nil { + return err + } + if exclusion.Disabled != disabledAttribute { + return fmt.Errorf("mismatch on disabled: api has %t but client has %t", exclusion.Disabled, disabledAttribute) + } + + return nil + } +} + +func testAccLoggingBillingAccountExclusion_basic(exclusionName, description, billingAccount string) string { + return fmt.Sprintf(` +resource "google_logging_billing_account_exclusion" "basic" { + name = "%s" + billing_account = "%s" + description = "%s" + filter = "logName=\"projects/%s/logs/compute.googleapis.com%%2Factivity_log\" AND severity>=ERROR" +} +`, exclusionName, billingAccount, description, getTestProjectFromEnv()) +} diff --git a/google/resource_logging_exclusion.go b/google/resource_logging_exclusion.go new file mode 100644 index 00000000000..6298b1b5237 --- /dev/null +++ b/google/resource_logging_exclusion.go @@ -0,0 +1,265 @@ +package google + +import ( + "fmt" + "regexp" + "strings" + + "github.com/hashicorp/terraform/helper/schema" + "google.golang.org/api/logging/v2" +) + +var LoggingExclusionBaseSchema = map[string]*schema.Schema{ + "filter": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "disabled": { + Type: schema.TypeBool, + Optional: true, + }, +} + +func ResourceLoggingExclusion(parentSpecificSchema map[string]*schema.Schema, newUpdaterFunc newResourceLoggingExclusionUpdaterFunc, resourceIdParser resourceIdParserFunc) *schema.Resource { + return &schema.Resource{ + Create: resourceLoggingExclusionCreate(newUpdaterFunc), + Read: resourceLoggingExclusionRead(newUpdaterFunc), + Update: resourceLoggingExclusionUpdate(newUpdaterFunc), + Delete: resourceLoggingExclusionDelete(newUpdaterFunc), + + Importer: &schema.ResourceImporter{ + State: resourceLoggingExclusionImportState(resourceIdParser), + }, + + Schema: mergeSchemas(LoggingExclusionBaseSchema, parentSpecificSchema), + } +} + +func resourceLoggingExclusionCreate(newUpdaterFunc newResourceLoggingExclusionUpdaterFunc) schema.CreateFunc { + return func(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + updater, err := newUpdaterFunc(d, config) + if err != nil { + return err + } + + id, exclusion := expandResourceLoggingExclusion(d, updater.GetResourceType(), updater.GetResourceId()) + + err = updater.CreateLoggingExclusion(id.parent(), exclusion) + if err != nil { + return err + } + + d.SetId(id.canonicalId()) + + return resourceLoggingExclusionRead(newUpdaterFunc)(d, meta) + } +} + +func resourceLoggingExclusionRead(newUpdaterFunc newResourceLoggingExclusionUpdaterFunc) schema.ReadFunc { + return func(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + updater, err := newUpdaterFunc(d, config) + if err != nil { + return err + } + + exclusion, err := updater.ReadLoggingExclusion(d.Id()) + + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("Logging Exclusion %s", d.Get("name").(string))) + } + + flattenResourceLoggingExclusion(d, exclusion) + + if updater.GetResourceType() == "projects" { + d.Set("project", updater.GetResourceId()) + } + + return nil + } +} + +func resourceLoggingExclusionUpdate(newUpdaterFunc newResourceLoggingExclusionUpdaterFunc) schema.UpdateFunc { + return func(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + updater, err := newUpdaterFunc(d, config) + if err != nil { + return err + } + + exclusion, updateMask := expandResourceLoggingExclusionForUpdate(d) + + err = updater.UpdateLoggingExclusion(d.Id(), exclusion, updateMask) + if err != nil { + return err + } + + return resourceLoggingExclusionRead(newUpdaterFunc)(d, meta) + } +} + +func resourceLoggingExclusionDelete(newUpdaterFunc newResourceLoggingExclusionUpdaterFunc) schema.DeleteFunc { + return func(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + updater, err := newUpdaterFunc(d, config) + if err != nil { + return err + } + + err = updater.DeleteLoggingExclusion(d.Id()) + if err != nil { + return err + } + + d.SetId("") + return nil + } +} + +func resourceLoggingExclusionImportState(resourceIdParser resourceIdParserFunc) schema.StateFunc { + return func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + err := resourceIdParser(d, config) + if err != nil { + return nil, err + } + return []*schema.ResourceData{d}, nil + } +} + +func expandResourceLoggingExclusion(d *schema.ResourceData, resourceType, resourceId string) (LoggingExclusionId, *logging.LogExclusion) { + id := LoggingExclusionId{ + resourceType: resourceType, + resourceId: resourceId, + name: d.Get("name").(string), + } + + exclusion := logging.LogExclusion{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + Filter: d.Get("filter").(string), + Disabled: d.Get("disabled").(bool), + } + return id, &exclusion +} + +func flattenResourceLoggingExclusion(d *schema.ResourceData, exclusion *logging.LogExclusion) { + d.Set("name", exclusion.Name) + d.Set("description", exclusion.Description) + d.Set("filter", exclusion.Filter) + d.Set("disabled", exclusion.Disabled) +} + +func expandResourceLoggingExclusionForUpdate(d *schema.ResourceData) (*logging.LogExclusion, string) { + // Can update description/filter/disabled right now. + exclusion := logging.LogExclusion{} + + var updateMaskArr []string + + if d.HasChange("description") { + exclusion.Description = d.Get("description").(string) + exclusion.ForceSendFields = append(exclusion.ForceSendFields, "Description") + updateMaskArr = append(updateMaskArr, "description") + } + + if d.HasChange("filter") { + exclusion.Filter = d.Get("filter").(string) + exclusion.ForceSendFields = append(exclusion.ForceSendFields, "Filter") + updateMaskArr = append(updateMaskArr, "filter") + } + + if d.HasChange("disabled") { + exclusion.Disabled = d.Get("disabled").(bool) + exclusion.ForceSendFields = append(exclusion.ForceSendFields, "Disabled") + updateMaskArr = append(updateMaskArr, "disabled") + } + + updateMask := strings.Join(updateMaskArr, ",") + return &exclusion, updateMask +} + +// The ResourceLoggingExclusionUpdater interface is implemented for each GCP +// resource supporting log exclusions. +// +// Implementations should keep track of the resource identifier. +type ResourceLoggingExclusionUpdater interface { + CreateLoggingExclusion(parent string, exclusion *logging.LogExclusion) error + ReadLoggingExclusion(id string) (*logging.LogExclusion, error) + UpdateLoggingExclusion(id string, exclusion *logging.LogExclusion, updateMask string) error + DeleteLoggingExclusion(id string) error + + GetResourceType() string + + // Returns the unique resource identifier. + GetResourceId() string + + // Textual description of this resource to be used in error message. + // The description should include the unique resource identifier. + DescribeResource() string +} + +type newResourceLoggingExclusionUpdaterFunc func(d *schema.ResourceData, config *Config) (ResourceLoggingExclusionUpdater, error) + +// loggingExclusionResourceTypes contains all the possible Stackdriver Logging resource types. Used to parse ids safely. +var loggingExclusionResourceTypes = []string{ + "billingAccounts", + "folders", + "organizations", + "projects", +} + +// LoggingExclusionId represents the parts that make up the canonical id used within terraform for a logging resource. +type LoggingExclusionId struct { + resourceType string + resourceId string + name string +} + +// loggingExclusionIdRegex matches valid logging exclusion canonical ids +var loggingExclusionIdRegex = regexp.MustCompile("(.+)/(.+)/exclusions/(.+)") + +// canonicalId returns the LoggingExclusionId as the canonical id used within terraform. +func (l LoggingExclusionId) canonicalId() string { + return fmt.Sprintf("%s/%s/exclusions/%s", l.resourceType, l.resourceId, l.name) +} + +// parent returns the "parent-level" resource that the exclusion is in (e.g. `folders/foo` for id `folders/foo/exclusions/bar`) +func (l LoggingExclusionId) parent() string { + return fmt.Sprintf("%s/%s", l.resourceType, l.resourceId) +} + +// parseLoggingExclusionId parses a canonical id into a LoggingExclusionId, or returns an error on failure. +func parseLoggingExclusionId(id string) (*LoggingExclusionId, error) { + parts := loggingExclusionIdRegex.FindStringSubmatch(id) + if parts == nil { + return nil, fmt.Errorf("unable to parse logging exclusion id %#v", id) + } + // If our resourceType is not a valid logging exclusion resource type, complain loudly + validLoggingExclusionResourceType := false + for _, v := range loggingExclusionResourceTypes { + if v == parts[1] { + validLoggingExclusionResourceType = true + break + } + } + + if !validLoggingExclusionResourceType { + return nil, fmt.Errorf("Logging resource type %s is not valid. Valid resource types: %#v", parts[1], + loggingExclusionResourceTypes) + } + return &LoggingExclusionId{ + resourceType: parts[1], + resourceId: parts[2], + name: parts[3], + }, nil +} diff --git a/google/resource_logging_folder_exclusion_test.go b/google/resource_logging_folder_exclusion_test.go new file mode 100644 index 00000000000..4517876bf25 --- /dev/null +++ b/google/resource_logging_folder_exclusion_test.go @@ -0,0 +1,240 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "google.golang.org/api/logging/v2" +) + +func TestAccLoggingFolderExclusion_basic(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + exclusionName := "tf-test-exclusion-" + acctest.RandString(10) + folderName := "tf-test-folder-" + acctest.RandString(10) + description := "Description " + acctest.RandString(10) + + var exclusion logging.LogExclusion + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLoggingFolderExclusionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoggingFolderExclusion_basic(exclusionName, description, folderName, "organizations/"+org), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingFolderExclusionExists("google_logging_folder_exclusion.basic", &exclusion), + testAccCheckLoggingFolderExclusion(&exclusion, "google_logging_folder_exclusion.basic"), + ), + }, + { + ResourceName: "google_logging_folder_exclusion.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccLoggingFolderExclusion_folderAcceptsFullFolderPath(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + exclusionName := "tf-test-exclusion-" + acctest.RandString(10) + folderName := "tf-test-folder-" + acctest.RandString(10) + description := "Description " + acctest.RandString(10) + + var exclusion logging.LogExclusion + + checkFn := func(s []*terraform.InstanceState) error { + loggingExclusionId, err := parseLoggingExclusionId(s[0].ID) + if err != nil { + return err + } + + folderAttribute := s[0].Attributes["folder"] + if loggingExclusionId.resourceId != folderAttribute { + return fmt.Errorf("imported folder id does not match: actual = %#v expected = %#v", folderAttribute, loggingExclusionId.resourceId) + } + + return nil + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLoggingFolderExclusionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoggingFolderExclusion_withFullFolderPath(exclusionName, description, folderName, "organizations/"+org), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingFolderExclusionExists("google_logging_folder_exclusion.full-folder", &exclusion), + testAccCheckLoggingFolderExclusion(&exclusion, "google_logging_folder_exclusion.full-folder"), + ), + }, + { + ResourceName: "google_logging_folder_exclusion.full-folder", + ImportState: true, + ImportStateVerify: true, + // We support both notations: folder/[FOLDER_ID] and plain [FOLDER_ID] however the + // importer will always use the plain [FOLDER_ID] notation which will differ from + // the schema if the schema has used the prefixed notation. We have to check this in + // a checkFn instead. + ImportStateVerifyIgnore: []string{"folder"}, + ImportStateCheck: checkFn, + }, + }, + }) +} + +func TestAccLoggingFolderExclusion_update(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + exclusionName := "tf-test-exclusion-" + acctest.RandString(10) + folderName := "tf-test-folder-" + acctest.RandString(10) + parent := "organizations/" + org + descriptionBefore := "Basic Folder Logging Exclusion" + acctest.RandString(10) + descriptionAfter := "Updated Basic Folder Logging Exclusion" + acctest.RandString(10) + + var exclusionBefore, exclusionAfter logging.LogExclusion + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLoggingFolderExclusionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoggingFolderExclusion_basic(exclusionName, descriptionBefore, folderName, parent), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingFolderExclusionExists("google_logging_folder_exclusion.basic", &exclusionBefore), + testAccCheckLoggingFolderExclusion(&exclusionBefore, "google_logging_folder_exclusion.basic"), + ), + }, + { + Config: testAccLoggingFolderExclusion_basic(exclusionName, descriptionAfter, folderName, parent), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingFolderExclusionExists("google_logging_folder_exclusion.basic", &exclusionAfter), + testAccCheckLoggingFolderExclusion(&exclusionAfter, "google_logging_folder_exclusion.basic"), + ), + }, + { + ResourceName: "google_logging_folder_exclusion.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + + // Description should have changed, but Filter and Disabled should be the same + if exclusionBefore.Description == exclusionAfter.Description { + t.Errorf("Expected Description to change, but it didn't: Description = %#v", exclusionBefore.Description) + } + if exclusionBefore.Filter != exclusionAfter.Filter { + t.Errorf("Expected Filter to be the same, but it differs: before = %#v, after = %#v", + exclusionBefore.Filter, exclusionAfter.Filter) + } + if exclusionBefore.Disabled != exclusionAfter.Disabled { + t.Errorf("Expected Disabled to be the same, but it differs: before = %#v, after = %#v", + exclusionBefore.Disabled, exclusionAfter.Disabled) + } +} + +func testAccCheckLoggingFolderExclusionDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_logging_folder_exclusion" { + continue + } + + attributes := rs.Primary.Attributes + + _, err := config.clientLogging.Folders.Exclusions.Get(attributes["id"]).Do() + if err == nil { + return fmt.Errorf("folder exclusion still exists") + } + } + + return nil +} + +func testAccCheckLoggingFolderExclusionExists(n string, exclusion *logging.LogExclusion) resource.TestCheckFunc { + return func(s *terraform.State) error { + attributes, err := getResourceAttributes(n, s) + if err != nil { + return err + } + config := testAccProvider.Meta().(*Config) + + si, err := config.clientLogging.Folders.Exclusions.Get(attributes["id"]).Do() + if err != nil { + return err + } + *exclusion = *si + + return nil + } +} + +func testAccCheckLoggingFolderExclusion(exclusion *logging.LogExclusion, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + attributes, err := getResourceAttributes(n, s) + if err != nil { + return err + } + + if exclusion.Description != attributes["description"] { + return fmt.Errorf("mismatch on description: api has %s but client has %s", exclusion.Description, attributes["description"]) + } + + if exclusion.Filter != attributes["filter"] { + return fmt.Errorf("mismatch on filter: api has %s but client has %s", exclusion.Filter, attributes["filter"]) + } + + disabledAttribute, err := toBool(attributes["disabled"]) + if err != nil { + return err + } + if exclusion.Disabled != disabledAttribute { + return fmt.Errorf("mismatch on disabled: api has %t but client has %t", exclusion.Disabled, disabledAttribute) + } + + return nil + } +} + +func testAccLoggingFolderExclusion_basic(exclusionName, description, folderName, folderParent string) string { + return fmt.Sprintf(` +resource "google_logging_folder_exclusion" "basic" { + name = "%s" + folder = "${element(split("/", google_folder.my-folder.name), 1)}" + description = "%s" + filter = "logName=\"projects/%s/logs/compute.googleapis.com%%2Factivity_log\" AND severity>=ERROR" +} + +resource "google_folder" "my-folder" { + display_name = "%s" + parent = "%s" +}`, exclusionName, description, getTestProjectFromEnv(), folderName, folderParent) +} + +func testAccLoggingFolderExclusion_withFullFolderPath(exclusionName, description, folderName, folderParent string) string { + return fmt.Sprintf(` +resource "google_logging_folder_exclusion" "full-folder" { + name = "%s" + folder = "${google_folder.my-folder.name}" + description = "%s" + filter = "logName=\"projects/%s/logs/compute.googleapis.com%%2Factivity_log\" AND severity>=ERROR" +} + +resource "google_folder" "my-folder" { + display_name = "%s" + parent = "%s" +}`, exclusionName, description, getTestProjectFromEnv(), folderName, folderParent) +} diff --git a/google/resource_logging_organization_exclusion_test.go b/google/resource_logging_organization_exclusion_test.go new file mode 100644 index 00000000000..ff3e168957c --- /dev/null +++ b/google/resource_logging_organization_exclusion_test.go @@ -0,0 +1,167 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "google.golang.org/api/logging/v2" +) + +func TestAccLoggingOrganizationExclusion_basic(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + exclusionName := "tf-test-exclusion-" + acctest.RandString(10) + description := "Description " + acctest.RandString(10) + + var exclusion logging.LogExclusion + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLoggingOrganizationExclusionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoggingOrganizationExclusion_basic(exclusionName, description, org), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingOrganizationExclusionExists("google_logging_organization_exclusion.basic", &exclusion), + testAccCheckLoggingOrganizationExclusion(&exclusion, "google_logging_organization_exclusion.basic"), + ), + }, + { + ResourceName: "google_logging_organization_exclusion.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccLoggingOrganizationExclusion_update(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + exclusionName := "tf-test-exclusion-" + acctest.RandString(10) + descriptionBefore := "Basic Organization Logging Exclusion" + acctest.RandString(10) + descriptionAfter := "Updated Basic Organization Logging Exclusion" + acctest.RandString(10) + + var exclusionBefore, exclusionAfter logging.LogExclusion + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLoggingOrganizationExclusionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoggingOrganizationExclusion_basic(exclusionName, descriptionBefore, org), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingOrganizationExclusionExists("google_logging_organization_exclusion.basic", &exclusionBefore), + testAccCheckLoggingOrganizationExclusion(&exclusionBefore, "google_logging_organization_exclusion.basic"), + ), + }, + { + Config: testAccLoggingOrganizationExclusion_basic(exclusionName, descriptionAfter, org), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingOrganizationExclusionExists("google_logging_organization_exclusion.basic", &exclusionAfter), + testAccCheckLoggingOrganizationExclusion(&exclusionAfter, "google_logging_organization_exclusion.basic"), + ), + }, + { + ResourceName: "google_logging_organization_exclusion.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + + // Description should have changed, but Filter and Disabled should be the same + if exclusionBefore.Description == exclusionAfter.Description { + t.Errorf("Expected Description to change, but it didn't: Description = %#v", exclusionBefore.Description) + } + if exclusionBefore.Filter != exclusionAfter.Filter { + t.Errorf("Expected Filter to be the same, but it differs: before = %#v, after = %#v", + exclusionBefore.Filter, exclusionAfter.Filter) + } + if exclusionBefore.Disabled != exclusionAfter.Disabled { + t.Errorf("Expected Disabled to be the same, but it differs: before = %#v, after = %#v", + exclusionBefore.Disabled, exclusionAfter.Disabled) + } +} + +func testAccCheckLoggingOrganizationExclusionDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_logging_organization_exclusion" { + continue + } + + attributes := rs.Primary.Attributes + + _, err := config.clientLogging.Organizations.Exclusions.Get(attributes["id"]).Do() + if err == nil { + return fmt.Errorf("organization exclusion still exists") + } + } + + return nil +} + +func testAccCheckLoggingOrganizationExclusionExists(n string, exclusion *logging.LogExclusion) resource.TestCheckFunc { + return func(s *terraform.State) error { + attributes, err := getResourceAttributes(n, s) + if err != nil { + return err + } + config := testAccProvider.Meta().(*Config) + + si, err := config.clientLogging.Organizations.Exclusions.Get(attributes["id"]).Do() + if err != nil { + return err + } + *exclusion = *si + + return nil + } +} + +func testAccCheckLoggingOrganizationExclusion(exclusion *logging.LogExclusion, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + attributes, err := getResourceAttributes(n, s) + if err != nil { + return err + } + + if exclusion.Description != attributes["description"] { + return fmt.Errorf("mismatch on description: api has %s but client has %s", exclusion.Description, attributes["description"]) + } + + if exclusion.Filter != attributes["filter"] { + return fmt.Errorf("mismatch on filter: api has %s but client has %s", exclusion.Filter, attributes["filter"]) + } + + disabledAttribute, err := toBool(attributes["disabled"]) + if err != nil { + return err + } + if exclusion.Disabled != disabledAttribute { + return fmt.Errorf("mismatch on disabled: api has %t but client has %t", exclusion.Disabled, disabledAttribute) + } + + return nil + } +} + +func testAccLoggingOrganizationExclusion_basic(exclusionName, description, orgId string) string { + return fmt.Sprintf(` +resource "google_logging_organization_exclusion" "basic" { + name = "%s" + org_id = "%s" + description = "%s" + filter = "logName=\"projects/%s/logs/compute.googleapis.com%%2Factivity_log\" AND severity>=ERROR" +} +`, exclusionName, orgId, description, getTestProjectFromEnv()) +} diff --git a/google/resource_logging_project_exclusion_test.go b/google/resource_logging_project_exclusion_test.go new file mode 100644 index 00000000000..c53521d7171 --- /dev/null +++ b/google/resource_logging_project_exclusion_test.go @@ -0,0 +1,225 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "google.golang.org/api/logging/v2" +) + +func TestAccLoggingProjectExclusion_basic(t *testing.T) { + t.Parallel() + + exclusionName := "tf-test-exclusion-" + acctest.RandString(10) + + var exclusion logging.LogExclusion + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLoggingProjectExclusionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoggingProjectExclusion_basic(exclusionName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingProjectExclusionExists("google_logging_project_exclusion.basic", &exclusion), + testAccCheckLoggingProjectExclusion(&exclusion, "google_logging_project_exclusion.basic")), + }, + { + ResourceName: "google_logging_project_exclusion.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccLoggingProjectExclusion_disablePreservesFilter(t *testing.T) { + t.Parallel() + + exclusionName := "tf-test-exclusion-" + acctest.RandString(10) + + var exclusionBefore, exclusionAfter logging.LogExclusion + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLoggingProjectExclusionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoggingProjectExclusion_basic(exclusionName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingProjectExclusionExists("google_logging_project_exclusion.basic", &exclusionBefore), + testAccCheckLoggingProjectExclusion(&exclusionBefore, "google_logging_project_exclusion.basic"), + ), + }, + { + Config: testAccLoggingProjectExclusion_basicDisabled(exclusionName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingProjectExclusionExists("google_logging_project_exclusion.basic", &exclusionAfter), + testAccCheckLoggingProjectExclusion(&exclusionAfter, "google_logging_project_exclusion.basic"), + ), + }, + { + ResourceName: "google_logging_project_exclusion.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + + // Description and Disabled should have changed, but Filter should be the same + if exclusionBefore.Description == exclusionAfter.Description { + t.Errorf("Expected Description to change, but it didn't: Description = %#v", exclusionBefore.Description) + } + if exclusionBefore.Filter != exclusionAfter.Filter { + t.Errorf("Expected Filter to be the same, but it differs: before = %#v, after = %#v", + exclusionBefore.Filter, exclusionAfter.Filter) + } + if exclusionBefore.Disabled == exclusionAfter.Disabled { + t.Errorf("Expected Disabled to change, but it didn't: Disabled = %#v", exclusionBefore.Disabled) + } +} + +func TestAccLoggingProjectExclusion_update(t *testing.T) { + t.Parallel() + + exclusionName := "tf-test-exclusion-" + acctest.RandString(10) + + var exclusionBefore, exclusionAfter logging.LogExclusion + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLoggingProjectExclusionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoggingProjectExclusion_basic(exclusionName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingProjectExclusionExists("google_logging_project_exclusion.basic", &exclusionBefore), + testAccCheckLoggingProjectExclusion(&exclusionBefore, "google_logging_project_exclusion.basic"), + ), + }, + { + Config: testAccLoggingProjectExclusion_basicUpdated(exclusionName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoggingProjectExclusionExists("google_logging_project_exclusion.basic", &exclusionAfter), + testAccCheckLoggingProjectExclusion(&exclusionAfter, "google_logging_project_exclusion.basic"), + ), + }, + { + ResourceName: "google_logging_project_exclusion.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + + // Filter should have changed, but Description and Disabled should be the same + if exclusionBefore.Description != exclusionAfter.Description { + t.Errorf("Expected Description to be the same, but it differs: before = %#v, after = %#v", + exclusionBefore.Description, exclusionAfter.Description) + } + if exclusionBefore.Filter == exclusionAfter.Filter { + t.Errorf("Expected Filter to change, but it didn't: Filter = %#v", exclusionBefore.Filter) + } + if exclusionBefore.Disabled != exclusionAfter.Disabled { + t.Errorf("Expected Disabled to be the same, but it differs: before = %#v, after = %#v", + exclusionBefore.Disabled, exclusionAfter.Disabled) + } +} + +func testAccCheckLoggingProjectExclusionDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_logging_project_exclusion" { + continue + } + + attributes := rs.Primary.Attributes + + _, err := config.clientLogging.Projects.Exclusions.Get(attributes["id"]).Do() + if err == nil { + return fmt.Errorf("project exclusion still exists") + } + } + + return nil +} + +func testAccCheckLoggingProjectExclusionExists(n string, exclusion *logging.LogExclusion) resource.TestCheckFunc { + return func(s *terraform.State) error { + attributes, err := getResourceAttributes(n, s) + if err != nil { + return err + } + config := testAccProvider.Meta().(*Config) + + si, err := config.clientLogging.Projects.Exclusions.Get(attributes["id"]).Do() + if err != nil { + return err + } + *exclusion = *si + + return nil + } +} + +func testAccCheckLoggingProjectExclusion(exclusion *logging.LogExclusion, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + attributes, err := getResourceAttributes(n, s) + if err != nil { + return err + } + + if exclusion.Description != attributes["description"] { + return fmt.Errorf("mismatch on description: api has %s but client has %s", exclusion.Description, attributes["description"]) + } + + if exclusion.Filter != attributes["filter"] { + return fmt.Errorf("mismatch on filter: api has %s but client has %s", exclusion.Filter, attributes["filter"]) + } + + disabledAttribute, err := toBool(attributes["disabled"]) + if err != nil { + return err + } + if exclusion.Disabled != disabledAttribute { + return fmt.Errorf("mismatch on disabled: api has %t but client has %t", exclusion.Disabled, disabledAttribute) + } + + return nil + } +} + +func testAccLoggingProjectExclusion_basic(name string) string { + return fmt.Sprintf(` +resource "google_logging_project_exclusion" "basic" { + name = "%s" + description = "Basic Project Logging Exclusion" + filter = "logName=\"projects/%s/logs/compute.googleapis.com%%2Factivity_log\" AND severity>=ERROR" +}`, name, getTestProjectFromEnv()) +} + +func testAccLoggingProjectExclusion_basicUpdated(name string) string { + return fmt.Sprintf(` +resource "google_logging_project_exclusion" "basic" { + name = "%s" + description = "Basic Project Logging Exclusion" + filter = "logName=\"projects/%s/logs/compute.googleapis.com%%2Factivity_log\" AND severity>=INFO" +}`, name, getTestProjectFromEnv()) +} + +func testAccLoggingProjectExclusion_basicDisabled(name string) string { + return fmt.Sprintf(` +resource "google_logging_project_exclusion" "basic" { + name = "%s" + description = "" + filter = "logName=\"projects/%s/logs/compute.googleapis.com%%2Factivity_log\" AND severity>=ERROR" + disabled = true +}`, name, getTestProjectFromEnv()) +} diff --git a/google/test_utils.go b/google/test_utils.go index de0cb1eae3f..d2075ba55d8 100644 --- a/google/test_utils.go +++ b/google/test_utils.go @@ -1,5 +1,9 @@ package google +import ( + "strconv" +) + type ResourceDataMock struct { FieldsInSchema map[string]interface{} FieldsWithHasChange []string @@ -39,3 +43,11 @@ func (d *ResourceDataMock) SetId(v string) { func (d *ResourceDataMock) Id() string { return d.id } + +func toBool(attribute string) (bool, error) { + // Handle the case where an unset value defaults to false + if attribute == "" { + return false, nil + } + return strconv.ParseBool(attribute) +} diff --git a/website/docs/r/logging_billing_account_exclusion.html.markdown b/website/docs/r/logging_billing_account_exclusion.html.markdown new file mode 100644 index 00000000000..f33337609a4 --- /dev/null +++ b/website/docs/r/logging_billing_account_exclusion.html.markdown @@ -0,0 +1,55 @@ +--- +layout: "google" +page_title: "Google: google_logging_billing_account_exclusion" +sidebar_current: "docs-google-logging-billing_account-exclusion" +description: |- + Manages a billing_account-level logging exclusion. +--- + +# google\_logging\_billing\_account\_exclusion + +Manages a billing account logging exclusion. For more information see +[the official documentation](https://cloud.google.com/logging/docs/) and +[Excluding Logs](https://cloud.google.com/logging/docs/exclusions). + +Note that you must have the "Logs Configuration Writer" IAM role (`roles/logging.configWriter`) +granted to the credentials used with Terraform. + +## Example Usage + +```hcl +resource "google_logging_billing_account_exclusion" "my-exclusion" { + name = "my-instance-debug-exclusion" + billing_account = "ABCDEF-012345-GHIJKL" + + description = "Exclude GCE instance debug logs" + + # Exclude all DEBUG or lower severity messages relating to instances + filter = "resource.type = gce_instance AND severity <= DEBUG" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `billing_account` - (Required) The billing account to create the exclusion for. + +* `name` - (Required) The name of the logging exclusion. + +* `description` - (Optional) A human-readable description. + +* `disabled` - (Optional) Whether this exclusion rule should be disabled or not. This defaults to + false. + +* `filter` - (Required) The filter to apply when excluding logs. Only log entries that match the filter are excluded. + See [Advanced Log Filters](https://cloud.google.com/logging/docs/view/advanced-filters) for information on how to + write a filter. + +## Import + +Billing account logging exclusions can be imported using their URI, e.g. + +``` +$ terraform import google_logging_billing_account_exclusion.my_exclusion billingAccounts/my-billing_account/exclusions/my-exclusion +``` diff --git a/website/docs/r/logging_folder_exclusion.html.markdown b/website/docs/r/logging_folder_exclusion.html.markdown new file mode 100644 index 00000000000..7f4784bd0f6 --- /dev/null +++ b/website/docs/r/logging_folder_exclusion.html.markdown @@ -0,0 +1,61 @@ +--- +layout: "google" +page_title: "Google: google_logging_folder_exclusion" +sidebar_current: "docs-google-logging-folder-exclusion" +description: |- + Manages a folder-level logging exclusion. +--- + +# google\_logging\_folder\_exclusion + +Manages a folder-level logging exclusion. For more information see +[the official documentation](https://cloud.google.com/logging/docs/) and +[Excluding Logs](https://cloud.google.com/logging/docs/exclusions). + +Note that you must have the "Logs Configuration Writer" IAM role (`roles/logging.configWriter`) +granted to the credentials used with Terraform. + +## Example Usage + +```hcl +resource "google_logging_folder_exclusion" "my-exclusion" { + name = "my-instance-debug-exclusion" + folder = "${google_folder.my-folder.name}" + + description = "Exclude GCE instance debug logs" + + # Exclude all DEBUG or lower severity messages relating to instances + filter = "resource.type = gce_instance AND severity <= DEBUG" +} + +resource "google_folder" "my-folder" { + display_name = "My folder" + parent = "organizations/123456" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `folder` - (Required) The folder to be exported to the sink. Note that either [FOLDER_ID] or "folders/[FOLDER_ID]" is + accepted. + +* `name` - (Required) The name of the logging exclusion. + +* `description` - (Optional) A human-readable description. + +* `disabled` - (Optional) Whether this exclusion rule should be disabled or not. This defaults to + false. + +* `filter` - (Required) The filter to apply when excluding logs. Only log entries that match the filter are excluded. + See [Advanced Log Filters](https://cloud.google.com/logging/docs/view/advanced-filters) for information on how to + write a filter. + +## Import + +Folder-level logging exclusions can be imported using their URI, e.g. + +``` +$ terraform import google_logging_folder_exclusion.my_exclusion folders/my-folder/exclusions/my-exclusion +``` diff --git a/website/docs/r/logging_organization_exclusion.html.markdown b/website/docs/r/logging_organization_exclusion.html.markdown new file mode 100644 index 00000000000..252f44e2127 --- /dev/null +++ b/website/docs/r/logging_organization_exclusion.html.markdown @@ -0,0 +1,55 @@ +--- +layout: "google" +page_title: "Google: google_logging_organization_exclusion" +sidebar_current: "docs-google-logging-organization-exclusion" +description: |- + Manages a organization-level logging exclusion. +--- + +# google\_logging\_organization\_exclusion + +Manages an organization-level logging exclusion. For more information see +[the official documentation](https://cloud.google.com/logging/docs/) and +[Excluding Logs](https://cloud.google.com/logging/docs/exclusions). + +Note that you must have the "Logs Configuration Writer" IAM role (`roles/logging.configWriter`) +granted to the credentials used with Terraform. + +## Example Usage + +```hcl +resource "google_logging_organization_exclusion" "my-exclusion" { + name = "my-instance-debug-exclusion" + org_id = "123456789" + + description = "Exclude GCE instance debug logs" + + # Exclude all DEBUG or lower severity messages relating to instances + filter = "resource.type = gce_instance AND severity <= DEBUG" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the logging exclusion. + +* `org_id` - (Required) The organization to create the exclusion in. + +* `description` - (Optional) A human-readable description. + +* `disabled` - (Optional) Whether this exclusion rule should be disabled or not. This defaults to + false. + +* `filter` - (Required) The filter to apply when excluding logs. Only log entries that match the filter are excluded. + See [Advanced Log Filters](https://cloud.google.com/logging/docs/view/advanced-filters) for information on how to + write a filter. + +## Import + +Organization-level logging exclusions can be imported using their URI, e.g. + +``` +$ terraform import google_logging_organization_exclusion.my_exclusion organizations/my-organization/exclusions/my-exclusion +``` diff --git a/website/docs/r/logging_project_exclusion.html.markdown b/website/docs/r/logging_project_exclusion.html.markdown new file mode 100644 index 00000000000..0fc71866484 --- /dev/null +++ b/website/docs/r/logging_project_exclusion.html.markdown @@ -0,0 +1,55 @@ +--- +layout: "google" +page_title: "Google: google_logging_project_exclusion" +sidebar_current: "docs-google-logging-project-exclusion" +description: |- + Manages a project-level logging exclusion. +--- + +# google\_logging\_project\_exclusion + +Manages a project-level logging exclusion. For more information see +[the official documentation](https://cloud.google.com/logging/docs/) and +[Excluding Logs](https://cloud.google.com/logging/docs/exclusions). + +Note that you must have the "Logs Configuration Writer" IAM role (`roles/logging.configWriter`) +granted to the credentials used with Terraform. + +## Example Usage + +```hcl +resource "google_logging_project_exclusion" "my-exclusion" { + name = "my-instance-debug-exclusion" + + description = "Exclude GCE instance debug logs" + + # Exclude all DEBUG or lower severity messages relating to instances + filter = "resource.type = gce_instance AND severity <= DEBUG" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `filter` - (Required) The filter to apply when excluding logs. Only log entries that match the filter are excluded. + See [Advanced Log Filters](https://cloud.google.com/logging/docs/view/advanced-filters) for information on how to + write a filter. + +* `name` - (Required) The name of the logging exclusion. + +* `description` - (Optional) A human-readable description. + +* `disabled` - (Optional) Whether this exclusion rule should be disabled or not. This defaults to + false. + +* `project` - (Optional) The project to create the exclusion in. If omitted, the project associated with the provider is + used. + +## Import + +Project-level logging exclusions can be imported using their URI, e.g. + +``` +$ terraform import google_logging_project_exclusion.my_exclusion projects/my-project/exclusions/my-exclusion +``` diff --git a/website/google.erb b/website/google.erb index 77e7b1c72e0..591a1461082 100644 --- a/website/google.erb +++ b/website/google.erb @@ -581,17 +581,33 @@ google_logging_billing_account_sink + > + google_logging_billing_account_exclusion + + > google_logging_organization_sink + > + google_logging_organization_exclusion + + > google_logging_folder_sink + > + google_logging_folder_exclusion + + > google_logging_project_sink + + > + google_logging_project_exclusion +