Skip to content

Commit

Permalink
Monitoring metric descriptor (#3754) (#6829)
Browse files Browse the repository at this point in the history
* added metric descriptor resource and more functionality to PollAsync

* added handrwitten test for metric descriptor

* added a test case and cleaned up stale comments

* fixed small formatting things

* addressed more comments

Co-authored-by: Tiffany Shen <[email protected]>
Signed-off-by: Modular Magician <[email protected]>

Co-authored-by: Tiffany Shen <[email protected]>
  • Loading branch information
modular-magician and tiffunky authored Jul 22, 2020
1 parent f84d4f4 commit dd9be82
Show file tree
Hide file tree
Showing 16 changed files with 1,337 additions and 13 deletions.
3 changes: 3 additions & 0 deletions .changelog/3754.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
`google_monitoring_metric_descriptor`
```
81 changes: 78 additions & 3 deletions google/common_polling.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package google
import (
"fmt"
"log"
"sync"
"time"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
Expand Down Expand Up @@ -31,19 +32,81 @@ func SuccessPollResult() PollResult {
return nil
}

func PollingWaitTime(pollF PollReadFunc, checkResponse PollCheckResponseFunc, activity string, timeout time.Duration) error {
func PollingWaitTime(pollF PollReadFunc, checkResponse PollCheckResponseFunc, activity string,
timeout time.Duration, targetOccurrences int) error {
log.Printf("[DEBUG] %s: Polling until expected state is read", activity)
return resource.Retry(timeout, func() *resource.RetryError {
log.Printf("[DEBUG] Target occurrences: %d", targetOccurrences)
if targetOccurrences == 1 {
return resource.Retry(timeout, func() *resource.RetryError {
readResp, readErr := pollF()
return checkResponse(readResp, readErr)
})
}
return RetryWithTargetOccurrences(timeout, targetOccurrences, func() *resource.RetryError {
readResp, readErr := pollF()
return checkResponse(readResp, readErr)
})
}

// RetryWithTargetOccurrences is a basic wrapper around StateChangeConf that will retry
// a function until it returns the specified amount of target occurrences continuously.
// Adapted from the Retry function in the go SDK.
func RetryWithTargetOccurrences(timeout time.Duration, targetOccurrences int,
f resource.RetryFunc) error {
// These are used to pull the error out of the function; need a mutex to
// avoid a data race.
var resultErr error
var resultErrMu sync.Mutex

c := &resource.StateChangeConf{
Pending: []string{"retryableerror"},
Target: []string{"success"},
Timeout: timeout,
MinTimeout: 500 * time.Millisecond,
ContinuousTargetOccurence: targetOccurrences,
Refresh: func() (interface{}, string, error) {
rerr := f()

resultErrMu.Lock()
defer resultErrMu.Unlock()

if rerr == nil {
resultErr = nil
return 42, "success", nil
}

resultErr = rerr.Err

if rerr.Retryable {
return 42, "retryableerror", nil
}
return nil, "quit", rerr.Err
},
}

_, waitErr := c.WaitForState()

// Need to acquire the lock here to be able to avoid race using resultErr as
// the return value
resultErrMu.Lock()
defer resultErrMu.Unlock()

// resultErr may be nil because the wait timed out and resultErr was never
// set; this is still an error
if resultErr == nil {
return waitErr
}
// resultErr takes precedence over waitErr if both are set because it is
// more likely to be useful
return resultErr
}

/**
* Common PollCheckResponseFunc implementations
*/

// PollCheckForExistence waits for a successful response, continues polling on 404, and returns any other error.
// PollCheckForExistence waits for a successful response, continues polling on 404,
// and returns any other error.
func PollCheckForExistence(_ map[string]interface{}, respErr error) PollResult {
if respErr != nil {
if isGoogleApiErrorWithCode(respErr, 404) {
Expand All @@ -53,3 +116,15 @@ func PollCheckForExistence(_ map[string]interface{}, respErr error) PollResult {
}
return SuccessPollResult()
}

// PollCheckForAbsence waits for a 404 response, continues polling on a successful
// response, and returns any other error.
func PollCheckForAbsence(_ map[string]interface{}, respErr error) PollResult {
if respErr != nil {
if isGoogleApiErrorWithCode(respErr, 404) {
return SuccessPollResult()
}
return ErrorPollResult(respErr)
}
return PendingStatusPollResult("found")
}
5 changes: 3 additions & 2 deletions google/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,9 +590,9 @@ func Provider() terraform.ResourceProvider {
return provider
}

// Generated resources: 142
// Generated resources: 143
// Generated IAM resources: 57
// Total generated resources: 199
// Total generated resources: 200
func ResourceMap() map[string]*schema.Resource {
resourceMap, _ := ResourceMapWithErrors()
return resourceMap
Expand Down Expand Up @@ -761,6 +761,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) {
"google_monitoring_custom_service": resourceMonitoringService(),
"google_monitoring_slo": resourceMonitoringSlo(),
"google_monitoring_uptime_check_config": resourceMonitoringUptimeCheckConfig(),
"google_monitoring_metric_descriptor": resourceMonitoringMetricDescriptor(),
"google_network_management_connectivity_test": resourceNetworkManagementConnectivityTest(),
"google_os_config_patch_deployment": resourceOSConfigPatchDeployment(),
"google_os_login_ssh_public_key": resourceOSLoginSSHPublicKey(),
Expand Down
2 changes: 1 addition & 1 deletion google/resource_app_engine_firewall_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func resourceAppEngineFirewallRuleCreate(d *schema.ResourceData, meta interface{
}
d.SetId(id)

err = PollingWaitTime(resourceAppEngineFirewallRulePollRead(d, meta), PollCheckForExistence, "Creating FirewallRule", d.Timeout(schema.TimeoutCreate))
err = PollingWaitTime(resourceAppEngineFirewallRulePollRead(d, meta), PollCheckForExistence, "Creating FirewallRule", d.Timeout(schema.TimeoutCreate), 1)
if err != nil {
return fmt.Errorf("Error waiting to create FirewallRule: %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion google/resource_big_query_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ func resourceBigQueryJobCreate(d *schema.ResourceData, meta interface{}) error {
}
d.SetId(id)

err = PollingWaitTime(resourceBigQueryJobPollRead(d, meta), PollCheckForExistence, "Creating Job", d.Timeout(schema.TimeoutCreate))
err = PollingWaitTime(resourceBigQueryJobPollRead(d, meta), PollCheckForExistence, "Creating Job", d.Timeout(schema.TimeoutCreate), 1)
if err != nil {
return fmt.Errorf("Error waiting to create Job: %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion google/resource_cloud_run_domain_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ func resourceCloudRunDomainMappingCreate(d *schema.ResourceData, meta interface{
}
d.SetId(id)

err = PollingWaitTime(resourceCloudRunDomainMappingPollRead(d, meta), PollCheckKnativeStatus, "Creating DomainMapping", d.Timeout(schema.TimeoutCreate))
err = PollingWaitTime(resourceCloudRunDomainMappingPollRead(d, meta), PollCheckKnativeStatus, "Creating DomainMapping", d.Timeout(schema.TimeoutCreate), 1)
if err != nil {
return fmt.Errorf("Error waiting to create DomainMapping: %s", err)
}
Expand Down
4 changes: 2 additions & 2 deletions google/resource_cloud_run_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ func resourceCloudRunServiceCreate(d *schema.ResourceData, meta interface{}) err
}
d.SetId(id)

err = PollingWaitTime(resourceCloudRunServicePollRead(d, meta), PollCheckKnativeStatus, "Creating Service", d.Timeout(schema.TimeoutCreate))
err = PollingWaitTime(resourceCloudRunServicePollRead(d, meta), PollCheckKnativeStatus, "Creating Service", d.Timeout(schema.TimeoutCreate), 1)
if err != nil {
return fmt.Errorf("Error waiting to create Service: %s", err)
}
Expand Down Expand Up @@ -785,7 +785,7 @@ func resourceCloudRunServiceUpdate(d *schema.ResourceData, meta interface{}) err
return fmt.Errorf("Error updating Service %q: %s", d.Id(), err)
}

err = PollingWaitTime(resourceCloudRunServicePollRead(d, meta), PollCheckKnativeStatus, "Updating Service", d.Timeout(schema.TimeoutUpdate))
err = PollingWaitTime(resourceCloudRunServicePollRead(d, meta), PollCheckKnativeStatus, "Updating Service", d.Timeout(schema.TimeoutUpdate), 1)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion google/resource_iap_brand.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func resourceIapBrandCreate(d *schema.ResourceData, meta interface{}) error {
}
d.SetId(id)

err = PollingWaitTime(resourceIapBrandPollRead(d, meta), PollCheckForExistence, "Creating Brand", d.Timeout(schema.TimeoutCreate))
err = PollingWaitTime(resourceIapBrandPollRead(d, meta), PollCheckForExistence, "Creating Brand", d.Timeout(schema.TimeoutCreate), 1)
if err != nil {
return fmt.Errorf("Error waiting to create Brand: %s", err)
}
Expand Down
Loading

0 comments on commit dd9be82

Please sign in to comment.