mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-06-29 06:42:36 +00:00
Generate Pubsub Topics/Subscriptions with MM (+add labels) (#3043)
<!-- This change is generated by MagicModules. --> /cc @drebes
This commit is contained in:
parent
5a4bb8f299
commit
2950923ee6
|
@ -137,6 +137,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) {
|
|||
GeneratedComputeResourcesMap,
|
||||
GeneratedCloudBuildResourcesMap,
|
||||
GeneratedDnsResourcesMap,
|
||||
GeneratedPubsubResourcesMap,
|
||||
GeneratedRedisResourcesMap,
|
||||
GeneratedResourceManagerResourcesMap,
|
||||
GeneratedSourceRepoResourcesMap,
|
||||
|
@ -228,11 +229,9 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) {
|
|||
"google_project_organization_policy": resourceGoogleProjectOrganizationPolicy(),
|
||||
"google_project_usage_export_bucket": resourceProjectUsageBucket(),
|
||||
"google_project_services": resourceGoogleProjectServices(),
|
||||
"google_pubsub_topic": resourcePubsubTopic(),
|
||||
"google_pubsub_topic_iam_binding": ResourceIamBindingWithImport(IamPubsubTopicSchema, NewPubsubTopicIamUpdater, PubsubTopicIdParseFunc),
|
||||
"google_pubsub_topic_iam_member": ResourceIamMemberWithImport(IamPubsubTopicSchema, NewPubsubTopicIamUpdater, PubsubTopicIdParseFunc),
|
||||
"google_pubsub_topic_iam_policy": ResourceIamPolicyWithImport(IamPubsubTopicSchema, NewPubsubTopicIamUpdater, PubsubTopicIdParseFunc),
|
||||
"google_pubsub_subscription": resourcePubsubSubscription(),
|
||||
"google_pubsub_subscription_iam_binding": ResourceIamBindingWithImport(IamPubsubSubscriptionSchema, NewPubsubSubscriptionIamUpdater, PubsubSubscriptionIdParseFunc),
|
||||
"google_pubsub_subscription_iam_member": ResourceIamMemberWithImport(IamPubsubSubscriptionSchema, NewPubsubSubscriptionIamUpdater, PubsubSubscriptionIdParseFunc),
|
||||
"google_pubsub_subscription_iam_policy": ResourceIamPolicyWithImport(IamPubsubSubscriptionSchema, NewPubsubSubscriptionIamUpdater, PubsubSubscriptionIdParseFunc),
|
||||
|
|
22
google/provider_pubsub_gen.go
Normal file
22
google/provider_pubsub_gen.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// *** 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 "github.com/hashicorp/terraform/helper/schema"
|
||||
|
||||
var GeneratedPubsubResourcesMap = map[string]*schema.Resource{
|
||||
"google_pubsub_topic": resourcePubsubTopic(),
|
||||
"google_pubsub_subscription": resourcePubsubSubscription(),
|
||||
}
|
32
google/pubsub_utils.go
Normal file
32
google/pubsub_utils.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func comparePubsubSubscriptionBasename(_, old, new string, _ *schema.ResourceData) bool {
|
||||
if GetResourceNameFromSelfLink(old) == GetResourceNameFromSelfLink(new) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func getComputedSubscriptionName(project, subscription string) string {
|
||||
match, _ := regexp.MatchString("projects\\/.*\\/subscriptions\\/.*", subscription)
|
||||
if match {
|
||||
return subscription
|
||||
}
|
||||
return fmt.Sprintf("projects/%s/subscriptions/%s", project, subscription)
|
||||
}
|
||||
|
||||
func getComputedTopicName(project, topic string) string {
|
||||
match, _ := regexp.MatchString("projects\\/.*\\/topics\\/.*", topic)
|
||||
if match {
|
||||
return topic
|
||||
}
|
||||
return fmt.Sprintf("projects/%s/topics/%s", project, topic)
|
||||
}
|
|
@ -1,11 +1,29 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// *** 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"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/pubsub/v1"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func resourcePubsubSubscription() *schema.Resource {
|
||||
|
@ -16,61 +34,66 @@ func resourcePubsubSubscription() *schema.Resource {
|
|||
Delete: resourcePubsubSubscriptionDelete,
|
||||
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: resourcePubsubSubscriptionStateImporter,
|
||||
State: resourcePubsubSubscriptionImport,
|
||||
},
|
||||
|
||||
Timeouts: &schema.ResourceTimeout{
|
||||
Create: schema.DefaultTimeout(240 * time.Second),
|
||||
Update: schema.DefaultTimeout(240 * time.Second),
|
||||
Delete: schema.DefaultTimeout(240 * time.Second),
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: comparePubsubSubscriptionBasename,
|
||||
},
|
||||
|
||||
"topic": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: compareSelfLinkOrResourceName,
|
||||
},
|
||||
|
||||
"ack_deadline_seconds": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"project": {
|
||||
Type: schema.TypeString,
|
||||
"labels": {
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"path": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"push_config": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
MaxItems: 1,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"push_endpoint": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"attributes": {
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"push_endpoint": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"path": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"project": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -78,74 +101,102 @@ func resourcePubsubSubscription() *schema.Resource {
|
|||
func resourcePubsubSubscriptionCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
obj := make(map[string]interface{})
|
||||
nameProp, err := expandPubsubSubscriptionName(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
|
||||
}
|
||||
topicProp, err := expandPubsubSubscriptionTopic(d.Get("topic"), d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if v, ok := d.GetOkExists("topic"); !isEmptyValue(reflect.ValueOf(topicProp)) && (ok || !reflect.DeepEqual(v, topicProp)) {
|
||||
obj["topic"] = topicProp
|
||||
}
|
||||
labelsProp, err := expandPubsubSubscriptionLabels(d.Get("labels"), d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) {
|
||||
obj["labels"] = labelsProp
|
||||
}
|
||||
pushConfigProp, err := expandPubsubSubscriptionPushConfig(d.Get("push_config"), d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if v, ok := d.GetOkExists("push_config"); !isEmptyValue(reflect.ValueOf(pushConfigProp)) && (ok || !reflect.DeepEqual(v, pushConfigProp)) {
|
||||
obj["pushConfig"] = pushConfigProp
|
||||
}
|
||||
ackDeadlineSecondsProp, err := expandPubsubSubscriptionAckDeadlineSeconds(d.Get("ack_deadline_seconds"), d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if v, ok := d.GetOkExists("ack_deadline_seconds"); !isEmptyValue(reflect.ValueOf(ackDeadlineSecondsProp)) && (ok || !reflect.DeepEqual(v, ackDeadlineSecondsProp)) {
|
||||
obj["ackDeadlineSeconds"] = ackDeadlineSecondsProp
|
||||
}
|
||||
|
||||
url, err := replaceVars(d, config, "https://pubsub.googleapis.com/v1/projects/{{project}}/subscriptions/{{name}}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := getComputedSubscriptionName(project, d.Get("name").(string))
|
||||
computed_topic_name := getComputedTopicName(project, d.Get("topic").(string))
|
||||
|
||||
// process optional parameters
|
||||
var ackDeadlineSeconds int64
|
||||
ackDeadlineSeconds = 10
|
||||
if v, ok := d.GetOk("ack_deadline_seconds"); ok {
|
||||
ackDeadlineSeconds = int64(v.(int))
|
||||
}
|
||||
|
||||
subscription := &pubsub.Subscription{
|
||||
AckDeadlineSeconds: ackDeadlineSeconds,
|
||||
Topic: computed_topic_name,
|
||||
PushConfig: expandPubsubSubscriptionPushConfig(d.Get("push_config").([]interface{})),
|
||||
}
|
||||
|
||||
call := config.clientPubsub.Projects.Subscriptions.Create(name, subscription)
|
||||
res, err := call.Do()
|
||||
log.Printf("[DEBUG] Creating new Subscription: %#v", obj)
|
||||
res, err := sendRequestWithTimeout(config, "PUT", url, obj, d.Timeout(schema.TimeoutCreate))
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Error creating Subscription: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(res.Name)
|
||||
// Store the ID now
|
||||
id, err := replaceVars(d, config, "projects/{{project}}/subscriptions/{{name}}")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error constructing id: %s", err)
|
||||
}
|
||||
d.SetId(id)
|
||||
|
||||
log.Printf("[DEBUG] Finished creating Subscription %q: %#v", d.Id(), res)
|
||||
|
||||
return resourcePubsubSubscriptionRead(d, meta)
|
||||
}
|
||||
|
||||
func getComputedTopicName(project, topic string) string {
|
||||
match, _ := regexp.MatchString("projects\\/.*\\/topics\\/.*", topic)
|
||||
if match {
|
||||
return topic
|
||||
}
|
||||
return fmt.Sprintf("projects/%s/topics/%s", project, topic)
|
||||
}
|
||||
|
||||
func getComputedSubscriptionName(project, subscription string) string {
|
||||
match, _ := regexp.MatchString("projects\\/.*\\/subscriptions\\/.*", subscription)
|
||||
if match {
|
||||
return subscription
|
||||
}
|
||||
return fmt.Sprintf("projects/%s/subscriptions/%s", project, subscription)
|
||||
}
|
||||
|
||||
func resourcePubsubSubscriptionRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
url, err := replaceVars(d, config, "https://pubsub.googleapis.com/v1/projects/{{project}}/subscriptions/{{name}}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := d.Id()
|
||||
subscription, err := config.clientPubsub.Projects.Subscriptions.Get(name).Do()
|
||||
res, err := sendRequest(config, "GET", url, nil)
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Pubsub Subscription %q", name))
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("PubsubSubscription %q", d.Id()))
|
||||
}
|
||||
|
||||
d.Set("name", GetResourceNameFromSelfLink(subscription.Name))
|
||||
d.Set("topic", subscription.Topic)
|
||||
d.Set("ack_deadline_seconds", subscription.AckDeadlineSeconds)
|
||||
d.Set("path", subscription.Name)
|
||||
d.Set("push_config", flattenPubsubSubscriptionPushConfig(subscription.PushConfig))
|
||||
d.Set("project", project)
|
||||
res, err = resourcePubsubSubscriptionDecoder(d, meta, res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("project", project); err != nil {
|
||||
return fmt.Errorf("Error reading Subscription: %s", err)
|
||||
}
|
||||
|
||||
if err := d.Set("name", flattenPubsubSubscriptionName(res["name"], d)); err != nil {
|
||||
return fmt.Errorf("Error reading Subscription: %s", err)
|
||||
}
|
||||
if err := d.Set("topic", flattenPubsubSubscriptionTopic(res["topic"], d)); err != nil {
|
||||
return fmt.Errorf("Error reading Subscription: %s", err)
|
||||
}
|
||||
if err := d.Set("labels", flattenPubsubSubscriptionLabels(res["labels"], d)); err != nil {
|
||||
return fmt.Errorf("Error reading Subscription: %s", err)
|
||||
}
|
||||
if err := d.Set("push_config", flattenPubsubSubscriptionPushConfig(res["pushConfig"], d)); err != nil {
|
||||
return fmt.Errorf("Error reading Subscription: %s", err)
|
||||
}
|
||||
if err := d.Set("ack_deadline_seconds", flattenPubsubSubscriptionAckDeadlineSeconds(res["ackDeadlineSeconds"], d)); err != nil {
|
||||
return fmt.Errorf("Error reading Subscription: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -153,76 +204,259 @@ func resourcePubsubSubscriptionRead(d *schema.ResourceData, meta interface{}) er
|
|||
func resourcePubsubSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
d.Partial(true)
|
||||
|
||||
if d.HasChange("push_config") {
|
||||
_, err := config.clientPubsub.Projects.Subscriptions.ModifyPushConfig(d.Id(), &pubsub.ModifyPushConfigRequest{
|
||||
PushConfig: expandPubsubSubscriptionPushConfig(d.Get("push_config").([]interface{})),
|
||||
}).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating subscription %q: %s", d.Get("name"), err)
|
||||
}
|
||||
obj := make(map[string]interface{})
|
||||
labelsProp, err := expandPubsubSubscriptionLabels(d.Get("labels"), d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) {
|
||||
obj["labels"] = labelsProp
|
||||
}
|
||||
pushConfigProp, err := expandPubsubSubscriptionPushConfig(d.Get("push_config"), d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if v, ok := d.GetOkExists("push_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, pushConfigProp)) {
|
||||
obj["pushConfig"] = pushConfigProp
|
||||
}
|
||||
ackDeadlineSecondsProp, err := expandPubsubSubscriptionAckDeadlineSeconds(d.Get("ack_deadline_seconds"), d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if v, ok := d.GetOkExists("ack_deadline_seconds"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, ackDeadlineSecondsProp)) {
|
||||
obj["ackDeadlineSeconds"] = ackDeadlineSecondsProp
|
||||
}
|
||||
|
||||
d.Partial(false)
|
||||
obj, err = resourcePubsubSubscriptionUpdateEncoder(d, meta, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
url, err := replaceVars(d, config, "https://pubsub.googleapis.com/v1/projects/{{project}}/subscriptions/{{name}}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Updating Subscription %q: %#v", d.Id(), obj)
|
||||
updateMask := []string{}
|
||||
|
||||
if d.HasChange("labels") {
|
||||
updateMask = append(updateMask, "labels")
|
||||
}
|
||||
|
||||
if d.HasChange("push_config") {
|
||||
updateMask = append(updateMask, "pushConfig")
|
||||
}
|
||||
|
||||
if d.HasChange("ack_deadline_seconds") {
|
||||
updateMask = append(updateMask, "ackDeadlineSeconds")
|
||||
}
|
||||
// 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", url, obj, d.Timeout(schema.TimeoutUpdate))
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating Subscription %q: %s", d.Id(), err)
|
||||
}
|
||||
|
||||
return resourcePubsubSubscriptionRead(d, meta)
|
||||
}
|
||||
|
||||
func resourcePubsubSubscriptionDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
name := d.Id()
|
||||
call := config.clientPubsub.Projects.Subscriptions.Delete(name)
|
||||
_, err := call.Do()
|
||||
url, err := replaceVars(d, config, "https://pubsub.googleapis.com/v1/projects/{{project}}/subscriptions/{{name}}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var obj map[string]interface{}
|
||||
log.Printf("[DEBUG] Deleting Subscription %q", d.Id())
|
||||
res, err := sendRequestWithTimeout(config, "DELETE", url, obj, d.Timeout(schema.TimeoutDelete))
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, "Subscription")
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Finished deleting Subscription %q: %#v", d.Id(), res)
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourcePubsubSubscriptionStateImporter(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||
func resourcePubsubSubscriptionImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
if err := parseImportId([]string{"projects/(?P<project>[^/]+)/subscriptions/(?P<name>[^/]+)", "(?P<project>[^/]+)/(?P<name>[^/]+)", "(?P<name>[^/]+)"}, d, config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id := fmt.Sprintf("projects/%s/subscriptions/%s", project, d.Id())
|
||||
|
||||
// Replace import id for the resource id
|
||||
id, err := replaceVars(d, config, "projects/{{project}}/subscriptions/{{name}}")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error constructing id: %s", err)
|
||||
}
|
||||
d.SetId(id)
|
||||
|
||||
return []*schema.ResourceData{d}, nil
|
||||
}
|
||||
|
||||
func flattenPubsubSubscriptionPushConfig(pushConfig *pubsub.PushConfig) []map[string]interface{} {
|
||||
configs := make([]map[string]interface{}, 0, 1)
|
||||
|
||||
if pushConfig == nil || len(pushConfig.PushEndpoint) == 0 {
|
||||
return configs
|
||||
func flattenPubsubSubscriptionName(v interface{}, d *schema.ResourceData) interface{} {
|
||||
if v == nil {
|
||||
return v
|
||||
}
|
||||
|
||||
configs = append(configs, map[string]interface{}{
|
||||
"push_endpoint": pushConfig.PushEndpoint,
|
||||
"attributes": pushConfig.Attributes,
|
||||
})
|
||||
|
||||
return configs
|
||||
return NameFromSelfLinkStateFunc(v)
|
||||
}
|
||||
|
||||
func expandPubsubSubscriptionPushConfig(configured []interface{}) *pubsub.PushConfig {
|
||||
if len(configured) == 0 || configured[0] == nil {
|
||||
// An empty `pushConfig` indicates that the Pub/Sub system should stop pushing messages
|
||||
// from the given subscription and allow messages to be pulled and acknowledged.
|
||||
return &pubsub.PushConfig{}
|
||||
func flattenPubsubSubscriptionTopic(v interface{}, d *schema.ResourceData) interface{} {
|
||||
if v == nil {
|
||||
return v
|
||||
}
|
||||
return ConvertSelfLinkToV1(v.(string))
|
||||
}
|
||||
|
||||
func flattenPubsubSubscriptionLabels(v interface{}, d *schema.ResourceData) interface{} {
|
||||
return v
|
||||
}
|
||||
|
||||
func flattenPubsubSubscriptionPushConfig(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["push_endpoint"] =
|
||||
flattenPubsubSubscriptionPushConfigPushEndpoint(original["pushEndpoint"], d)
|
||||
transformed["attributes"] =
|
||||
flattenPubsubSubscriptionPushConfigAttributes(original["attributes"], d)
|
||||
return []interface{}{transformed}
|
||||
}
|
||||
func flattenPubsubSubscriptionPushConfigPushEndpoint(v interface{}, d *schema.ResourceData) interface{} {
|
||||
return v
|
||||
}
|
||||
|
||||
func flattenPubsubSubscriptionPushConfigAttributes(v interface{}, d *schema.ResourceData) interface{} {
|
||||
return v
|
||||
}
|
||||
|
||||
func flattenPubsubSubscriptionAckDeadlineSeconds(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 expandPubsubSubscriptionName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
pushConfig := configured[0].(map[string]interface{})
|
||||
return &pubsub.PushConfig{
|
||||
PushEndpoint: pushConfig["push_endpoint"].(string),
|
||||
Attributes: convertStringMap(pushConfig["attributes"].(map[string]interface{})),
|
||||
subscription := d.Get("name").(string)
|
||||
|
||||
re := regexp.MustCompile("projects\\/(.*)\\/subscriptions\\/(.*)")
|
||||
match := re.FindStringSubmatch(subscription)
|
||||
if len(match) == 3 {
|
||||
// We need to preserve the behavior where the user passes the subscription name already in the long form,
|
||||
// however we need it to be stored as the short form since it's used for the replaceVars in the URL.
|
||||
// The unintuitive behavior is that if the user provides the long form, we use the project from there, not the one
|
||||
// specified on the resource or provider.
|
||||
// TODO(drebes): consider depracating the long form behavior for 3.0
|
||||
d.Set("project", match[1])
|
||||
d.Set("name", match[2])
|
||||
return subscription, nil
|
||||
}
|
||||
return fmt.Sprintf("projects/%s/subscriptions/%s", project, subscription), nil
|
||||
}
|
||||
|
||||
func expandPubsubSubscriptionTopic(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
topic := d.Get("topic").(string)
|
||||
|
||||
re := regexp.MustCompile("projects\\/(.*)\\/topics\\/(.*)")
|
||||
match := re.FindStringSubmatch(topic)
|
||||
if len(match) == 3 {
|
||||
return topic, nil
|
||||
} else {
|
||||
// If no full topic given, we expand it to a full topic on the same project
|
||||
fullTopic := fmt.Sprintf("projects/%s/topics/%s", project, topic)
|
||||
d.Set("topic", fullTopic)
|
||||
return fullTopic, nil
|
||||
}
|
||||
}
|
||||
|
||||
func expandPubsubSubscriptionLabels(v interface{}, d *schema.ResourceData, config *Config) (map[string]string, error) {
|
||||
if v == nil {
|
||||
return map[string]string{}, nil
|
||||
}
|
||||
m := make(map[string]string)
|
||||
for k, val := range v.(map[string]interface{}) {
|
||||
m[k] = val.(string)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func expandPubsubSubscriptionPushConfig(v interface{}, d *schema.ResourceData, 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{})
|
||||
|
||||
transformedPushEndpoint, err := expandPubsubSubscriptionPushConfigPushEndpoint(original["push_endpoint"], d, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if val := reflect.ValueOf(transformedPushEndpoint); val.IsValid() && !isEmptyValue(val) {
|
||||
transformed["pushEndpoint"] = transformedPushEndpoint
|
||||
}
|
||||
|
||||
transformedAttributes, err := expandPubsubSubscriptionPushConfigAttributes(original["attributes"], d, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if val := reflect.ValueOf(transformedAttributes); val.IsValid() && !isEmptyValue(val) {
|
||||
transformed["attributes"] = transformedAttributes
|
||||
}
|
||||
|
||||
return transformed, nil
|
||||
}
|
||||
|
||||
func expandPubsubSubscriptionPushConfigPushEndpoint(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func expandPubsubSubscriptionPushConfigAttributes(v interface{}, d *schema.ResourceData, config *Config) (map[string]string, error) {
|
||||
if v == nil {
|
||||
return map[string]string{}, nil
|
||||
}
|
||||
m := make(map[string]string)
|
||||
for k, val := range v.(map[string]interface{}) {
|
||||
m[k] = val.(string)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func expandPubsubSubscriptionAckDeadlineSeconds(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func resourcePubsubSubscriptionUpdateEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
|
||||
newObj := make(map[string]interface{})
|
||||
newObj["subscription"] = obj
|
||||
return newObj, nil
|
||||
}
|
||||
|
||||
func resourcePubsubSubscriptionDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) {
|
||||
|
||||
path := fmt.Sprintf("projects/%s/subscriptions/%s", d.Get("project"), d.Get("name"))
|
||||
d.Set("path", path)
|
||||
return res, nil
|
||||
}
|
||||
|
|
93
google/resource_pubsub_subscription_generated_test.go
Normal file
93
google/resource_pubsub_subscription_generated_test.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// *** 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/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccPubsubSubscription_pubsubSubscriptionPullExample(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: testAccCheckPubsubSubscriptionDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccPubsubSubscription_pubsubSubscriptionPullExample(context),
|
||||
},
|
||||
{
|
||||
ResourceName: "google_pubsub_subscription.example",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccPubsubSubscription_pubsubSubscriptionPullExample(context map[string]interface{}) string {
|
||||
return Nprintf(`
|
||||
resource "google_pubsub_topic" "example" {
|
||||
name = "example-topic-%{random_suffix}"
|
||||
}
|
||||
|
||||
resource "google_pubsub_subscription" "example" {
|
||||
name = "example-subscription-%{random_suffix}"
|
||||
topic = "${google_pubsub_topic.example.name}"
|
||||
|
||||
labels = {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
ack_deadline_seconds = 20
|
||||
}
|
||||
`, context)
|
||||
}
|
||||
|
||||
func testAccCheckPubsubSubscriptionDestroy(s *terraform.State) error {
|
||||
for name, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_pubsub_subscription" {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(name, "data.") {
|
||||
continue
|
||||
}
|
||||
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
url, err := replaceVarsForTest(rs, "https://pubsub.googleapis.com/v1/projects/{{project}}/subscriptions/{{name}}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sendRequest(config, "GET", url, nil)
|
||||
if err == nil {
|
||||
return fmt.Errorf("PubsubSubscription still exists at %s", url)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -6,14 +6,13 @@ import (
|
|||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccPubsubSubscription_basic(t *testing.T) {
|
||||
func TestAccPubsubSubscription_fullName(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
topic := fmt.Sprintf("tf-test-topic-%s", acctest.RandString(10))
|
||||
subscription := fmt.Sprintf("tf-test-sub-%s", acctest.RandString(10))
|
||||
subscription := fmt.Sprintf("projects/%s/subscriptions/tf-test-sub-%s", getTestProjectFromEnv(), acctest.RandString(10))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -21,7 +20,7 @@ func TestAccPubsubSubscription_basic(t *testing.T) {
|
|||
CheckDestroy: testAccCheckPubsubSubscriptionDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccPubsubSubscription_basic(topic, subscription),
|
||||
Config: testAccPubsubSubscription_fullName(topic, subscription, "bar", 20),
|
||||
},
|
||||
{
|
||||
ResourceName: "google_pubsub_subscription.foo",
|
||||
|
@ -33,6 +32,55 @@ func TestAccPubsubSubscription_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccPubsubSubscription_update(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
topic := fmt.Sprintf("tf-test-topic-%s", acctest.RandString(10))
|
||||
subscriptionShort := fmt.Sprintf("tf-test-sub-%s", acctest.RandString(10))
|
||||
subscriptionLong := fmt.Sprintf("projects/%s/subscriptions/%s", getTestProjectFromEnv(), subscriptionShort)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckPubsubSubscriptionDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccPubsubSubscription_fullName(topic, subscriptionLong, "bar", 20),
|
||||
},
|
||||
{
|
||||
ResourceName: "google_pubsub_subscription.foo",
|
||||
ImportStateId: subscriptionLong,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
{
|
||||
Config: testAccPubsubSubscription_fullName(topic, subscriptionLong, "baz", 30),
|
||||
Check: resource.TestCheckResourceAttr(
|
||||
"google_pubsub_subscription.foo", "path", subscriptionLong,
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "google_pubsub_subscription.foo",
|
||||
ImportStateId: subscriptionLong,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
{
|
||||
Config: testAccPubsubSubscription_fullName(topic, subscriptionShort, "baz", 30),
|
||||
Check: resource.TestCheckResourceAttr(
|
||||
"google_pubsub_subscription.foo", "path", subscriptionLong,
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "google_pubsub_subscription.foo",
|
||||
ImportStateId: subscriptionShort,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: Add acceptance test for push delivery.
|
||||
//
|
||||
// Testing push endpoints is tricky for the following reason:
|
||||
|
@ -45,23 +93,8 @@ func TestAccPubsubSubscription_basic(t *testing.T) {
|
|||
// An easy way to test this would be to create an App Engine Hello World app. With AppEngine, SSL certificate, DNS and domain registry is handled for us.
|
||||
// App Engine is not yet supported by Terraform but once it is, it will provide an easy path to testing push configs.
|
||||
// Another option would be to use Cloud Functions once Terraform support is added.
|
||||
func testAccCheckPubsubSubscriptionDestroy(s *terraform.State) error {
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_pubsub_subscription" {
|
||||
continue
|
||||
}
|
||||
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
sub, _ := config.clientPubsub.Projects.Subscriptions.Get(rs.Primary.ID).Do()
|
||||
if sub != nil {
|
||||
return fmt.Errorf("Subscription still present")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccPubsubSubscription_basic(topic, subscription string) string {
|
||||
func testAccPubsubSubscription_fullName(topic, subscription, label string, deadline int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_pubsub_topic" "foo" {
|
||||
name = "%s"
|
||||
|
@ -69,9 +102,12 @@ resource "google_pubsub_topic" "foo" {
|
|||
|
||||
resource "google_pubsub_subscription" "foo" {
|
||||
name = "%s"
|
||||
topic = "${google_pubsub_topic.foo.name}"
|
||||
ack_deadline_seconds = 20
|
||||
}`, topic, subscription)
|
||||
topic = "${google_pubsub_topic.foo.id}"
|
||||
labels = {
|
||||
foo = "%s"
|
||||
}
|
||||
ack_deadline_seconds = %d
|
||||
}`, topic, subscription, label, deadline)
|
||||
}
|
||||
|
||||
func TestGetComputedTopicName(t *testing.T) {
|
||||
|
|
|
@ -1,11 +1,26 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// *** 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"
|
||||
"regexp"
|
||||
"log"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/pubsub/v1"
|
||||
)
|
||||
|
||||
func resourcePubsubTopic() *schema.Resource {
|
||||
|
@ -15,7 +30,12 @@ func resourcePubsubTopic() *schema.Resource {
|
|||
Delete: resourcePubsubTopicDelete,
|
||||
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: resourcePubsubTopicStateImporter,
|
||||
State: resourcePubsubTopicImport,
|
||||
},
|
||||
|
||||
Timeouts: &schema.ResourceTimeout{
|
||||
Create: schema.DefaultTimeout(240 * time.Second),
|
||||
Delete: schema.DefaultTimeout(240 * time.Second),
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
|
@ -23,9 +43,14 @@ func resourcePubsubTopic() *schema.Resource {
|
|||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: linkDiffSuppress,
|
||||
DiffSuppressFunc: compareSelfLinkOrResourceName,
|
||||
},
|
||||
"labels": {
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"project": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
|
@ -39,21 +64,39 @@ func resourcePubsubTopic() *schema.Resource {
|
|||
func resourcePubsubTopicCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
obj := make(map[string]interface{})
|
||||
nameProp, err := expandPubsubTopicName(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
|
||||
}
|
||||
labelsProp, err := expandPubsubTopicLabels(d.Get("labels"), d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) {
|
||||
obj["labels"] = labelsProp
|
||||
}
|
||||
|
||||
url, err := replaceVars(d, config, "https://pubsub.googleapis.com/v1/projects/{{project}}/topics/{{name}}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("projects/%s/topics/%s", project, d.Get("name").(string))
|
||||
topic := &pubsub.Topic{}
|
||||
|
||||
call := config.clientPubsub.Projects.Topics.Create(name, topic)
|
||||
res, err := call.Do()
|
||||
log.Printf("[DEBUG] Creating new Topic: %#v", obj)
|
||||
res, err := sendRequestWithTimeout(config, "PUT", url, obj, d.Timeout(schema.TimeoutCreate))
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Error creating Topic: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(res.Name)
|
||||
// Store the ID now
|
||||
id, err := replaceVars(d, config, "projects/{{project}}/topics/{{name}}")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error constructing id: %s", err)
|
||||
}
|
||||
d.SetId(id)
|
||||
|
||||
log.Printf("[DEBUG] Finished creating Topic %q: %#v", d.Id(), res)
|
||||
|
||||
return resourcePubsubTopicRead(d, meta)
|
||||
}
|
||||
|
@ -61,20 +104,30 @@ func resourcePubsubTopicCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
func resourcePubsubTopicRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
url, err := replaceVars(d, config, "https://pubsub.googleapis.com/v1/projects/{{project}}/topics/{{name}}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := d.Id()
|
||||
call := config.clientPubsub.Projects.Topics.Get(name)
|
||||
res, err := call.Do()
|
||||
res, err := sendRequest(config, "GET", url, nil)
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Pubsub Topic %q", name))
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("PubsubTopic %q", d.Id()))
|
||||
}
|
||||
|
||||
d.Set("name", GetResourceNameFromSelfLink(res.Name))
|
||||
d.Set("project", project)
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("project", project); err != nil {
|
||||
return fmt.Errorf("Error reading Topic: %s", err)
|
||||
}
|
||||
|
||||
if err := d.Set("name", flattenPubsubTopicName(res["name"], d)); err != nil {
|
||||
return fmt.Errorf("Error reading Topic: %s", err)
|
||||
}
|
||||
if err := d.Set("labels", flattenPubsubTopicLabels(res["labels"], d)); err != nil {
|
||||
return fmt.Errorf("Error reading Topic: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -82,31 +135,60 @@ func resourcePubsubTopicRead(d *schema.ResourceData, meta interface{}) error {
|
|||
func resourcePubsubTopicDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
name := d.Id()
|
||||
call := config.clientPubsub.Projects.Topics.Delete(name)
|
||||
_, err := call.Do()
|
||||
url, err := replaceVars(d, config, "https://pubsub.googleapis.com/v1/projects/{{project}}/topics/{{name}}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var obj map[string]interface{}
|
||||
log.Printf("[DEBUG] Deleting Topic %q", d.Id())
|
||||
res, err := sendRequestWithTimeout(config, "DELETE", url, obj, d.Timeout(schema.TimeoutDelete))
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, "Topic")
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Finished deleting Topic %q: %#v", d.Id(), res)
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourcePubsubTopicStateImporter(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||
func resourcePubsubTopicImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||
config := meta.(*Config)
|
||||
|
||||
topicId := regexp.MustCompile("^projects/[^/]+/topics/[^/]+$")
|
||||
if topicId.MatchString(d.Id()) {
|
||||
return []*schema.ResourceData{d}, nil
|
||||
if err := parseImportId([]string{"projects/(?P<project>[^/]+)/topics/(?P<name>[^/]+)", "(?P<project>[^/]+)/(?P<name>[^/]+)", "(?P<name>[^/]+)"}, d, config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config.Project == "" {
|
||||
return nil, fmt.Errorf("The default project for the provider must be set when using the `{name}` id format.")
|
||||
// Replace import id for the resource id
|
||||
id, err := replaceVars(d, config, "projects/{{project}}/topics/{{name}}")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error constructing id: %s", err)
|
||||
}
|
||||
|
||||
id := fmt.Sprintf("projects/%s/topics/%s", config.Project, d.Id())
|
||||
|
||||
d.SetId(id)
|
||||
|
||||
return []*schema.ResourceData{d}, nil
|
||||
}
|
||||
|
||||
func flattenPubsubTopicName(v interface{}, d *schema.ResourceData) interface{} {
|
||||
if v == nil {
|
||||
return v
|
||||
}
|
||||
return NameFromSelfLinkStateFunc(v)
|
||||
}
|
||||
|
||||
func flattenPubsubTopicLabels(v interface{}, d *schema.ResourceData) interface{} {
|
||||
return v
|
||||
}
|
||||
|
||||
func expandPubsubTopicName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
|
||||
return GetResourceNameFromSelfLink(v.(string)), nil
|
||||
}
|
||||
|
||||
func expandPubsubTopicLabels(v interface{}, d *schema.ResourceData, config *Config) (map[string]string, error) {
|
||||
if v == nil {
|
||||
return map[string]string{}, nil
|
||||
}
|
||||
m := make(map[string]string)
|
||||
for k, val := range v.(map[string]interface{}) {
|
||||
m[k] = val.(string)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
|
86
google/resource_pubsub_topic_generated_test.go
Normal file
86
google/resource_pubsub_topic_generated_test.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// *** 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/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccPubsubTopic_pubsubTopicBasicExample(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: testAccCheckPubsubTopicDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccPubsubTopic_pubsubTopicBasicExample(context),
|
||||
},
|
||||
{
|
||||
ResourceName: "google_pubsub_topic.example",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccPubsubTopic_pubsubTopicBasicExample(context map[string]interface{}) string {
|
||||
return Nprintf(`
|
||||
resource "google_pubsub_topic" "example" {
|
||||
name = "example-topic-%{random_suffix}"
|
||||
|
||||
labels = {
|
||||
foo = "bar"
|
||||
}
|
||||
}
|
||||
`, context)
|
||||
}
|
||||
|
||||
func testAccCheckPubsubTopicDestroy(s *terraform.State) error {
|
||||
for name, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_pubsub_topic" {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(name, "data.") {
|
||||
continue
|
||||
}
|
||||
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
url, err := replaceVarsForTest(rs, "https://pubsub.googleapis.com/v1/projects/{{project}}/topics/{{name}}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sendRequest(config, "GET", url, nil)
|
||||
if err == nil {
|
||||
return fmt.Errorf("PubsubTopic still exists at %s", url)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccPubsubTopic_basic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
topicName := acctest.RandomWithPrefix("tf-test-topic")
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckPubsubTopicDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccPubsubTopic_basic(topicName),
|
||||
},
|
||||
// Check importing with just the topic name
|
||||
{
|
||||
ResourceName: "google_pubsub_topic.foo",
|
||||
ImportStateId: topicName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
ImportStateVerifyIgnore: []string{"force_destroy"},
|
||||
},
|
||||
// Check importing with the full resource id
|
||||
{
|
||||
ResourceName: "google_pubsub_topic.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
ImportStateVerifyIgnore: []string{"force_destroy"},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckPubsubTopicDestroy(s *terraform.State) error {
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_pubsub_topic" {
|
||||
continue
|
||||
}
|
||||
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
topic, _ := config.clientPubsub.Projects.Topics.Get(rs.Primary.ID).Do()
|
||||
if topic != nil {
|
||||
return fmt.Errorf("Topic still present")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccPubsubTopic_basic(name string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_pubsub_topic" "foo" {
|
||||
name = "%s"
|
||||
}`, name)
|
||||
}
|
|
@ -1,52 +1,101 @@
|
|||
---
|
||||
# ----------------------------------------------------------------------------
|
||||
#
|
||||
# *** 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_pubsub_subscription"
|
||||
sidebar_current: "docs-google-pubsub-subscription-x"
|
||||
sidebar_current: "docs-google-pubsub-subscription"
|
||||
description: |-
|
||||
Creates a subscription in Google's pubsub queueing system
|
||||
A named resource representing the stream of messages from a single,
|
||||
specific topic, to be delivered to the subscribing application.
|
||||
---
|
||||
|
||||
# google\_pubsub\_subscription
|
||||
|
||||
Creates a subscription in Google's pubsub queueing system. For more information see
|
||||
[the official documentation](https://cloud.google.com/pubsub/docs) and
|
||||
[API](https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions).
|
||||
A named resource representing the stream of messages from a single,
|
||||
specific topic, to be delivered to the subscribing application.
|
||||
|
||||
|
||||
## Example Usage
|
||||
To get more information about Subscription, see:
|
||||
|
||||
* [API documentation](https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions)
|
||||
* How-to Guides
|
||||
* [Managing Subscriptions](https://cloud.google.com/pubsub/docs/admin#managing_subscriptions)
|
||||
|
||||
## Example Usage - Pubsub Subscription Push
|
||||
|
||||
|
||||
```hcl
|
||||
resource "google_pubsub_topic" "default-topic" {
|
||||
name = "default-topic"
|
||||
resource "google_pubsub_topic" "example" {
|
||||
name = "example-topic"
|
||||
}
|
||||
|
||||
resource "google_pubsub_subscription" "default" {
|
||||
name = "default-subscription"
|
||||
topic = "${google_pubsub_topic.default-topic.name}"
|
||||
resource "google_pubsub_subscription" "example" {
|
||||
name = "example-subscription"
|
||||
topic = "${google_pubsub_topic.example.name}"
|
||||
|
||||
ack_deadline_seconds = 20
|
||||
|
||||
labels = {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
push_config {
|
||||
push_endpoint = "https://example.com/push"
|
||||
|
||||
attributes = {
|
||||
attributes {
|
||||
x-goog-version = "v1"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
<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=pubsub_subscription_pull&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 - Pubsub Subscription Pull
|
||||
|
||||
If the subscription has a topic in a different project:
|
||||
|
||||
```hcl
|
||||
resource "google_pubsub_topic" "topic-different-project" {
|
||||
project = "another-project"
|
||||
name = "topic-different-project"
|
||||
resource "google_pubsub_topic" "example" {
|
||||
name = "example-topic"
|
||||
}
|
||||
|
||||
resource "google_pubsub_subscription" "default" {
|
||||
name = "default-subscription"
|
||||
topic = "${google_pubsub_topic.topic-different-project.id}"
|
||||
resource "google_pubsub_subscription" "example" {
|
||||
name = "example-subscription"
|
||||
topic = "${google_pubsub_topic.example.name}"
|
||||
|
||||
labels = {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
ack_deadline_seconds = 20
|
||||
}
|
||||
```
|
||||
## Example Usage - Pubsub Subscription Different Project
|
||||
|
||||
|
||||
```hcl
|
||||
resource "google_pubsub_topic" "example" {
|
||||
project = "topic-project"
|
||||
name = "example-topic"
|
||||
}
|
||||
|
||||
resource "google_pubsub_subscription" "example" {
|
||||
project = "subscription-project"
|
||||
name = "example-subscription"
|
||||
topic = "${google_pubsub_topic.example.id}"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -54,45 +103,105 @@ resource "google_pubsub_subscription" "default" {
|
|||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) A unique name for the resource, required by pubsub.
|
||||
Changing this forces a new resource to be created.
|
||||
|
||||
* `topic` - (Required) The topic name or id to bind this subscription to, required by pubsub.
|
||||
Changing this forces a new resource to be created.
|
||||
* `name` -
|
||||
(Required)
|
||||
Name of the subscription.
|
||||
|
||||
* `topic` -
|
||||
(Required)
|
||||
A reference to a Topic resource.
|
||||
|
||||
|
||||
- - -
|
||||
|
||||
* `ack_deadline_seconds` - (Optional) The maximum number of seconds a
|
||||
subscriber has to acknowledge a received message, otherwise the message is
|
||||
redelivered. Changing this forces a new resource to be created.
|
||||
|
||||
* `project` - (Optional) The ID of the project in which the resource belongs. If it
|
||||
is not provided, the provider project is used.
|
||||
* `labels` -
|
||||
(Optional)
|
||||
A set of key/value label pairs to assign to this Subscription.
|
||||
|
||||
* `push_config` - (Optional) Block configuration for push options. More
|
||||
configuration options are detailed below.
|
||||
* `push_config` -
|
||||
(Optional)
|
||||
If push delivery is used with this subscription, this field is used to
|
||||
configure it. An empty pushConfig signifies that the subscriber will
|
||||
pull and ack messages using API methods. Structure is documented below.
|
||||
|
||||
The optional `push_config` block supports:
|
||||
* `ack_deadline_seconds` -
|
||||
(Optional)
|
||||
This value is the maximum time after a subscriber receives a message
|
||||
before the subscriber should acknowledge the message. After message
|
||||
delivery but before the ack deadline expires and before the message is
|
||||
acknowledged, it is an outstanding message and will not be delivered
|
||||
again during that time (on a best-effort basis).
|
||||
For pull subscriptions, this value is used as the initial value for
|
||||
the ack deadline. To override this value for a given message, call
|
||||
subscriptions.modifyAckDeadline with the corresponding ackId if using
|
||||
pull. The minimum custom deadline you can specify is 10 seconds. The
|
||||
maximum custom deadline you can specify is 600 seconds (10 minutes).
|
||||
If this parameter is 0, a default value of 10 seconds is used.
|
||||
For push delivery, this value is also used to set the request timeout
|
||||
for the call to the push endpoint.
|
||||
If the subscriber never acknowledges the message, the Pub/Sub system
|
||||
will eventually redeliver the message.
|
||||
* `project` - (Optional) The ID of the project in which the resource belongs.
|
||||
If it is not provided, the provider project is used.
|
||||
|
||||
* `push_endpoint` - (Required) The URL of the endpoint to which messages should
|
||||
be pushed. Changing this forces a new resource to be created.
|
||||
|
||||
* `attributes` - (Optional) Key-value pairs of API supported attributes used
|
||||
to control aspects of the message delivery. Currently, only
|
||||
`x-goog-version` is supported, which controls the format of the data
|
||||
delivery. For more information, read [the API docs
|
||||
here](https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions#PushConfig.FIELDS.attributes).
|
||||
Changing this forces a new resource to be created.
|
||||
The `push_config` block supports:
|
||||
|
||||
* `push_endpoint` -
|
||||
(Required)
|
||||
A URL locating the endpoint to which messages should be pushed.
|
||||
For example, a Webhook endpoint might use
|
||||
"https://example.com/push".
|
||||
|
||||
* `attributes` -
|
||||
(Optional)
|
||||
Endpoint configuration attributes.
|
||||
Every endpoint has a set of API supported attributes that can
|
||||
be used to control different aspects of the message delivery.
|
||||
The currently supported attribute is x-goog-version, which you
|
||||
can use to change the format of the pushed message. This
|
||||
attribute indicates the version of the data expected by
|
||||
the endpoint. This controls the shape of the pushed message
|
||||
(i.e., its fields and metadata). The endpoint version is
|
||||
based on the version of the Pub/Sub API.
|
||||
If not present during the subscriptions.create call,
|
||||
it will default to the version of the API used to make
|
||||
such call. If not present during a subscriptions.modifyPushConfig
|
||||
call, its value will not be changed. subscriptions.get
|
||||
calls will always return a valid version, even if the
|
||||
subscription was created without this attribute.
|
||||
The possible values for this attribute are:
|
||||
- v1beta1: uses the push format defined in the v1beta1 Pub/Sub API.
|
||||
- v1 or v1beta2: uses the push format defined in the v1 Pub/Sub API.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
* `path` - Path of the subscription in the format `projects/{project}/subscriptions/{sub}`
|
||||
In addition to the arguments listed above, the following computed attributes are exported:
|
||||
|
||||
|
||||
|
||||
* `path`: Path of the subscription in the format `projects/{project}/subscriptions/{name}`
|
||||
|
||||
## 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
|
||||
|
||||
Pubsub subscription can be imported using the `name`, e.g.
|
||||
Subscription can be imported using any of these accepted formats:
|
||||
|
||||
```
|
||||
$ terraform import google_pubsub_subscription.default default-subscription
|
||||
$ terraform import google_pubsub_subscription.default projects/{{project}}/subscriptions/{{name}}
|
||||
$ terraform import google_pubsub_subscription.default {{project}}/{{name}}
|
||||
$ terraform import google_pubsub_subscription.default {{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.
|
||||
|
|
|
@ -1,23 +1,50 @@
|
|||
---
|
||||
# ----------------------------------------------------------------------------
|
||||
#
|
||||
# *** 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_pubsub_topic"
|
||||
sidebar_current: "docs-google-pubsub-topic-x"
|
||||
sidebar_current: "docs-google-pubsub-topic"
|
||||
description: |-
|
||||
Creates a topic in Google's pubsub queueing system
|
||||
A named resource to which messages are sent by publishers.
|
||||
---
|
||||
|
||||
# google\_pubsub\_topic
|
||||
|
||||
Creates a topic in Google's pubsub queueing system. For more information see
|
||||
[the official documentation](https://cloud.google.com/pubsub/docs) and
|
||||
[API](https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics).
|
||||
A named resource to which messages are sent by publishers.
|
||||
|
||||
|
||||
## Example Usage
|
||||
To get more information about Topic, see:
|
||||
|
||||
* [API documentation](https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics)
|
||||
* How-to Guides
|
||||
* [Managing Topics](https://cloud.google.com/pubsub/docs/admin#managing_topics)
|
||||
|
||||
<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=pubsub_topic_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 - Pubsub Topic Basic
|
||||
|
||||
|
||||
```hcl
|
||||
resource "google_pubsub_topic" "mytopic" {
|
||||
name = "default-topic"
|
||||
resource "google_pubsub_topic" "example" {
|
||||
name = "example-topic"
|
||||
|
||||
labels = {
|
||||
foo = "bar"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -25,26 +52,40 @@ resource "google_pubsub_topic" "mytopic" {
|
|||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) A unique name for the pubsub topic.
|
||||
Changing this forces a new resource to be created.
|
||||
|
||||
* `name` -
|
||||
(Required)
|
||||
Name of the topic.
|
||||
|
||||
|
||||
- - -
|
||||
|
||||
* `project` - (Optional) The ID of the project in which the resource belongs. If it
|
||||
is not provided, the provider project is used.
|
||||
|
||||
## Attributes Reference
|
||||
* `labels` -
|
||||
(Optional)
|
||||
A set of key/value label pairs to assign to this Topic.
|
||||
* `project` - (Optional) The ID of the project in which the resource belongs.
|
||||
If it is not provided, the provider project is used.
|
||||
|
||||
Only the arguments listed above are exposed as attributes.
|
||||
|
||||
|
||||
## Timeouts
|
||||
|
||||
This resource provides the following
|
||||
[Timeouts](/docs/configuration/resources.html#timeouts) configuration options:
|
||||
|
||||
- `create` - Default is 4 minutes.
|
||||
- `delete` - Default is 4 minutes.
|
||||
|
||||
## Import
|
||||
|
||||
Pubsub topics can be imported using the `name` or full topic id, e.g.
|
||||
Topic can be imported using any of these accepted formats:
|
||||
|
||||
```
|
||||
$ terraform import google_pubsub_topic.mytopic default-topic
|
||||
$ terraform import google_pubsub_topic.default projects/{{project}}/topics/{{name}}
|
||||
$ terraform import google_pubsub_topic.default {{project}}/{{name}}
|
||||
$ terraform import google_pubsub_topic.default {{name}}
|
||||
```
|
||||
```
|
||||
$ terraform import google_pubsub_topic.mytopic projects/my-gcp-project/topics/default-topic
|
||||
```
|
||||
When importing using only the name, the provider project must be set.
|
||||
|
||||
-> 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.
|
||||
|
|
Loading…
Reference in New Issue
Block a user