mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-10-03 01:01:06 +00:00
Add google_logging_folder_sink resource (#470)
* Fix bad page title * Add resource logging_folder_sink * Use proper parse function and string format * Remove unused strings
This commit is contained in:
parent
547f20a803
commit
ef543b20c5
@ -108,6 +108,7 @@ func Provider() terraform.ResourceProvider {
|
||||
"google_folder": resourceGoogleFolder(),
|
||||
"google_folder_iam_policy": resourceGoogleFolderIamPolicy(),
|
||||
"google_logging_billing_account_sink": resourceLoggingBillingAccountSink(),
|
||||
"google_logging_folder_sink": resourceLoggingFolderSink(),
|
||||
"google_logging_project_sink": resourceLoggingProjectSink(),
|
||||
"google_sourcerepo_repository": resourceSourceRepoRepository(),
|
||||
"google_spanner_instance": resourceSpannerInstance(),
|
||||
|
91
google/resource_logging_folder_sink.go
Normal file
91
google/resource_logging_folder_sink.go
Normal file
@ -0,0 +1,91 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceLoggingFolderSink() *schema.Resource {
|
||||
schm := &schema.Resource{
|
||||
Create: resourceLoggingFolderSinkCreate,
|
||||
Read: resourceLoggingFolderSinkRead,
|
||||
Delete: resourceLoggingFolderSinkDelete,
|
||||
Update: resourceLoggingFolderSinkUpdate,
|
||||
Schema: resourceLoggingSinkSchema(),
|
||||
}
|
||||
schm.Schema["folder"] = &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: optionalPrefixSuppress("folders/"),
|
||||
}
|
||||
schm.Schema["include_children"] = &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: false,
|
||||
}
|
||||
|
||||
return schm
|
||||
}
|
||||
|
||||
func resourceLoggingFolderSinkCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
folder := parseFolderId(d.Get("folder"))
|
||||
id, sink := expandResourceLoggingSink(d, "folders", folder)
|
||||
sink.IncludeChildren = d.Get("include_children").(bool)
|
||||
|
||||
// The API will reject any requests that don't explicitly set 'uniqueWriterIdentity' to true.
|
||||
_, err := config.clientLogging.Folders.Sinks.Create(id.parent(), sink).UniqueWriterIdentity(true).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(id.canonicalId())
|
||||
return resourceLoggingFolderSinkRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceLoggingFolderSinkRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
sink, err := config.clientLogging.Folders.Sinks.Get(d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Folder Logging Sink %s", d.Get("name").(string)))
|
||||
}
|
||||
|
||||
flattenResourceLoggingSink(d, sink)
|
||||
d.Set("include_children", sink.IncludeChildren)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceLoggingFolderSinkUpdate(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.Folders.Sinks.Patch(d.Id(), sink).UniqueWriterIdentity(true).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return resourceLoggingFolderSinkRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceLoggingFolderSinkDelete(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
|
||||
}
|
218
google/resource_logging_folder_sink_test.go
Normal file
218
google/resource_logging_folder_sink_test.go
Normal file
@ -0,0 +1,218 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"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 TestAccLoggingFolderSink_basic(t *testing.T) {
|
||||
skipIfEnvNotSet(t, "GOOGLE_ORG")
|
||||
|
||||
sinkName := "tf-test-sink-" + acctest.RandString(10)
|
||||
bucketName := "tf-test-sink-bucket-" + acctest.RandString(10)
|
||||
folderName := "tf-test-folder-" + acctest.RandString(10)
|
||||
org := os.Getenv("GOOGLE_ORG")
|
||||
|
||||
var sink logging.LogSink
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckLoggingFolderSinkDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccLoggingFolderSink_basic(sinkName, bucketName, folderName, "organizations/"+org),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLoggingFolderSinkExists("google_logging_folder_sink.basic", &sink),
|
||||
testAccCheckLoggingFolderSink(&sink, "google_logging_folder_sink.basic"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccLoggingFolderSink_folderAcceptsFullFolderPath(t *testing.T) {
|
||||
skipIfEnvNotSet(t, "GOOGLE_ORG")
|
||||
|
||||
sinkName := "tf-test-sink-" + acctest.RandString(10)
|
||||
bucketName := "tf-test-sink-bucket-" + acctest.RandString(10)
|
||||
folderName := "tf-test-folder-" + acctest.RandString(10)
|
||||
org := os.Getenv("GOOGLE_ORG")
|
||||
|
||||
var sink logging.LogSink
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckLoggingFolderSinkDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccLoggingFolderSink_withFullFolderPath(sinkName, bucketName, folderName, "organizations/"+org),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLoggingFolderSinkExists("google_logging_folder_sink.basic", &sink),
|
||||
testAccCheckLoggingFolderSink(&sink, "google_logging_folder_sink.basic"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccLoggingFolderSink_update(t *testing.T) {
|
||||
skipIfEnvNotSet(t, "GOOGLE_ORG")
|
||||
|
||||
sinkName := "tf-test-sink-" + acctest.RandString(10)
|
||||
bucketName := "tf-test-sink-bucket-" + acctest.RandString(10)
|
||||
updatedBucketName := "tf-test-sink-bucket-" + acctest.RandString(10)
|
||||
folderName := "tf-test-folder-" + acctest.RandString(10)
|
||||
parent := "organizations/" + os.Getenv("GOOGLE_ORG")
|
||||
|
||||
var sinkBefore, sinkAfter logging.LogSink
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckLoggingFolderSinkDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccLoggingFolderSink_basic(sinkName, bucketName, folderName, parent),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLoggingFolderSinkExists("google_logging_folder_sink.basic", &sinkBefore),
|
||||
testAccCheckLoggingFolderSink(&sinkBefore, "google_logging_folder_sink.basic"),
|
||||
),
|
||||
}, {
|
||||
Config: testAccLoggingFolderSink_basic(sinkName, updatedBucketName, folderName, parent),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLoggingFolderSinkExists("google_logging_folder_sink.basic", &sinkAfter),
|
||||
testAccCheckLoggingFolderSink(&sinkAfter, "google_logging_folder_sink.basic"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// 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 testAccCheckLoggingFolderSinkDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_logging_folder_sink" {
|
||||
continue
|
||||
}
|
||||
|
||||
attributes := rs.Primary.Attributes
|
||||
|
||||
_, err := config.clientLogging.Folders.Sinks.Get(attributes["id"]).Do()
|
||||
if err == nil {
|
||||
return fmt.Errorf("folder sink still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckLoggingFolderSinkExists(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.Folders.Sinks.Get(attributes["id"]).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*sink = *si
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckLoggingFolderSink(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 testAccLoggingFolderSink_basic(sinkName, bucketName, folderName, folderParent string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_logging_folder_sink" "basic" {
|
||||
name = "%s"
|
||||
folder = "${element(split("/", google_folder.my-folder.name), 1)}"
|
||||
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"
|
||||
}
|
||||
|
||||
resource "google_folder" "my-folder" {
|
||||
display_name = "%s"
|
||||
parent = "%s"
|
||||
}`, sinkName, getTestProjectFromEnv(), bucketName, folderName, folderParent)
|
||||
}
|
||||
|
||||
func testAccLoggingFolderSink_withFullFolderPath(sinkName, bucketName, folderName, folderParent string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_logging_folder_sink" "basic" {
|
||||
name = "%s"
|
||||
folder = "${google_folder.my-folder.name}"
|
||||
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 = false
|
||||
}
|
||||
|
||||
resource "google_storage_bucket" "log-bucket" {
|
||||
name = "%s"
|
||||
}
|
||||
|
||||
resource "google_folder" "my-folder" {
|
||||
display_name = "%s"
|
||||
parent = "%s"
|
||||
}`, sinkName, getTestProjectFromEnv(), bucketName, folderName, folderParent)
|
||||
}
|
@ -258,6 +258,12 @@ func linkDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func optionalPrefixSuppress(prefix string) schema.SchemaDiffSuppressFunc {
|
||||
return func(k, old, new string, d *schema.ResourceData) bool {
|
||||
return prefix+old == new || prefix+new == old
|
||||
}
|
||||
}
|
||||
|
||||
func ipCidrRangeDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
|
||||
// The range may be a:
|
||||
// A) single IP address (e.g. 10.2.3.4)
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_logging_billing-account_sink"
|
||||
page_title: "Google: google_logging_billing_account_sink"
|
||||
sidebar_current: "docs-google-logging-billing-account-sink"
|
||||
description: |-
|
||||
Manages a billing account logging sink.
|
||||
|
81
website/docs/r/logging_folder_sink.html.markdown
Normal file
81
website/docs/r/logging_folder_sink.html.markdown
Normal file
@ -0,0 +1,81 @@
|
||||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_logging_folder_sink"
|
||||
sidebar_current: "docs-google-logging-folder-sink"
|
||||
description: |-
|
||||
Manages a folder-level logging sink.
|
||||
---
|
||||
|
||||
# google\_logging\_folder\_sink
|
||||
|
||||
Manages a folder-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_folder_sink" "my-sink" {
|
||||
name = "my-sink"
|
||||
folder = "${google_folder.my-folder.name}"
|
||||
|
||||
# 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 = "folder-logging-bucket"
|
||||
}
|
||||
|
||||
resource "google_project_iam_binding" "log-writer" {
|
||||
role = "roles/storage.objectCreator"
|
||||
|
||||
members = [
|
||||
"${google_logging_folder_sink.my-sink.writer_identity}",
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_folder" "my-folder" {
|
||||
display_name = "My folder"
|
||||
parent = "organizations/123456"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the logging sink.
|
||||
|
||||
* `folder` - (Required) The folder to be exported to the sink. Note that either [FOLDER_ID] or "folders/[FOLDER_ID]" is
|
||||
accepted.
|
||||
|
||||
* `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 folders in the sink export. If true, logs
|
||||
associated with child projects are also exported; otherwise only logs relating to the provided folder 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`.
|
@ -342,6 +342,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-folder-sink") %>>
|
||||
<a href="/docs/providers/google/r/logging_folder_sink.html">google_logging_folder_sink</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-logging-project-sink") %>>
|
||||
<a href="/docs/providers/google/r/logging_project_sink.html">google_logging_project_sink</a>
|
||||
</li>
|
||||
|
Loading…
Reference in New Issue
Block a user