New Resource: Stack Driver Group

This commit is contained in:
Chris Stephens 2018-11-13 21:33:51 +00:00 committed by Nathan McKinley
parent 2c828110f0
commit 77c757d1e0
6 changed files with 579 additions and 5 deletions

View File

@ -18,4 +18,5 @@ import "github.com/hashicorp/terraform/helper/schema"
var GeneratedMonitoringResourcesMap = map[string]*schema.Resource{ var GeneratedMonitoringResourcesMap = map[string]*schema.Resource{
"google_monitoring_alert_policy": resourceMonitoringAlertPolicy(), "google_monitoring_alert_policy": resourceMonitoringAlertPolicy(),
"google_monitoring_group": resourceMonitoringGroup(),
} }

View File

@ -0,0 +1,295 @@
// ----------------------------------------------------------------------------
//
// *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
//
// ----------------------------------------------------------------------------
//
// This file is automatically generated by Magic Modules and manual
// changes will be clobbered when the file is regenerated.
//
// Please read more about how to change this file in
// .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------
package google
import (
"fmt"
"log"
"reflect"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceMonitoringGroup() *schema.Resource {
return &schema.Resource{
Create: resourceMonitoringGroupCreate,
Read: resourceMonitoringGroupRead,
Update: resourceMonitoringGroupUpdate,
Delete: resourceMonitoringGroupDelete,
Importer: &schema.ResourceImporter{
State: resourceMonitoringGroupImport,
},
Schema: map[string]*schema.Schema{
"display_name": {
Type: schema.TypeString,
Required: true,
},
"filter": {
Type: schema.TypeString,
Required: true,
},
"is_cluster": {
Type: schema.TypeBool,
Optional: true,
},
"parent_name": {
Type: schema.TypeString,
Optional: true,
DiffSuppressFunc: compareSelfLinkRelativePaths,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
"project": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
}
}
func resourceMonitoringGroupCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
obj := make(map[string]interface{})
parentNameProp, err := expandMonitoringGroupParentName(d.Get("parent_name"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("parent_name"); !isEmptyValue(reflect.ValueOf(parentNameProp)) && (ok || !reflect.DeepEqual(v, parentNameProp)) {
obj["parentName"] = parentNameProp
}
isClusterProp, err := expandMonitoringGroupIsCluster(d.Get("is_cluster"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("is_cluster"); !isEmptyValue(reflect.ValueOf(isClusterProp)) && (ok || !reflect.DeepEqual(v, isClusterProp)) {
obj["isCluster"] = isClusterProp
}
displayNameProp, err := expandMonitoringGroupDisplayName(d.Get("display_name"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
obj["displayName"] = displayNameProp
}
filterProp, err := expandMonitoringGroupFilter(d.Get("filter"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("filter"); !isEmptyValue(reflect.ValueOf(filterProp)) && (ok || !reflect.DeepEqual(v, filterProp)) {
obj["filter"] = filterProp
}
lockName, err := replaceVars(d, config, "stackdriver/groups/{{project}}")
if err != nil {
return err
}
mutexKV.Lock(lockName)
defer mutexKV.Unlock(lockName)
url, err := replaceVars(d, config, "https://monitoring.googleapis.com/v3/projects/{{project}}/groups")
if err != nil {
return err
}
log.Printf("[DEBUG] Creating new Group: %#v", obj)
res, err := sendRequest(config, "POST", url, obj)
if err != nil {
return fmt.Errorf("Error creating Group: %s", err)
}
// Store the ID now
id, err := replaceVars(d, config, "{{name}}")
if err != nil {
return fmt.Errorf("Error constructing id: %s", err)
}
d.SetId(id)
log.Printf("[DEBUG] Finished creating Group %q: %#v", d.Id(), res)
// `name` is autogenerated from the api so needs to be set post-create
name, ok := res["name"]
if !ok {
return fmt.Errorf("Create response didn't contain critical fields. Create may not have succeeded.")
}
d.Set("name", name.(string))
d.SetId(name.(string))
return resourceMonitoringGroupRead(d, meta)
}
func resourceMonitoringGroupRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
url, err := replaceVars(d, config, "https://monitoring.googleapis.com/v3/{{name}}")
if err != nil {
return err
}
res, err := sendRequest(config, "GET", url, nil)
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("MonitoringGroup %q", d.Id()))
}
if err := d.Set("parent_name", flattenMonitoringGroupParentName(res["parentName"])); err != nil {
return fmt.Errorf("Error reading Group: %s", err)
}
if err := d.Set("name", flattenMonitoringGroupName(res["name"])); err != nil {
return fmt.Errorf("Error reading Group: %s", err)
}
if err := d.Set("is_cluster", flattenMonitoringGroupIsCluster(res["isCluster"])); err != nil {
return fmt.Errorf("Error reading Group: %s", err)
}
if err := d.Set("display_name", flattenMonitoringGroupDisplayName(res["displayName"])); err != nil {
return fmt.Errorf("Error reading Group: %s", err)
}
if err := d.Set("filter", flattenMonitoringGroupFilter(res["filter"])); err != nil {
return fmt.Errorf("Error reading Group: %s", err)
}
project, err := getProject(d, config)
if err != nil {
return err
}
if err := d.Set("project", project); err != nil {
return fmt.Errorf("Error reading Group: %s", err)
}
return nil
}
func resourceMonitoringGroupUpdate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
obj := make(map[string]interface{})
parentNameProp, err := expandMonitoringGroupParentName(d.Get("parent_name"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("parent_name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, parentNameProp)) {
obj["parentName"] = parentNameProp
}
isClusterProp, err := expandMonitoringGroupIsCluster(d.Get("is_cluster"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("is_cluster"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, isClusterProp)) {
obj["isCluster"] = isClusterProp
}
displayNameProp, err := expandMonitoringGroupDisplayName(d.Get("display_name"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
obj["displayName"] = displayNameProp
}
filterProp, err := expandMonitoringGroupFilter(d.Get("filter"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("filter"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, filterProp)) {
obj["filter"] = filterProp
}
lockName, err := replaceVars(d, config, "stackdriver/groups/{{project}}")
if err != nil {
return err
}
mutexKV.Lock(lockName)
defer mutexKV.Unlock(lockName)
url, err := replaceVars(d, config, "https://monitoring.googleapis.com/v3/{{name}}")
if err != nil {
return err
}
log.Printf("[DEBUG] Updating Group %q: %#v", d.Id(), obj)
_, err = sendRequest(config, "PUT", url, obj)
if err != nil {
return fmt.Errorf("Error updating Group %q: %s", d.Id(), err)
}
return resourceMonitoringGroupRead(d, meta)
}
func resourceMonitoringGroupDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
lockName, err := replaceVars(d, config, "stackdriver/groups/{{project}}")
if err != nil {
return err
}
mutexKV.Lock(lockName)
defer mutexKV.Unlock(lockName)
url, err := replaceVars(d, config, "https://monitoring.googleapis.com/v3/{{name}}")
if err != nil {
return err
}
var obj map[string]interface{}
log.Printf("[DEBUG] Deleting Group %q", d.Id())
res, err := sendRequest(config, "DELETE", url, obj)
if err != nil {
return handleNotFoundError(err, d, "Group")
}
log.Printf("[DEBUG] Finished deleting Group %q: %#v", d.Id(), res)
return nil
}
func resourceMonitoringGroupImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
config := meta.(*Config)
// current import_formats can't import id's with forward slashes in them.
parseImportId([]string{"(?P<name>.+)"}, d, config)
return []*schema.ResourceData{d}, nil
}
func flattenMonitoringGroupParentName(v interface{}) interface{} {
return v
}
func flattenMonitoringGroupName(v interface{}) interface{} {
return v
}
func flattenMonitoringGroupIsCluster(v interface{}) interface{} {
return v
}
func flattenMonitoringGroupDisplayName(v interface{}) interface{} {
return v
}
func flattenMonitoringGroupFilter(v interface{}) interface{} {
return v
}
func expandMonitoringGroupParentName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandMonitoringGroupIsCluster(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandMonitoringGroupDisplayName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandMonitoringGroupFilter(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}

View File

@ -0,0 +1,113 @@
// ----------------------------------------------------------------------------
//
// *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
//
// ----------------------------------------------------------------------------
//
// This file is automatically generated by Magic Modules and manual
// changes will be clobbered when the file is regenerated.
//
// Please read more about how to change this file in
// .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------
package google
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccMonitoringGroup_monitoringGroupBasicExample(t *testing.T) {
t.Parallel()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckMonitoringGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccMonitoringGroup_monitoringGroupBasicExample(acctest.RandString(10)),
},
{
ResourceName: "google_monitoring_group.basic",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccMonitoringGroup_monitoringGroupBasicExample(val string) string {
return fmt.Sprintf(`
resource "google_monitoring_group" "basic" {
display_name = "New Test Group-%s"
filter = "resource.metadata.region=\"europe-west2\""
}
`, val,
)
}
func TestAccMonitoringGroup_monitoringGroupSubgroupExample(t *testing.T) {
t.Parallel()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckMonitoringGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccMonitoringGroup_monitoringGroupSubgroupExample(acctest.RandString(10)),
},
{
ResourceName: "google_monitoring_group.subgroup",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccMonitoringGroup_monitoringGroupSubgroupExample(val string) string {
return fmt.Sprintf(`
resource "google_monitoring_group" "parent" {
display_name = "New Test SubGroup-%s"
filter = "resource.metadata.region=\"europe-west2\""
}
resource "google_monitoring_group" "subgroup" {
display_name = "New Test SubGroup-%s"
filter = "resource.metadata.region=\"europe-west2\""
parent_name = "${google_monitoring_group.parent.name}"
}
`, val, val,
)
}
func testAccCheckMonitoringGroupDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "google_monitoring_group" {
continue
}
config := testAccProvider.Meta().(*Config)
url, err := replaceVarsForTest(rs, "https://monitoring.googleapis.com/v3/{{name}}")
if err != nil {
return err
}
_, err = sendRequest(config, "GET", url, nil)
if err == nil {
return fmt.Errorf("MonitoringGroup still exists at %s", url)
}
}
return nil
}

View File

@ -0,0 +1,47 @@
package google
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/resource"
)
func TestAccMonitoringGroup_update(t *testing.T) {
t.Parallel()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckMonitoringGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccMonitoringGroup_update("europe-west1"),
},
{
ResourceName: "google_monitoring_group.update",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccMonitoringGroup_update("europe-west2"),
},
{
ResourceName: "google_monitoring_group.update",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccMonitoringGroup_update(zone string) string {
return fmt.Sprintf(`
resource "google_monitoring_group" "update" {
display_name = "Integration Test Group"
filter = "resource.metadata.region=\"%s\""
}
`, zone,
)
}

View File

@ -357,11 +357,6 @@ The `node_config` block supports:
* `service_account` - (Optional) The service account to be used by the Node VMs. * `service_account` - (Optional) The service account to be used by the Node VMs.
If not specified, the "default" service account is used. If not specified, the "default" service account is used.
In order to use the configured `oauth_scopes` for logging and monitoring, the service account being used needs the
[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#stackdriver_logging_roles) and
[roles/monitoring.metricWriter](https://cloud.google.com/iam/docs/understanding-roles#stackdriver_monitoring_roles) roles.
-> Projects that enable the [Cloud Compute Engine API](https://cloud.google.com/compute/) with Terraform may need these roles added manually to the service account. Projects that enable the API in the Cloud Console should have them added automatically.
* `tags` - (Optional) The list of instance tags applied to all nodes. Tags are used to identify * `tags` - (Optional) The list of instance tags applied to all nodes. Tags are used to identify
valid sources or targets for network firewalls. valid sources or targets for network firewalls.

View File

@ -0,0 +1,123 @@
---
# ----------------------------------------------------------------------------
#
# *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
#
# ----------------------------------------------------------------------------
#
# This file is automatically generated by Magic Modules and manual
# changes will be clobbered when the file is regenerated.
#
# Please read more about how to change this file in
# .github/CONTRIBUTING.md.
#
# ----------------------------------------------------------------------------
layout: "google"
page_title: "Google: google_monitoring_group"
sidebar_current: "docs-google-monitoring-group"
description: |-
The description of a dynamic collection of monitored resources.
---
# google\_monitoring\_group
The description of a dynamic collection of monitored resources. Each group
has a filter that is matched against monitored resources and their
associated metadata. If a group's filter matches an available monitored
resource, then that resource is a member of that group.
To get more information about Group, see:
* [API documentation](https://cloud.google.com/monitoring/api/ref_v3/rest/v3/projects.groups)
* How-to Guides
* [Official Documentation](https://cloud.google.com/monitoring/groups/)
<div class = "oics-button" style="float: right; margin: 0 0 -15px">
<a href="https://console.cloud.google.com/cloudshell/open?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fterraform-google-modules%2Fdocs-examples.git&cloudshell_working_dir=monitoring_group_basic&cloudshell_image=gcr.io%2Fgraphite-cloud-shell-images%2Fterraform%3Alatest&open_in_editor=main.tf&cloudshell_print=.%2Fmotd&cloudshell_tutorial=.%2Ftutorial.md" target="_blank">
<img alt="Open in Cloud Shell" src="//gstatic.com/cloudssh/images/open-btn.svg" style="max-height: 44px; margin: 32px auto; max-width: 100%;">
</a>
</div>
## Example Usage - Monitoring Group Basic
```hcl
resource "google_monitoring_group" "basic" {
display_name = "New Test Group"
filter = "resource.metadata.region=\"europe-west2\""
}
```
<div class = "oics-button" style="float: right; margin: 0 0 -15px">
<a href="https://console.cloud.google.com/cloudshell/open?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fterraform-google-modules%2Fdocs-examples.git&cloudshell_working_dir=monitoring_group_subgroup&cloudshell_image=gcr.io%2Fgraphite-cloud-shell-images%2Fterraform%3Alatest&open_in_editor=main.tf&cloudshell_print=.%2Fmotd&cloudshell_tutorial=.%2Ftutorial.md" target="_blank">
<img alt="Open in Cloud Shell" src="//gstatic.com/cloudssh/images/open-btn.svg" style="max-height: 44px; margin: 32px auto; max-width: 100%;">
</a>
</div>
## Example Usage - Monitoring Group Subgroup
```hcl
resource "google_monitoring_group" "parent" {
display_name = "New Test SubGroup"
filter = "resource.metadata.region=\"europe-west2\""
}
resource "google_monitoring_group" "subgroup" {
display_name = "New Test SubGroup"
filter = "resource.metadata.region=\"europe-west2\""
parent_name = "${google_monitoring_group.parent.name}"
}
```
## Argument Reference
The following arguments are supported:
* `display_name` -
(Required)
A user-assigned name for this group, used only for display
purposes.
* `filter` -
(Required)
The filter used to determine which monitored resources
belong to this group.
- - -
* `parent_name` -
(Optional)
The name of the group's parent, if it has one. The format is
"projects/{project_id_or_number}/groups/{group_id}". For
groups with no parent, parentName is the empty string, "".
* `is_cluster` -
(Optional)
If true, the members of this group are considered to be a
cluster. The system can perform additional analysis on
groups that are clusters.
* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.
## Attributes Reference
In addition to the arguments listed above, the following computed attributes are exported:
* `name` -
A unique identifier for this group. The format is
"projects/{project_id_or_number}/groups/{group_id}".
## Import
Group can be imported using any of these accepted formats:
```
$ terraform import google_monitoring_group.default {{name}}
```