mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-07-03 08:42:39 +00:00
Add google_logging_organization_sink resource (#923)
* Add google_logging_organization_sink resource * cleanup
This commit is contained in:
parent
de23b59463
commit
5a557546a7
|
@ -137,6 +137,7 @@ 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_organization_sink": resourceLoggingOrganizationSink(),
|
||||
"google_logging_folder_sink": resourceLoggingFolderSink(),
|
||||
"google_logging_project_sink": resourceLoggingProjectSink(),
|
||||
"google_kms_key_ring": resourceKmsKeyRing(),
|
||||
|
|
90
google/resource_logging_organization_sink.go
Normal file
90
google/resource_logging_organization_sink.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceLoggingOrganizationSink() *schema.Resource {
|
||||
schm := &schema.Resource{
|
||||
Create: resourceLoggingOrganizationSinkCreate,
|
||||
Read: resourceLoggingOrganizationSinkRead,
|
||||
Delete: resourceLoggingOrganizationSinkDelete,
|
||||
Update: resourceLoggingOrganizationSinkUpdate,
|
||||
Schema: resourceLoggingSinkSchema(),
|
||||
}
|
||||
schm.Schema["org_id"] = &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DiffSuppressFunc: optionalPrefixSuppress("organizations/"),
|
||||
}
|
||||
schm.Schema["include_children"] = &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: false,
|
||||
}
|
||||
|
||||
return schm
|
||||
}
|
||||
|
||||
func resourceLoggingOrganizationSinkCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
org := d.Get("org_id").(string)
|
||||
id, sink := expandResourceLoggingSink(d, "organizations", org)
|
||||
sink.IncludeChildren = d.Get("include_children").(bool)
|
||||
|
||||
// Must use a unique writer, since all destinations are in projects.
|
||||
// The API will reject any requests that don't explicitly set 'uniqueWriterIdentity' to true.
|
||||
_, err := config.clientLogging.Organizations.Sinks.Create(id.parent(), sink).UniqueWriterIdentity(true).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(id.canonicalId())
|
||||
return resourceLoggingOrganizationSinkRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceLoggingOrganizationSinkRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
sink, err := config.clientLogging.Organizations.Sinks.Get(d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Organization Logging Sink %s", d.Get("name").(string)))
|
||||
}
|
||||
|
||||
flattenResourceLoggingSink(d, sink)
|
||||
d.Set("include_children", sink.IncludeChildren)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceLoggingOrganizationSinkUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
sink := expandResourceLoggingSinkForUpdate(d)
|
||||
// It seems the API might actually accept an update for include_children; this is not in the list of updatable
|
||||
// properties though and might break in the future. Always include the value to prevent it changing.
|
||||
sink.IncludeChildren = d.Get("include_children").(bool)
|
||||
sink.ForceSendFields = append(sink.ForceSendFields, "IncludeChildren")
|
||||
|
||||
// The API will reject any requests that don't explicitly set 'uniqueWriterIdentity' to true.
|
||||
_, err := config.clientLogging.Organizations.Sinks.Patch(d.Id(), sink).UniqueWriterIdentity(true).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return resourceLoggingOrganizationSinkRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceLoggingOrganizationSinkDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
_, err := config.clientLogging.Projects.Sinks.Delete(d.Id()).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
180
google/resource_logging_organization_sink_test.go
Normal file
180
google/resource_logging_organization_sink_test.go
Normal file
|
@ -0,0 +1,180 @@
|
|||
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"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func TestAccLoggingOrganizationSink_basic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
org := getTestOrgFromEnv(t)
|
||||
sinkName := "tf-test-sink-" + acctest.RandString(10)
|
||||
bucketName := "tf-test-sink-bucket-" + acctest.RandString(10)
|
||||
|
||||
var sink logging.LogSink
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckLoggingOrganizationSinkDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccLoggingOrganizationSink_basic(sinkName, bucketName, org),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLoggingOrganizationSinkExists("google_logging_organization_sink.basic", &sink),
|
||||
testAccCheckLoggingOrganizationSink(&sink, "google_logging_organization_sink.basic"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccLoggingOrganizationSink_update(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
org := getTestOrgFromEnv(t)
|
||||
sinkName := "tf-test-sink-" + acctest.RandString(10)
|
||||
bucketName := "tf-test-sink-bucket-" + acctest.RandString(10)
|
||||
updatedBucketName := "tf-test-sink-bucket-" + acctest.RandString(10)
|
||||
|
||||
var sinkBefore, sinkAfter logging.LogSink
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckLoggingOrganizationSinkDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccLoggingOrganizationSink_update(sinkName, bucketName, org),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLoggingOrganizationSinkExists("google_logging_organization_sink.update", &sinkBefore),
|
||||
testAccCheckLoggingOrganizationSink(&sinkBefore, "google_logging_organization_sink.update"),
|
||||
),
|
||||
}, {
|
||||
Config: testAccLoggingOrganizationSink_update(sinkName, updatedBucketName, org),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLoggingOrganizationSinkExists("google_logging_organization_sink.update", &sinkAfter),
|
||||
testAccCheckLoggingOrganizationSink(&sinkAfter, "google_logging_organization_sink.update"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Destination should have changed, but WriterIdentity should be the same
|
||||
if sinkBefore.Destination == sinkAfter.Destination {
|
||||
t.Errorf("Expected Destination to change, but it didn't: Destination = %#v", sinkBefore.Destination)
|
||||
}
|
||||
if sinkBefore.WriterIdentity != sinkAfter.WriterIdentity {
|
||||
t.Errorf("Expected WriterIdentity to be the same, but it differs: before = %#v, after = %#v",
|
||||
sinkBefore.WriterIdentity, sinkAfter.WriterIdentity)
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckLoggingOrganizationSinkDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_logging_organization_sink" {
|
||||
continue
|
||||
}
|
||||
|
||||
attributes := rs.Primary.Attributes
|
||||
|
||||
_, err := config.clientLogging.Organizations.Sinks.Get(attributes["id"]).Do()
|
||||
if err == nil {
|
||||
return fmt.Errorf("organization sink still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckLoggingOrganizationSinkExists(n string, sink *logging.LogSink) 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.Sinks.Get(attributes["id"]).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*sink = *si
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckLoggingOrganizationSink(sink *logging.LogSink, n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
attributes, err := getResourceAttributes(n, s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sink.Destination != attributes["destination"] {
|
||||
return fmt.Errorf("mismatch on destination: api has %s but client has %s", sink.Destination, attributes["destination"])
|
||||
}
|
||||
|
||||
if sink.Filter != attributes["filter"] {
|
||||
return fmt.Errorf("mismatch on filter: api has %s but client has %s", sink.Filter, attributes["filter"])
|
||||
}
|
||||
|
||||
if sink.WriterIdentity != attributes["writer_identity"] {
|
||||
return fmt.Errorf("mismatch on writer_identity: api has %s but client has %s", sink.WriterIdentity, attributes["writer_identity"])
|
||||
}
|
||||
|
||||
includeChildren := false
|
||||
if attributes["include_children"] != "" {
|
||||
includeChildren, err = strconv.ParseBool(attributes["include_children"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if sink.IncludeChildren != includeChildren {
|
||||
return fmt.Errorf("mismatch on include_children: api has %v but client has %v", sink.IncludeChildren, includeChildren)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccLoggingOrganizationSink_basic(sinkName, bucketName, orgId string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_logging_organization_sink" "basic" {
|
||||
name = "%s"
|
||||
org_id = "%s"
|
||||
destination = "storage.googleapis.com/${google_storage_bucket.log-bucket.name}"
|
||||
filter = "logName=\"projects/%s/logs/compute.googleapis.com%%2Factivity_log\" AND severity>=ERROR"
|
||||
include_children = true
|
||||
}
|
||||
|
||||
resource "google_storage_bucket" "log-bucket" {
|
||||
name = "%s"
|
||||
}`, sinkName, orgId, getTestProjectFromEnv(), bucketName)
|
||||
}
|
||||
|
||||
func testAccLoggingOrganizationSink_update(sinkName, bucketName, orgId string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_logging_organization_sink" "update" {
|
||||
name = "%s"
|
||||
org_id = "%s"
|
||||
destination = "storage.googleapis.com/${google_storage_bucket.log-bucket.name}"
|
||||
filter = "logName=\"projects/%s/logs/compute.googleapis.com%%2Factivity_log\" AND severity>=ERROR"
|
||||
destination = "storage.googleapis.com/${google_storage_bucket.log-bucket.name}"
|
||||
include_children = false
|
||||
}
|
||||
|
||||
resource "google_storage_bucket" "log-bucket" {
|
||||
name = "%s"
|
||||
}`, sinkName, orgId, getTestProjectFromEnv(), bucketName)
|
||||
}
|
75
website/docs/r/logging_organization_sink.hml.markdown
Normal file
75
website/docs/r/logging_organization_sink.hml.markdown
Normal file
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_logging_organization_sink"
|
||||
sidebar_current: "docs-google-logging-organization-sink"
|
||||
description: |-
|
||||
Manages a organization-level logging sink.
|
||||
---
|
||||
|
||||
# google\_logging\_organization\_sink
|
||||
|
||||
Manages a organization-level logging sink. For more information see
|
||||
[the official documentation](https://cloud.google.com/logging/docs/) and
|
||||
[Exporting Logs in the API](https://cloud.google.com/logging/docs/api/tasks/exporting-logs).
|
||||
|
||||
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_sink" "my-sink" {
|
||||
name = "my-sink"
|
||||
org_id = "123456789"
|
||||
|
||||
# Can export to pubsub, cloud storage, or bigtable
|
||||
destination = "storage.googleapis.com/${google_storage_bucket.log-bucket.name}"
|
||||
|
||||
# Log all WARN or higher severity messages relating to instances
|
||||
filter = "resource.type = gce_instance AND severity >= WARN"
|
||||
}
|
||||
|
||||
resource "google_storage_bucket" "log-bucket" {
|
||||
name = "organization-logging-bucket"
|
||||
}
|
||||
|
||||
resource "google_project_iam_binding" "log-writer" {
|
||||
role = "roles/storage.objectCreator"
|
||||
|
||||
members = [
|
||||
"${google_logging_organization_sink.my-sink.writer_identity}",
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the logging sink.
|
||||
|
||||
* `org_id` - (Required) The numeric ID of the organization to be exported to the sink.
|
||||
|
||||
* `destination` - (Required) The destination of the sink (or, in other words, where logs are written to). Can be a
|
||||
Cloud Storage bucket, a PubSub topic, or a BigQuery dataset. Examples:
|
||||
```
|
||||
"storage.googleapis.com/[GCS_BUCKET]"
|
||||
"bigquery.googleapis.com/projects/[PROJECT_ID]/datasets/[DATASET]"
|
||||
"pubsub.googleapis.com/projects/[PROJECT_ID]/topics/[TOPIC_ID]"
|
||||
```
|
||||
The writer associated with the sink must have access to write to the above resource.
|
||||
|
||||
* `filter` - (Optional) The filter to apply when exporting logs. Only log entries that match the filter are exported.
|
||||
See [Advanced Log Filters](https://cloud.google.com/logging/docs/view/advanced_filters) for information on how to
|
||||
write a filter.
|
||||
|
||||
* `include_children` - (Optional) Whether or not to include children organizations in the sink export. If true, logs
|
||||
associated with child projects are also exported; otherwise only logs relating to the provided organization are included.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
In addition to the arguments listed above, the following computed attributes are
|
||||
exported:
|
||||
|
||||
* `writer_identity` - The identity associated with this sink. This identity must be granted write access to the
|
||||
configured `destination`.
|
|
@ -448,6 +448,10 @@
|
|||
<a href="/docs/providers/google/r/logging_billing_account_sink.html">google_logging_billing_account_sink</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-logging-organization-sink") %>>
|
||||
<a href="/docs/providers/google/r/logging_organization_sink.html">google_logging_organization_sink</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-logging-folder-sink") %>>
|
||||
<a href="/docs/providers/google/r/logging_folder_sink.html">google_logging_folder_sink</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue
Block a user