From ea5c82e42ad1fac56f69f864d734467efe32e6b7 Mon Sep 17 00:00:00 2001 From: Ty Larrabee Date: Wed, 13 Nov 2019 01:13:48 +0000 Subject: [PATCH] Add CloudTasksQueue resource Signed-off-by: Modular Magician --- google-beta/config.go | 3 + google-beta/provider.go | 14 +- google-beta/resource_cloud_tasks_queue.go | 711 ++++++++++++++++++ ...source_cloud_tasks_queue_generated_test.go | 83 ++ .../resource_cloud_tasks_queue_test.go | 141 ++++ .../docs/r/cloud_tasks_queue.html.markdown | 190 +++++ 6 files changed, 1140 insertions(+), 2 deletions(-) create mode 100644 google-beta/resource_cloud_tasks_queue.go create mode 100644 google-beta/resource_cloud_tasks_queue_generated_test.go create mode 100644 google-beta/resource_cloud_tasks_queue_test.go create mode 100644 website/docs/r/cloud_tasks_queue.html.markdown diff --git a/google-beta/config.go b/google-beta/config.go index 6482b197e8..cf152c7aad 100644 --- a/google-beta/config.go +++ b/google-beta/config.go @@ -82,6 +82,7 @@ type Config struct { CloudFunctionsBasePath string CloudRunBasePath string CloudSchedulerBasePath string + CloudTasksBasePath string ComputeBasePath string ContainerAnalysisBasePath string DataFusionBasePath string @@ -219,6 +220,7 @@ var CloudBuildDefaultBasePath = "https://cloudbuild.googleapis.com/v1/" var CloudFunctionsDefaultBasePath = "https://cloudfunctions.googleapis.com/v1/" var CloudRunDefaultBasePath = "https://run.googleapis.com/v1alpha1/" var CloudSchedulerDefaultBasePath = "https://cloudscheduler.googleapis.com/v1/" +var CloudTasksDefaultBasePath = "https://cloudtasks.googleapis.com/v2/" var ComputeDefaultBasePath = "https://www.googleapis.com/compute/beta/" var ContainerAnalysisDefaultBasePath = "https://containeranalysis.googleapis.com/v1beta1/" var DataFusionDefaultBasePath = "https://datafusion.googleapis.com/v1beta1/" @@ -708,6 +710,7 @@ func ConfigureBasePaths(c *Config) { c.CloudFunctionsBasePath = CloudFunctionsDefaultBasePath c.CloudRunBasePath = CloudRunDefaultBasePath c.CloudSchedulerBasePath = CloudSchedulerDefaultBasePath + c.CloudTasksBasePath = CloudTasksDefaultBasePath c.ComputeBasePath = ComputeDefaultBasePath c.ContainerAnalysisBasePath = ContainerAnalysisDefaultBasePath c.DataFusionBasePath = DataFusionDefaultBasePath diff --git a/google-beta/provider.go b/google-beta/provider.go index 88bf7ecf5c..a590f26973 100644 --- a/google-beta/provider.go +++ b/google-beta/provider.go @@ -183,6 +183,14 @@ func Provider() terraform.ResourceProvider { "GOOGLE_CLOUD_SCHEDULER_CUSTOM_ENDPOINT", }, CloudSchedulerDefaultBasePath), }, + "cloud_tasks_custom_endpoint": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateCustomEndpoint, + DefaultFunc: schema.MultiEnvDefaultFunc([]string{ + "GOOGLE_CLOUD_TASKS_CUSTOM_ENDPOINT", + }, CloudTasksDefaultBasePath), + }, "compute_custom_endpoint": { Type: schema.TypeString, Optional: true, @@ -482,9 +490,9 @@ func Provider() terraform.ResourceProvider { return provider } -// Generated resources: 100 +// Generated resources: 101 // Generated IAM resources: 39 -// Total generated resources: 139 +// Total generated resources: 140 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -515,6 +523,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_cloud_run_domain_mapping": resourceCloudRunDomainMapping(), "google_cloud_run_service": resourceCloudRunService(), "google_cloud_scheduler_job": resourceCloudSchedulerJob(), + "google_cloud_tasks_queue": resourceCloudTasksQueue(), "google_compute_address": resourceComputeAddress(), "google_compute_autoscaler": resourceComputeAutoscaler(), "google_compute_backend_bucket": resourceComputeBackendBucket(), @@ -804,6 +813,7 @@ func providerConfigure(d *schema.ResourceData, terraformVersion string) (interfa config.CloudFunctionsBasePath = d.Get("cloud_functions_custom_endpoint").(string) config.CloudRunBasePath = d.Get("cloud_run_custom_endpoint").(string) config.CloudSchedulerBasePath = d.Get("cloud_scheduler_custom_endpoint").(string) + config.CloudTasksBasePath = d.Get("cloud_tasks_custom_endpoint").(string) config.ComputeBasePath = d.Get("compute_custom_endpoint").(string) config.ContainerAnalysisBasePath = d.Get("container_analysis_custom_endpoint").(string) config.DataFusionBasePath = d.Get("data_fusion_custom_endpoint").(string) diff --git a/google-beta/resource_cloud_tasks_queue.go b/google-beta/resource_cloud_tasks_queue.go new file mode 100644 index 0000000000..c887a1d9eb --- /dev/null +++ b/google-beta/resource_cloud_tasks_queue.go @@ -0,0 +1,711 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "strconv" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceCloudTasksQueue() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudTasksQueueCreate, + Read: resourceCloudTasksQueueRead, + Update: resourceCloudTasksQueueUpdate, + Delete: resourceCloudTasksQueueDelete, + + Importer: &schema.ResourceImporter{ + State: resourceCloudTasksQueueImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Update: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The location of the queue`, + }, + "app_engine_routing_override": { + Type: schema.TypeList, + Optional: true, + Description: `Overrides for task-level appEngineRouting. These settings apply only +to App Engine tasks in this queue`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance": { + Type: schema.TypeString, + Optional: true, + Description: `App instance. + +By default, the task is sent to an instance which is available when the task is attempted.`, + }, + "service": { + Type: schema.TypeString, + Optional: true, + Description: `App service. + +By default, the task is sent to the service which is the default service when the task is attempted.`, + }, + "version": { + Type: schema.TypeString, + Optional: true, + Description: `App version. + +By default, the task is sent to the version which is the default version when the task is attempted.`, + }, + "host": { + Type: schema.TypeString, + Computed: true, + Description: `The host that the task is sent to.`, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `The queue name.`, + }, + "rate_limits": { + Type: schema.TypeList, + Computed: true, + Optional: true, + Description: `Rate limits for task dispatches. + +The queue's actual dispatch rate is the result of: + +* Number of tasks in the queue +* User-specified throttling: rateLimits, retryConfig, and the queue's state. +* System throttling due to 429 (Too Many Requests) or 503 (Service + Unavailable) responses from the worker, high error rates, or to + smooth sudden large traffic spikes.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max_concurrent_dispatches": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + Description: `The maximum number of concurrent tasks that Cloud Tasks allows to +be dispatched for this queue. After this threshold has been +reached, Cloud Tasks stops dispatching tasks until the number of +concurrent requests decreases.`, + }, + "max_dispatches_per_second": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + Description: `The maximum rate at which tasks are dispatched from this queue. + +If unspecified when the queue is created, Cloud Tasks will pick the default.`, + }, + "max_burst_size": { + Type: schema.TypeInt, + Computed: true, + Description: `The max burst size. + +Max burst size limits how fast tasks in queue are processed when many tasks are +in the queue and the rate is high. This field allows the queue to have a high +rate so processing starts shortly after a task is enqueued, but still limits +resource usage when many tasks are enqueued in a short period of time.`, + }, + }, + }, + }, + "retry_config": { + Type: schema.TypeList, + Computed: true, + Optional: true, + Description: `Settings that determine the retry behavior.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max_attempts": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + Description: `Number of attempts per task. + +Cloud Tasks will attempt the task maxAttempts times (that is, if +the first attempt fails, then there will be maxAttempts - 1 +retries). Must be >= -1. + +If unspecified when the queue is created, Cloud Tasks will pick +the default. + +-1 indicates unlimited attempts.`, + }, + "max_backoff": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: `A task will be scheduled for retry between minBackoff and +maxBackoff duration after it fails, if the queue's RetryConfig +specifies that the task should be retried.`, + }, + "max_doublings": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + Description: `The time between retries will double maxDoublings times. + +A task's retry interval starts at minBackoff, then doubles maxDoublings times, +then increases linearly, and finally retries retries at intervals of maxBackoff +up to maxAttempts times.`, + }, + "max_retry_duration": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: `If positive, maxRetryDuration specifies the time limit for +retrying a failed task, measured from when the task was first +attempted. Once maxRetryDuration time has passed and the task has +been attempted maxAttempts times, no further attempts will be +made and the task will be deleted. + +If zero, then the task age is unlimited.`, + }, + "min_backoff": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: `A task will be scheduled for retry between minBackoff and +maxBackoff duration after it fails, if the queue's RetryConfig +specifies that the task should be retried.`, + }, + }, + }, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceCloudTasksQueueCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandCloudTasksQueueName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + appEngineRoutingOverrideProp, err := expandCloudTasksQueueAppEngineRoutingOverride(d.Get("app_engine_routing_override"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("app_engine_routing_override"); !isEmptyValue(reflect.ValueOf(appEngineRoutingOverrideProp)) && (ok || !reflect.DeepEqual(v, appEngineRoutingOverrideProp)) { + obj["appEngineRoutingOverride"] = appEngineRoutingOverrideProp + } + rateLimitsProp, err := expandCloudTasksQueueRateLimits(d.Get("rate_limits"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("rate_limits"); !isEmptyValue(reflect.ValueOf(rateLimitsProp)) && (ok || !reflect.DeepEqual(v, rateLimitsProp)) { + obj["rateLimits"] = rateLimitsProp + } + retryConfigProp, err := expandCloudTasksQueueRetryConfig(d.Get("retry_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("retry_config"); !isEmptyValue(reflect.ValueOf(retryConfigProp)) && (ok || !reflect.DeepEqual(v, retryConfigProp)) { + obj["retryConfig"] = retryConfigProp + } + + url, err := replaceVars(d, config, "{{CloudTasksBasePath}}projects/{{project}}/locations/{{location}}/queues") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Queue: %#v", obj) + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequestWithTimeout(config, "POST", project, url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating Queue: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "projects/{{project}}/locations/{{location}}/queues/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating Queue %q: %#v", d.Id(), res) + + return resourceCloudTasksQueueRead(d, meta) +} + +func resourceCloudTasksQueueRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "{{CloudTasksBasePath}}projects/{{project}}/locations/{{location}}/queues/{{name}}") + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequest(config, "GET", project, url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("CloudTasksQueue %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Queue: %s", err) + } + + if err := d.Set("name", flattenCloudTasksQueueName(res["name"], d)); err != nil { + return fmt.Errorf("Error reading Queue: %s", err) + } + if err := d.Set("app_engine_routing_override", flattenCloudTasksQueueAppEngineRoutingOverride(res["appEngineRoutingOverride"], d)); err != nil { + return fmt.Errorf("Error reading Queue: %s", err) + } + if err := d.Set("rate_limits", flattenCloudTasksQueueRateLimits(res["rateLimits"], d)); err != nil { + return fmt.Errorf("Error reading Queue: %s", err) + } + if err := d.Set("retry_config", flattenCloudTasksQueueRetryConfig(res["retryConfig"], d)); err != nil { + return fmt.Errorf("Error reading Queue: %s", err) + } + + return nil +} + +func resourceCloudTasksQueueUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + appEngineRoutingOverrideProp, err := expandCloudTasksQueueAppEngineRoutingOverride(d.Get("app_engine_routing_override"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("app_engine_routing_override"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, appEngineRoutingOverrideProp)) { + obj["appEngineRoutingOverride"] = appEngineRoutingOverrideProp + } + rateLimitsProp, err := expandCloudTasksQueueRateLimits(d.Get("rate_limits"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("rate_limits"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, rateLimitsProp)) { + obj["rateLimits"] = rateLimitsProp + } + retryConfigProp, err := expandCloudTasksQueueRetryConfig(d.Get("retry_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("retry_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, retryConfigProp)) { + obj["retryConfig"] = retryConfigProp + } + + url, err := replaceVars(d, config, "{{CloudTasksBasePath}}projects/{{project}}/locations/{{location}}/queues/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Queue %q: %#v", d.Id(), obj) + updateMask := []string{} + + if d.HasChange("app_engine_routing_override") { + updateMask = append(updateMask, "appEngineRoutingOverride") + } + + if d.HasChange("rate_limits") { + updateMask = append(updateMask, "rateLimits") + } + + if d.HasChange("retry_config") { + updateMask = append(updateMask, "retryConfig") + } + // updateMask is a URL parameter but not present in the schema, so replaceVars + // won't set it + url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + _, err = sendRequestWithTimeout(config, "PATCH", project, url, obj, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("Error updating Queue %q: %s", d.Id(), err) + } + + return resourceCloudTasksQueueRead(d, meta) +} + +func resourceCloudTasksQueueDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{CloudTasksBasePath}}projects/{{project}}/locations/{{location}}/queues/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting Queue %q", d.Id()) + + res, err := sendRequestWithTimeout(config, "DELETE", project, url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "Queue") + } + + log.Printf("[DEBUG] Finished deleting Queue %q: %#v", d.Id(), res) + return nil +} + +func resourceCloudTasksQueueImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)/locations/(?P[^/]+)/queues/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "projects/{{project}}/locations/{{location}}/queues/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenCloudTasksQueueName(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return NameFromSelfLinkStateFunc(v) +} + +// service, version, and instance are input-only. host is output-only. +func flattenCloudTasksQueueAppEngineRoutingOverride(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["host"] = original["host"] + if override, ok := d.GetOk("app_engine_routing_override"); ok && len(override.([]interface{})) > 0 { + transformed["service"] = d.Get("app_engine_routing_override.0.service") + transformed["version"] = d.Get("app_engine_routing_override.0.version") + transformed["instance"] = d.Get("app_engine_routing_override.0.instance") + } + return []interface{}{transformed} +} + +func flattenCloudTasksQueueRateLimits(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["max_dispatches_per_second"] = + flattenCloudTasksQueueRateLimitsMaxDispatchesPerSecond(original["maxDispatchesPerSecond"], d) + transformed["max_concurrent_dispatches"] = + flattenCloudTasksQueueRateLimitsMaxConcurrentDispatches(original["maxConcurrentDispatches"], d) + transformed["max_burst_size"] = + flattenCloudTasksQueueRateLimitsMaxBurstSize(original["maxBurstSize"], d) + return []interface{}{transformed} +} +func flattenCloudTasksQueueRateLimitsMaxDispatchesPerSecond(v interface{}, d *schema.ResourceData) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenCloudTasksQueueRateLimitsMaxConcurrentDispatches(v interface{}, d *schema.ResourceData) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenCloudTasksQueueRateLimitsMaxBurstSize(v interface{}, d *schema.ResourceData) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenCloudTasksQueueRetryConfig(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["max_attempts"] = + flattenCloudTasksQueueRetryConfigMaxAttempts(original["maxAttempts"], d) + transformed["max_retry_duration"] = + flattenCloudTasksQueueRetryConfigMaxRetryDuration(original["maxRetryDuration"], d) + transformed["min_backoff"] = + flattenCloudTasksQueueRetryConfigMinBackoff(original["minBackoff"], d) + transformed["max_backoff"] = + flattenCloudTasksQueueRetryConfigMaxBackoff(original["maxBackoff"], d) + transformed["max_doublings"] = + flattenCloudTasksQueueRetryConfigMaxDoublings(original["maxDoublings"], d) + return []interface{}{transformed} +} +func flattenCloudTasksQueueRetryConfigMaxAttempts(v interface{}, d *schema.ResourceData) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenCloudTasksQueueRetryConfigMaxRetryDuration(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudTasksQueueRetryConfigMinBackoff(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudTasksQueueRetryConfigMaxBackoff(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudTasksQueueRetryConfigMaxDoublings(v interface{}, d *schema.ResourceData) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func expandCloudTasksQueueName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return replaceVars(d, config, "projects/{{project}}/locations/{{location}}/queues/{{name}}") +} + +func expandCloudTasksQueueAppEngineRoutingOverride(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedService, err := expandCloudTasksQueueAppEngineRoutingOverrideService(original["service"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedService); val.IsValid() && !isEmptyValue(val) { + transformed["service"] = transformedService + } + + transformedVersion, err := expandCloudTasksQueueAppEngineRoutingOverrideVersion(original["version"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedVersion); val.IsValid() && !isEmptyValue(val) { + transformed["version"] = transformedVersion + } + + transformedInstance, err := expandCloudTasksQueueAppEngineRoutingOverrideInstance(original["instance"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedInstance); val.IsValid() && !isEmptyValue(val) { + transformed["instance"] = transformedInstance + } + + transformedHost, err := expandCloudTasksQueueAppEngineRoutingOverrideHost(original["host"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHost); val.IsValid() && !isEmptyValue(val) { + transformed["host"] = transformedHost + } + + return transformed, nil +} + +func expandCloudTasksQueueAppEngineRoutingOverrideService(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueAppEngineRoutingOverrideVersion(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueAppEngineRoutingOverrideInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueAppEngineRoutingOverrideHost(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueRateLimits(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedMaxDispatchesPerSecond, err := expandCloudTasksQueueRateLimitsMaxDispatchesPerSecond(original["max_dispatches_per_second"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxDispatchesPerSecond); val.IsValid() && !isEmptyValue(val) { + transformed["maxDispatchesPerSecond"] = transformedMaxDispatchesPerSecond + } + + transformedMaxConcurrentDispatches, err := expandCloudTasksQueueRateLimitsMaxConcurrentDispatches(original["max_concurrent_dispatches"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxConcurrentDispatches); val.IsValid() && !isEmptyValue(val) { + transformed["maxConcurrentDispatches"] = transformedMaxConcurrentDispatches + } + + transformedMaxBurstSize, err := expandCloudTasksQueueRateLimitsMaxBurstSize(original["max_burst_size"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxBurstSize); val.IsValid() && !isEmptyValue(val) { + transformed["maxBurstSize"] = transformedMaxBurstSize + } + + return transformed, nil +} + +func expandCloudTasksQueueRateLimitsMaxDispatchesPerSecond(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueRateLimitsMaxConcurrentDispatches(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueRateLimitsMaxBurstSize(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueRetryConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedMaxAttempts, err := expandCloudTasksQueueRetryConfigMaxAttempts(original["max_attempts"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxAttempts); val.IsValid() && !isEmptyValue(val) { + transformed["maxAttempts"] = transformedMaxAttempts + } + + transformedMaxRetryDuration, err := expandCloudTasksQueueRetryConfigMaxRetryDuration(original["max_retry_duration"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxRetryDuration); val.IsValid() && !isEmptyValue(val) { + transformed["maxRetryDuration"] = transformedMaxRetryDuration + } + + transformedMinBackoff, err := expandCloudTasksQueueRetryConfigMinBackoff(original["min_backoff"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMinBackoff); val.IsValid() && !isEmptyValue(val) { + transformed["minBackoff"] = transformedMinBackoff + } + + transformedMaxBackoff, err := expandCloudTasksQueueRetryConfigMaxBackoff(original["max_backoff"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxBackoff); val.IsValid() && !isEmptyValue(val) { + transformed["maxBackoff"] = transformedMaxBackoff + } + + transformedMaxDoublings, err := expandCloudTasksQueueRetryConfigMaxDoublings(original["max_doublings"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxDoublings); val.IsValid() && !isEmptyValue(val) { + transformed["maxDoublings"] = transformedMaxDoublings + } + + return transformed, nil +} + +func expandCloudTasksQueueRetryConfigMaxAttempts(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueRetryConfigMaxRetryDuration(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueRetryConfigMinBackoff(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueRetryConfigMaxBackoff(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudTasksQueueRetryConfigMaxDoublings(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google-beta/resource_cloud_tasks_queue_generated_test.go b/google-beta/resource_cloud_tasks_queue_generated_test.go new file mode 100644 index 0000000000..a835fb39ce --- /dev/null +++ b/google-beta/resource_cloud_tasks_queue_generated_test.go @@ -0,0 +1,83 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccCloudTasksQueue_queueBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudTasksQueueDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCloudTasksQueue_queueBasicExample(context), + }, + { + ResourceName: "google_cloud_tasks_queue.default", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCloudTasksQueue_queueBasicExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_cloud_tasks_queue" "default" { + name = "cloud-tasks-queue-test%{random_suffix}" + location = "us-central1" +} +`, context) +} + +func testAccCheckCloudTasksQueueDestroy(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_cloud_tasks_queue" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := testAccProvider.Meta().(*Config) + + url, err := replaceVarsForTest(config, rs, "{{CloudTasksBasePath}}projects/{{project}}/locations/{{location}}/queues/{{name}}") + if err != nil { + return err + } + + _, err = sendRequest(config, "GET", "", url, nil) + if err == nil { + return fmt.Errorf("CloudTasksQueue still exists at %s", url) + } + } + + return nil +} diff --git a/google-beta/resource_cloud_tasks_queue_test.go b/google-beta/resource_cloud_tasks_queue_test.go new file mode 100644 index 0000000000..4f14e5ff02 --- /dev/null +++ b/google-beta/resource_cloud_tasks_queue_test.go @@ -0,0 +1,141 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccCloudTasksQueue_update(t *testing.T) { + t.Parallel() + + name := "cloudtasksqueuetest-" + acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudTasksQueue_full(name), + }, + { + ResourceName: "google_cloud_tasks_queue.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_engine_routing_override.0.service", "app_engine_routing_override.0.version", "app_engine_routing_override.0.instance"}, + }, + { + Config: testAccCloudTasksQueue_update(name), + }, + { + ResourceName: "google_cloud_tasks_queue.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_engine_routing_override.0.service", "app_engine_routing_override.0.version", "app_engine_routing_override.0.instance"}, + }, + }, + }) +} + +func TestAccCloudTasksQueue_update2Basic(t *testing.T) { + t.Parallel() + + name := "cloudtasksqueuetest-" + acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudTasksQueue_full(name), + }, + { + ResourceName: "google_cloud_tasks_queue.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_engine_routing_override.0.service", "app_engine_routing_override.0.version", "app_engine_routing_override.0.instance"}, + }, + { + Config: testAccCloudTasksQueue_basic(name), + }, + { + ResourceName: "google_cloud_tasks_queue.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_engine_routing_override.0.service", "app_engine_routing_override.0.version", "app_engine_routing_override.0.instance"}, + }, + }, + }) +} + +func testAccCloudTasksQueue_basic(name string) string { + return fmt.Sprintf(` +resource "google_cloud_tasks_queue" "default" { + name = "%s" + location = "us-central1" + + retry_config { + max_attempts = 5 + } + +} +`, name) +} + +func testAccCloudTasksQueue_full(name string) string { + return fmt.Sprintf(` +resource "google_cloud_tasks_queue" "default" { + name = "%s" + location = "us-central1" + + app_engine_routing_override { + service = "worker" + version = "1.0" + instance = "test" + } + + rate_limits { + max_concurrent_dispatches = 3 + max_dispatches_per_second = 2 + } + + retry_config { + max_attempts = 5 + max_retry_duration = "4s" + max_backoff = "3s" + min_backoff = "2s" + max_doublings = 1 + } +} +`, name) +} + +func testAccCloudTasksQueue_update(name string) string { + return fmt.Sprintf(` +resource "google_cloud_tasks_queue" "default" { + name = "%s" + location = "us-central1" + + app_engine_routing_override { + service = "main" + version = "2.0" + instance = "beta" + } + + rate_limits { + max_concurrent_dispatches = 4 + max_dispatches_per_second = 3 + } + + retry_config { + max_attempts = 6 + max_retry_duration = "5s" + max_backoff = "4s" + min_backoff = "3s" + max_doublings = 2 + } +} +`, name) +} diff --git a/website/docs/r/cloud_tasks_queue.html.markdown b/website/docs/r/cloud_tasks_queue.html.markdown new file mode 100644 index 0000000000..8d70a0e823 --- /dev/null +++ b/website/docs/r/cloud_tasks_queue.html.markdown @@ -0,0 +1,190 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** 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. +# +# ---------------------------------------------------------------------------- +subcategory: "Cloud Tasks" +layout: "google" +page_title: "Google: google_cloud_tasks_queue" +sidebar_current: "docs-google-cloud-tasks-queue" +description: |- + A named resource to which messages are sent by publishers. +--- + +# google\_cloud\_tasks\_queue + +A named resource to which messages are sent by publishers. + + + + +## Example Usage - Queue Basic + + +```hcl +resource "google_cloud_tasks_queue" "default" { + name = "cloud-tasks-queue-test" + location = "us-central1" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `location` - + (Required) + The location of the queue + + +- - - + + +* `name` - + (Optional) + The queue name. + +* `app_engine_routing_override` - + (Optional) + Overrides for task-level appEngineRouting. These settings apply only + to App Engine tasks in this queue Structure is documented below. + +* `rate_limits` - + (Optional) + Rate limits for task dispatches. + The queue's actual dispatch rate is the result of: + * Number of tasks in the queue + * User-specified throttling: rateLimits, retryConfig, and the queue's state. + * System throttling due to 429 (Too Many Requests) or 503 (Service + Unavailable) responses from the worker, high error rates, or to + smooth sudden large traffic spikes. Structure is documented below. + +* `retry_config` - + (Optional) + Settings that determine the retry behavior. Structure is documented below. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +The `app_engine_routing_override` block supports: + +* `service` - + (Optional) + App service. + By default, the task is sent to the service which is the default service when the task is attempted. + +* `version` - + (Optional) + App version. + By default, the task is sent to the version which is the default version when the task is attempted. + +* `instance` - + (Optional) + App instance. + By default, the task is sent to an instance which is available when the task is attempted. + +* `host` - + The host that the task is sent to. + +The `rate_limits` block supports: + +* `max_dispatches_per_second` - + (Optional) + The maximum rate at which tasks are dispatched from this queue. + If unspecified when the queue is created, Cloud Tasks will pick the default. + +* `max_concurrent_dispatches` - + (Optional) + The maximum number of concurrent tasks that Cloud Tasks allows to + be dispatched for this queue. After this threshold has been + reached, Cloud Tasks stops dispatching tasks until the number of + concurrent requests decreases. + +* `max_burst_size` - + The max burst size. + Max burst size limits how fast tasks in queue are processed when many tasks are + in the queue and the rate is high. This field allows the queue to have a high + rate so processing starts shortly after a task is enqueued, but still limits + resource usage when many tasks are enqueued in a short period of time. + +The `retry_config` block supports: + +* `max_attempts` - + (Optional) + Number of attempts per task. + Cloud Tasks will attempt the task maxAttempts times (that is, if + the first attempt fails, then there will be maxAttempts - 1 + retries). Must be >= -1. + If unspecified when the queue is created, Cloud Tasks will pick + the default. + -1 indicates unlimited attempts. + +* `max_retry_duration` - + (Optional) + If positive, maxRetryDuration specifies the time limit for + retrying a failed task, measured from when the task was first + attempted. Once maxRetryDuration time has passed and the task has + been attempted maxAttempts times, no further attempts will be + made and the task will be deleted. + If zero, then the task age is unlimited. + +* `min_backoff` - + (Optional) + A task will be scheduled for retry between minBackoff and + maxBackoff duration after it fails, if the queue's RetryConfig + specifies that the task should be retried. + +* `max_backoff` - + (Optional) + A task will be scheduled for retry between minBackoff and + maxBackoff duration after it fails, if the queue's RetryConfig + specifies that the task should be retried. + +* `max_doublings` - + (Optional) + The time between retries will double maxDoublings times. + A task's retry interval starts at minBackoff, then doubles maxDoublings times, + then increases linearly, and finally retries retries at intervals of maxBackoff + up to maxAttempts times. + + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + +Queue can be imported using any of these accepted formats: + +``` +$ terraform import google_cloud_tasks_queue.default projects/{{project}}/locations/{{location}}/queues/{{name}} +$ terraform import google_cloud_tasks_queue.default {{project}}/{{location}}/{{name}} +$ terraform import google_cloud_tasks_queue.default {{location}}/{{name}} +``` + +-> If you're importing a resource with beta features, make sure to include `-provider=google-beta` +as an argument so that Terraform uses the correct provider to import your resource. + +## User Project Overrides + +This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override).