diff --git a/.changelog/6617.txt b/.changelog/6617.txt
new file mode 100644
index 0000000000..e3972ecc59
--- /dev/null
+++ b/.changelog/6617.txt
@@ -0,0 +1,3 @@
+```release-note:new-resource
+
+```
diff --git a/.github/BREAKING_CHANGES.md b/.github/BREAKING_CHANGES.md
index 084bfa57f6..0ac9c2a1da 100644
--- a/.github/BREAKING_CHANGES.md
+++ b/.github/BREAKING_CHANGES.md
@@ -1,3 +1,15 @@
+---
+# ----------------------------------------------------------------------------
+#
+# *** AUTO GENERATED CODE *** Type: breaking-change-detector ***
+#
+# ----------------------------------------------------------------------------
+#
+# This file is managed by Magic Modules (https:#github.com/GoogleCloudPlatform/magic-modules)
+# Changes will need to be made to the breaking-change-detector within Magic Modules instead of here.
+#
+# ----------------------------------------------------------------------------
+---
# Breaking Changes and Provider Development
@@ -27,22 +39,23 @@ go into the four categories and rules therein.
### Resource Inventory Level Breakages
-Resource/datasource naming conventions and entry differences.
-
Removing or Renaming an resource
+* Resource/datasource naming conventions and entry differences.
-* In terraform resources should be retained whenever possible. A removable of an resource will result in a configuration breakage wherever a dependency on that resource exists. Renaming or Removing a resources are functionally equivalent in terms of configuration breakages.
+ Removing or Renaming an Resource
+In terraform resources should be retained whenever possible. A removable of an resource will result in a configuration breakage wherever a dependency on that resource exists. Renaming or Removing a resources are functionally equivalent in terms of configuration breakages.
### Resource Level Breakages
-Individual resource breakages like field entry removals or behavior within a resource.
- Removing or Renaming an field
+* Individual resource breakages like field entry removals or behavior within a resource.
-* In terraform fields should be retained whenever possible. A removable of an field will result in a configuration breakage wherever a dependency on that field exists. Renaming or Removing a field are functionally equivalent in terms of configuration breakages.
+ Removing or Renaming an field
+In terraform fields should be retained whenever possible. A removable of an field will result in a configuration breakage wherever a dependency on that field exists. Renaming or Removing a field are functionally equivalent in terms of configuration breakages.
### Field Level Breakages
-Field level conventions like attribute changes and naming conventions.
- Optional to Required Field
+* Field level conventions like attribute changes and naming conventions.
+
+ Field becoming Required Field
+A field cannot become required as existing terraform modules may not have this field defined. Thus breaking their modules in sequential plan or applies.
-* A field cannot go from optional to required as existing terraform modules may not have this field defined. Thus breaking their modules in sequential plan or applies.
diff --git a/google/cloud_ids_operation.go b/google/cloud_ids_operation.go
new file mode 100644
index 0000000000..5569445bea
--- /dev/null
+++ b/google/cloud_ids_operation.go
@@ -0,0 +1,75 @@
+// ----------------------------------------------------------------------------
+//
+// *** AUTO GENERATED CODE *** Type: MMv1 ***
+//
+// ----------------------------------------------------------------------------
+//
+// 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 (
+ "encoding/json"
+ "fmt"
+ "time"
+)
+
+type CloudIdsOperationWaiter struct {
+ Config *Config
+ UserAgent string
+ Project string
+ CommonOperationWaiter
+}
+
+func (w *CloudIdsOperationWaiter) QueryOp() (interface{}, error) {
+ if w == nil {
+ return nil, fmt.Errorf("Cannot query operation, it's unset or nil.")
+ }
+ // Returns the proper get.
+ url := fmt.Sprintf("%s%s", w.Config.CloudIdsBasePath, w.CommonOperationWaiter.Op.Name)
+
+ return sendRequest(w.Config, "GET", w.Project, url, w.UserAgent, nil)
+}
+
+func createCloudIdsWaiter(config *Config, op map[string]interface{}, project, activity, userAgent string) (*CloudIdsOperationWaiter, error) {
+ w := &CloudIdsOperationWaiter{
+ Config: config,
+ UserAgent: userAgent,
+ Project: project,
+ }
+ if err := w.CommonOperationWaiter.SetOp(op); err != nil {
+ return nil, err
+ }
+ return w, nil
+}
+
+// nolint: deadcode,unused
+func cloudIdsOperationWaitTimeWithResponse(config *Config, op map[string]interface{}, response *map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error {
+ w, err := createCloudIdsWaiter(config, op, project, activity, userAgent)
+ if err != nil {
+ return err
+ }
+ if err := OperationWait(w, activity, timeout, config.PollInterval); err != nil {
+ return err
+ }
+ return json.Unmarshal([]byte(w.CommonOperationWaiter.Op.Response), response)
+}
+
+func cloudIdsOperationWaitTime(config *Config, op map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error {
+ if val, ok := op["name"]; !ok || val == "" {
+ // This was a synchronous call - there is no operation to wait for.
+ return nil
+ }
+ w, err := createCloudIdsWaiter(config, op, project, activity, userAgent)
+ if err != nil {
+ // If w is nil, the op was synchronous.
+ return err
+ }
+ return OperationWait(w, activity, timeout, config.PollInterval)
+}
diff --git a/google/config.go b/google/config.go
index ec207be4e5..3ccdeb9fab 100644
--- a/google/config.go
+++ b/google/config.go
@@ -190,6 +190,7 @@ type Config struct {
CloudFunctionsBasePath string
Cloudfunctions2BasePath string
CloudIdentityBasePath string
+ CloudIdsBasePath string
CloudIotBasePath string
CloudRunBasePath string
CloudSchedulerBasePath string
@@ -285,6 +286,7 @@ const CloudBuildBasePathKey = "CloudBuild"
const CloudFunctionsBasePathKey = "CloudFunctions"
const Cloudfunctions2BasePathKey = "Cloudfunctions2"
const CloudIdentityBasePathKey = "CloudIdentity"
+const CloudIdsBasePathKey = "CloudIds"
const CloudIotBasePathKey = "CloudIot"
const CloudRunBasePathKey = "CloudRun"
const CloudSchedulerBasePathKey = "CloudScheduler"
@@ -374,6 +376,7 @@ var DefaultBasePaths = map[string]string{
CloudFunctionsBasePathKey: "https://cloudfunctions.googleapis.com/v1/",
Cloudfunctions2BasePathKey: "https://cloudfunctions.googleapis.com/v2/",
CloudIdentityBasePathKey: "https://cloudidentity.googleapis.com/v1/",
+ CloudIdsBasePathKey: "https://ids.googleapis.com/v1/",
CloudIotBasePathKey: "https://cloudiot.googleapis.com/v1/",
CloudRunBasePathKey: "https://{{location}}-run.googleapis.com/",
CloudSchedulerBasePathKey: "https://cloudscheduler.googleapis.com/v1/",
@@ -1225,6 +1228,7 @@ func ConfigureBasePaths(c *Config) {
c.CloudFunctionsBasePath = DefaultBasePaths[CloudFunctionsBasePathKey]
c.Cloudfunctions2BasePath = DefaultBasePaths[Cloudfunctions2BasePathKey]
c.CloudIdentityBasePath = DefaultBasePaths[CloudIdentityBasePathKey]
+ c.CloudIdsBasePath = DefaultBasePaths[CloudIdsBasePathKey]
c.CloudIotBasePath = DefaultBasePaths[CloudIotBasePathKey]
c.CloudRunBasePath = DefaultBasePaths[CloudRunBasePathKey]
c.CloudSchedulerBasePath = DefaultBasePaths[CloudSchedulerBasePathKey]
diff --git a/google/provider.go b/google/provider.go
index d4a063ced6..1a6c4312a7 100644
--- a/google/provider.go
+++ b/google/provider.go
@@ -301,6 +301,14 @@ func Provider() *schema.Provider {
"GOOGLE_CLOUD_IDENTITY_CUSTOM_ENDPOINT",
}, DefaultBasePaths[CloudIdentityBasePathKey]),
},
+ "cloud_ids_custom_endpoint": {
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateFunc: validateCustomEndpoint,
+ DefaultFunc: schema.MultiEnvDefaultFunc([]string{
+ "GOOGLE_CLOUD_IDS_CUSTOM_ENDPOINT",
+ }, DefaultBasePaths[CloudIdsBasePathKey]),
+ },
"cloud_iot_custom_endpoint": {
Type: schema.TypeString,
Optional: true,
@@ -892,9 +900,9 @@ func Provider() *schema.Provider {
return provider
}
-// Generated resources: 235
+// Generated resources: 236
// Generated IAM resources: 138
-// Total generated resources: 373
+// Total generated resources: 374
func ResourceMap() map[string]*schema.Resource {
resourceMap, _ := ResourceMapWithErrors()
return resourceMap
@@ -978,6 +986,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) {
"google_cloudfunctions2_function_iam_policy": ResourceIamPolicy(Cloudfunctions2functionIamSchema, Cloudfunctions2functionIamUpdaterProducer, Cloudfunctions2functionIdParseFunc),
"google_cloud_identity_group": resourceCloudIdentityGroup(),
"google_cloud_identity_group_membership": resourceCloudIdentityGroupMembership(),
+ "google_cloud_ids_endpoint": resourceCloudIdsEndpoint(),
"google_cloudiot_registry": resourceCloudIotDeviceRegistry(),
"google_cloudiot_registry_iam_binding": ResourceIamBinding(CloudIotDeviceRegistryIamSchema, CloudIotDeviceRegistryIamUpdaterProducer, CloudIotDeviceRegistryIdParseFunc),
"google_cloudiot_registry_iam_member": ResourceIamMember(CloudIotDeviceRegistryIamSchema, CloudIotDeviceRegistryIamUpdaterProducer, CloudIotDeviceRegistryIdParseFunc),
@@ -1509,6 +1518,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr
config.CloudFunctionsBasePath = d.Get("cloud_functions_custom_endpoint").(string)
config.Cloudfunctions2BasePath = d.Get("cloudfunctions2_custom_endpoint").(string)
config.CloudIdentityBasePath = d.Get("cloud_identity_custom_endpoint").(string)
+ config.CloudIdsBasePath = d.Get("cloud_ids_custom_endpoint").(string)
config.CloudIotBasePath = d.Get("cloud_iot_custom_endpoint").(string)
config.CloudRunBasePath = d.Get("cloud_run_custom_endpoint").(string)
config.CloudSchedulerBasePath = d.Get("cloud_scheduler_custom_endpoint").(string)
diff --git a/google/resource_cloud_ids_endpoint.go b/google/resource_cloud_ids_endpoint.go
new file mode 100644
index 0000000000..c855a519b2
--- /dev/null
+++ b/google/resource_cloud_ids_endpoint.go
@@ -0,0 +1,373 @@
+// ----------------------------------------------------------------------------
+//
+// *** AUTO GENERATED CODE *** Type: MMv1 ***
+//
+// ----------------------------------------------------------------------------
+//
+// 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"
+ "time"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func resourceCloudIdsEndpoint() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceCloudIdsEndpointCreate,
+ Read: resourceCloudIdsEndpointRead,
+ Delete: resourceCloudIdsEndpointDelete,
+
+ Importer: &schema.ResourceImporter{
+ State: resourceCloudIdsEndpointImport,
+ },
+
+ Timeouts: &schema.ResourceTimeout{
+ Create: schema.DefaultTimeout(20 * time.Minute),
+ Delete: schema.DefaultTimeout(20 * time.Minute),
+ },
+
+ Schema: map[string]*schema.Schema{
+ "location": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: `The location for the endpoint.`,
+ },
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: `Name of the endpoint in the format projects/{project_id}/locations/{locationId}/endpoints/{endpointId}.`,
+ },
+ "network": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: `Name of the VPC network that is connected to the IDS endpoint. This can either contain the VPC network name itself (like "src-net") or the full URL to the network (like "projects/{project_id}/global/networks/src-net").`,
+ },
+ "severity": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ ValidateFunc: validateEnum([]string{"INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL"}),
+ Description: `The minimum alert severity level that is reported by the endpoint. Possible values: ["INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL"]`,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: `An optional description of the endpoint.`,
+ },
+ "create_time": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `Creation timestamp in RFC 3339 text format.`,
+ },
+ "endpoint": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `Internal IP address of the endpoint's network entry point.`,
+ },
+ "endpoint_forwarding_rule": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `URL of the endpoint's network address to which traffic is to be sent by Packet Mirroring.`,
+ },
+ "update_time": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `Last update timestamp in RFC 3339 text format.`,
+ },
+ "project": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ForceNew: true,
+ },
+ },
+ UseJSONNumber: true,
+ }
+}
+
+func resourceCloudIdsEndpointCreate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+ userAgent, err := generateUserAgentString(d, config.userAgent)
+ if err != nil {
+ return err
+ }
+
+ obj := make(map[string]interface{})
+ nameProp, err := expandCloudIdsEndpointName(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
+ }
+ networkProp, err := expandCloudIdsEndpointNetwork(d.Get("network"), d, config)
+ if err != nil {
+ return err
+ } else if v, ok := d.GetOkExists("network"); !isEmptyValue(reflect.ValueOf(networkProp)) && (ok || !reflect.DeepEqual(v, networkProp)) {
+ obj["network"] = networkProp
+ }
+ descriptionProp, err := expandCloudIdsEndpointDescription(d.Get("description"), d, config)
+ if err != nil {
+ return err
+ } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
+ obj["description"] = descriptionProp
+ }
+ severityProp, err := expandCloudIdsEndpointSeverity(d.Get("severity"), d, config)
+ if err != nil {
+ return err
+ } else if v, ok := d.GetOkExists("severity"); !isEmptyValue(reflect.ValueOf(severityProp)) && (ok || !reflect.DeepEqual(v, severityProp)) {
+ obj["severity"] = severityProp
+ }
+
+ url, err := replaceVars(d, config, "{{CloudIdsBasePath}}projects/{{project}}/locations/{{location}}/endpoints?endpointId={{name}}")
+ if err != nil {
+ return err
+ }
+
+ log.Printf("[DEBUG] Creating new Endpoint: %#v", obj)
+ billingProject := ""
+
+ project, err := getProject(d, config)
+ if err != nil {
+ return fmt.Errorf("Error fetching project for Endpoint: %s", err)
+ }
+ billingProject = project
+
+ // err == nil indicates that the billing_project value was found
+ if bp, err := getBillingProject(d, config); err == nil {
+ billingProject = bp
+ }
+
+ res, err := sendRequestWithTimeout(config, "POST", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutCreate))
+ if err != nil {
+ return fmt.Errorf("Error creating Endpoint: %s", err)
+ }
+
+ // Store the ID now
+ id, err := replaceVars(d, config, "projects/{{project}}/locations/{{location}}/endpoints/{{name}}")
+ if err != nil {
+ return fmt.Errorf("Error constructing id: %s", err)
+ }
+ d.SetId(id)
+
+ // Use the resource in the operation response to populate
+ // identity fields and d.Id() before read
+ var opRes map[string]interface{}
+ err = cloudIdsOperationWaitTimeWithResponse(
+ config, res, &opRes, project, "Creating Endpoint", userAgent,
+ d.Timeout(schema.TimeoutCreate))
+ if err != nil {
+ // The resource didn't actually create
+ d.SetId("")
+
+ return fmt.Errorf("Error waiting to create Endpoint: %s", err)
+ }
+
+ if err := d.Set("name", flattenCloudIdsEndpointName(opRes["name"], d, config)); err != nil {
+ return err
+ }
+
+ // This may have caused the ID to update - update it if so.
+ id, err = replaceVars(d, config, "projects/{{project}}/locations/{{location}}/endpoints/{{name}}")
+ if err != nil {
+ return fmt.Errorf("Error constructing id: %s", err)
+ }
+ d.SetId(id)
+
+ log.Printf("[DEBUG] Finished creating Endpoint %q: %#v", d.Id(), res)
+
+ return resourceCloudIdsEndpointRead(d, meta)
+}
+
+func resourceCloudIdsEndpointRead(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+ userAgent, err := generateUserAgentString(d, config.userAgent)
+ if err != nil {
+ return err
+ }
+
+ url, err := replaceVars(d, config, "{{CloudIdsBasePath}}projects/{{project}}/locations/{{location}}/endpoints/{{name}}")
+ if err != nil {
+ return err
+ }
+
+ billingProject := ""
+
+ project, err := getProject(d, config)
+ if err != nil {
+ return fmt.Errorf("Error fetching project for Endpoint: %s", err)
+ }
+ billingProject = project
+
+ // err == nil indicates that the billing_project value was found
+ if bp, err := getBillingProject(d, config); err == nil {
+ billingProject = bp
+ }
+
+ res, err := sendRequest(config, "GET", billingProject, url, userAgent, nil)
+ if err != nil {
+ return handleNotFoundError(err, d, fmt.Sprintf("CloudIdsEndpoint %q", d.Id()))
+ }
+
+ if err := d.Set("project", project); err != nil {
+ return fmt.Errorf("Error reading Endpoint: %s", err)
+ }
+
+ if err := d.Set("name", flattenCloudIdsEndpointName(res["name"], d, config)); err != nil {
+ return fmt.Errorf("Error reading Endpoint: %s", err)
+ }
+ if err := d.Set("create_time", flattenCloudIdsEndpointCreateTime(res["createTime"], d, config)); err != nil {
+ return fmt.Errorf("Error reading Endpoint: %s", err)
+ }
+ if err := d.Set("update_time", flattenCloudIdsEndpointUpdateTime(res["updateTime"], d, config)); err != nil {
+ return fmt.Errorf("Error reading Endpoint: %s", err)
+ }
+ if err := d.Set("network", flattenCloudIdsEndpointNetwork(res["network"], d, config)); err != nil {
+ return fmt.Errorf("Error reading Endpoint: %s", err)
+ }
+ if err := d.Set("description", flattenCloudIdsEndpointDescription(res["description"], d, config)); err != nil {
+ return fmt.Errorf("Error reading Endpoint: %s", err)
+ }
+ if err := d.Set("endpoint_forwarding_rule", flattenCloudIdsEndpointEndpointForwardingRule(res["endpoint_forwarding_rule"], d, config)); err != nil {
+ return fmt.Errorf("Error reading Endpoint: %s", err)
+ }
+ if err := d.Set("endpoint", flattenCloudIdsEndpointEndpoint(res["endpoint"], d, config)); err != nil {
+ return fmt.Errorf("Error reading Endpoint: %s", err)
+ }
+ if err := d.Set("severity", flattenCloudIdsEndpointSeverity(res["severity"], d, config)); err != nil {
+ return fmt.Errorf("Error reading Endpoint: %s", err)
+ }
+
+ return nil
+}
+
+func resourceCloudIdsEndpointDelete(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+ userAgent, err := generateUserAgentString(d, config.userAgent)
+ if err != nil {
+ return err
+ }
+
+ billingProject := ""
+
+ project, err := getProject(d, config)
+ if err != nil {
+ return fmt.Errorf("Error fetching project for Endpoint: %s", err)
+ }
+ billingProject = project
+
+ url, err := replaceVars(d, config, "{{CloudIdsBasePath}}projects/{{project}}/locations/{{location}}/endpoints/{{name}}")
+ if err != nil {
+ return err
+ }
+
+ var obj map[string]interface{}
+ log.Printf("[DEBUG] Deleting Endpoint %q", d.Id())
+
+ // err == nil indicates that the billing_project value was found
+ if bp, err := getBillingProject(d, config); err == nil {
+ billingProject = bp
+ }
+
+ res, err := sendRequestWithTimeout(config, "DELETE", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutDelete))
+ if err != nil {
+ return handleNotFoundError(err, d, "Endpoint")
+ }
+
+ err = cloudIdsOperationWaitTime(
+ config, res, project, "Deleting Endpoint", userAgent,
+ d.Timeout(schema.TimeoutDelete))
+
+ if err != nil {
+ return err
+ }
+
+ log.Printf("[DEBUG] Finished deleting Endpoint %q: %#v", d.Id(), res)
+ return nil
+}
+
+func resourceCloudIdsEndpointImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
+ config := meta.(*Config)
+ if err := parseImportId([]string{
+ "projects/(?P[^/]+)/locations/(?P[^/]+)/endpoints/(?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}}/endpoints/{{name}}")
+ if err != nil {
+ return nil, fmt.Errorf("Error constructing id: %s", err)
+ }
+ d.SetId(id)
+
+ return []*schema.ResourceData{d}, nil
+}
+
+func flattenCloudIdsEndpointName(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ if v == nil {
+ return v
+ }
+ return NameFromSelfLinkStateFunc(v)
+}
+
+func flattenCloudIdsEndpointCreateTime(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ return v
+}
+
+func flattenCloudIdsEndpointUpdateTime(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ return v
+}
+
+func flattenCloudIdsEndpointNetwork(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ return v
+}
+
+func flattenCloudIdsEndpointDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ return v
+}
+
+func flattenCloudIdsEndpointEndpointForwardingRule(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ return v
+}
+
+func flattenCloudIdsEndpointEndpoint(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ return v
+}
+
+func flattenCloudIdsEndpointSeverity(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ return v
+}
+
+func expandCloudIdsEndpointName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+ return replaceVars(d, config, "projects/{{project}}/locations/{{location}}/endpoints/{{name}}")
+}
+
+func expandCloudIdsEndpointNetwork(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+ return v, nil
+}
+
+func expandCloudIdsEndpointDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+ return v, nil
+}
+
+func expandCloudIdsEndpointSeverity(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+ return v, nil
+}
diff --git a/google/resource_cloud_ids_endpoint_sweeper_test.go b/google/resource_cloud_ids_endpoint_sweeper_test.go
new file mode 100644
index 0000000000..abdc99fe09
--- /dev/null
+++ b/google/resource_cloud_ids_endpoint_sweeper_test.go
@@ -0,0 +1,124 @@
+// ----------------------------------------------------------------------------
+//
+// *** AUTO GENERATED CODE *** Type: MMv1 ***
+//
+// ----------------------------------------------------------------------------
+//
+// 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 (
+ "context"
+ "log"
+ "strings"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+)
+
+func init() {
+ resource.AddTestSweepers("CloudIdsEndpoint", &resource.Sweeper{
+ Name: "CloudIdsEndpoint",
+ F: testSweepCloudIdsEndpoint,
+ })
+}
+
+// At the time of writing, the CI only passes us-central1 as the region
+func testSweepCloudIdsEndpoint(region string) error {
+ resourceName := "CloudIdsEndpoint"
+ log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName)
+
+ config, err := sharedConfigForRegion(region)
+ if err != nil {
+ log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err)
+ return err
+ }
+
+ err = config.LoadAndValidate(context.Background())
+ if err != nil {
+ log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err)
+ return err
+ }
+
+ t := &testing.T{}
+ billingId := getTestBillingAccountFromEnv(t)
+
+ // Setup variables to replace in list template
+ d := &ResourceDataMock{
+ FieldsInSchema: map[string]interface{}{
+ "project": config.Project,
+ "region": region,
+ "location": region,
+ "zone": "-",
+ "billing_account": billingId,
+ },
+ }
+
+ listTemplate := strings.Split("https://ids.googleapis.com/v1/projects/{{project}}/locations/{{location}}/endpoints", "?")[0]
+ listUrl, err := replaceVars(d, config, listTemplate)
+ if err != nil {
+ log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err)
+ return nil
+ }
+
+ res, err := sendRequest(config, "GET", config.Project, listUrl, config.userAgent, nil)
+ if err != nil {
+ log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err)
+ return nil
+ }
+
+ resourceList, ok := res["endpoints"]
+ if !ok {
+ log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.")
+ return nil
+ }
+
+ rl := resourceList.([]interface{})
+
+ log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName)
+ // Keep count of items that aren't sweepable for logging.
+ nonPrefixCount := 0
+ for _, ri := range rl {
+ obj := ri.(map[string]interface{})
+ if obj["name"] == nil {
+ log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName)
+ return nil
+ }
+
+ name := GetResourceNameFromSelfLink(obj["name"].(string))
+ // Skip resources that shouldn't be sweeped
+ if !isSweepableTestResource(name) {
+ nonPrefixCount++
+ continue
+ }
+
+ deleteTemplate := "https://ids.googleapis.com/v1/projects/{{project}}/locations/{{location}}/endpoints/{{name}}"
+ deleteUrl, err := replaceVars(d, config, deleteTemplate)
+ if err != nil {
+ log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err)
+ return nil
+ }
+ deleteUrl = deleteUrl + name
+
+ // Don't wait on operations as we may have a lot to delete
+ _, err = sendRequest(config, "DELETE", config.Project, deleteUrl, config.userAgent, nil)
+ if err != nil {
+ log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err)
+ } else {
+ log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name)
+ }
+ }
+
+ if nonPrefixCount > 0 {
+ log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount)
+ }
+
+ return nil
+}
diff --git a/google/resource_cloudids_endpoint_test.go b/google/resource_cloudids_endpoint_test.go
new file mode 100644
index 0000000000..8797febd8b
--- /dev/null
+++ b/google/resource_cloudids_endpoint_test.go
@@ -0,0 +1,95 @@
+package google
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
+)
+
+func TestAccCloudIdsEndpoint_basic(t *testing.T) {
+ t.Parallel()
+
+ context := map[string]interface{}{
+ "random_suffix": randString(t, 10),
+ }
+
+ vcrTest(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckCloudIdsEndpointDestroyProducer(t),
+ Steps: []resource.TestStep{
+ {
+ Config: testCloudIds_basic(context),
+ },
+ {
+ ResourceName: "google_cloud_ids_endpoint.endpoint",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func testCloudIds_basic(context map[string]interface{}) string {
+ return Nprintf(`
+resource "google_compute_network" "default" {
+ name = "tf-test-my-network%{random_suffix}"
+}
+resource "google_compute_global_address" "service_range" {
+ name = "address"
+ purpose = "VPC_PEERING"
+ address_type = "INTERNAL"
+ prefix_length = 16
+ network = google_compute_network.default.id
+}
+resource "google_service_networking_connection" "private_service_connection" {
+ network = google_compute_network.default.id
+ service = "servicenetworking.googleapis.com"
+ reserved_peering_ranges = [google_compute_global_address.service_range.name]
+}
+
+resource "google_cloud_ids_endpoint" "endpoint" {
+ name = "cloud-ids-test-%{random_suffix}"
+ location = "us-central1-f"
+ network = google_compute_network.default.id
+ severity = "INFORMATIONAL"
+ depends_on = [google_service_networking_connection.private_service_connection]
+}
+`, context)
+}
+
+func testAccCheckCloudIdsEndpointDestroyProducer(t *testing.T) func(s *terraform.State) error {
+ return func(s *terraform.State) error {
+ for name, rs := range s.RootModule().Resources {
+ if rs.Type != "google_cloud_ids_endpoint" {
+ continue
+ }
+ if strings.HasPrefix(name, "data.") {
+ continue
+ }
+
+ config := googleProviderConfig(t)
+
+ url, err := replaceVarsForTest(config, rs, "{{CloudIdsBasePath}}projects/{{project}}/locations/{{location}}/endpoints/{{name}}")
+ if err != nil {
+ return err
+ }
+
+ billingProject := ""
+
+ if config.BillingProject != "" {
+ billingProject = config.BillingProject
+ }
+
+ _, err = sendRequest(config, "GET", billingProject, url, config.userAgent, nil)
+ if err == nil {
+ return fmt.Errorf("CloudIdsEndpoint still exists at %s", url)
+ }
+ }
+
+ return nil
+ }
+}
diff --git a/website/docs/r/cloud_ids_endpoint.html.markdown b/website/docs/r/cloud_ids_endpoint.html.markdown
new file mode 100644
index 0000000000..06ab630520
--- /dev/null
+++ b/website/docs/r/cloud_ids_endpoint.html.markdown
@@ -0,0 +1,133 @@
+---
+# ----------------------------------------------------------------------------
+#
+# *** AUTO GENERATED CODE *** Type: MMv1 ***
+#
+# ----------------------------------------------------------------------------
+#
+# 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 Intrusion Detection Service"
+page_title: "Google: google_cloud_ids_endpoint"
+description: |-
+ Cloud IDS is an intrusion detection service that provides threat detection for intrusions, malware, spyware, and command-and-control attacks on your network.
+---
+
+# google\_cloud\_ids\_endpoint
+
+Cloud IDS is an intrusion detection service that provides threat detection for intrusions, malware, spyware, and command-and-control attacks on your network.
+
+
+To get more information about Endpoint, see:
+
+* [API documentation](https://cloud.google.com/intrusion-detection-system/docs/configuring-ids)
+
+## Example Usage - Cloudids Endpoint
+
+
+```hcl
+resource "google_compute_network" "default" {
+ name = "tf-test-my-network"
+}
+resource "google_compute_global_address" "service_range" {
+ name = "address"
+ purpose = "VPC_PEERING"
+ address_type = "INTERNAL"
+ prefix_length = 16
+ network = google_compute_network.default.id
+}
+resource "google_service_networking_connection" "private_service_connection" {
+ network = google_compute_network.default.id
+ service = "servicenetworking.googleapis.com"
+ reserved_peering_ranges = [google_compute_global_address.service_range.name]
+}
+
+resource "google_cloud_ids_endpoint" "example-endpoint" {
+ name = "test"
+ location = "us-central1-f"
+ network = google_compute_network.default.id
+ severity = "INFORMATIONAL"
+ depends_on = [google_service_networking_connection.private_service_connection]
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+
+* `name` -
+ (Required)
+ Name of the endpoint in the format projects/{project_id}/locations/{locationId}/endpoints/{endpointId}.
+
+* `network` -
+ (Required)
+ Name of the VPC network that is connected to the IDS endpoint. This can either contain the VPC network name itself (like "src-net") or the full URL to the network (like "projects/{project_id}/global/networks/src-net").
+
+* `severity` -
+ (Required)
+ The minimum alert severity level that is reported by the endpoint.
+ Possible values are `INFORMATIONAL`, `LOW`, `MEDIUM`, `HIGH`, and `CRITICAL`.
+
+* `location` -
+ (Required)
+ The location for the endpoint.
+
+
+- - -
+
+
+* `description` -
+ (Optional)
+ An optional description of the endpoint.
+
+* `project` - (Optional) The ID of the project in which the resource belongs.
+ If it is not provided, the provider project is used.
+
+
+## Attributes Reference
+
+In addition to the arguments listed above, the following computed attributes are exported:
+
+* `id` - an identifier for the resource with format `projects/{{project}}/locations/{{location}}/endpoints/{{name}}`
+
+* `create_time` -
+ Creation timestamp in RFC 3339 text format.
+
+* `update_time` -
+ Last update timestamp in RFC 3339 text format.
+
+* `endpoint_forwarding_rule` -
+ URL of the endpoint's network address to which traffic is to be sent by Packet Mirroring.
+
+* `endpoint` -
+ Internal IP address of the endpoint's network entry point.
+
+
+## Timeouts
+
+This resource provides the following
+[Timeouts](/docs/configuration/resources.html#timeouts) configuration options:
+
+- `create` - Default is 20 minutes.
+- `delete` - Default is 20 minutes.
+
+## Import
+
+
+Endpoint can be imported using any of these accepted formats:
+
+```
+$ terraform import google_cloud_ids_endpoint.default projects/{{project}}/locations/{{location}}/endpoints/{{name}}
+$ terraform import google_cloud_ids_endpoint.default {{project}}/{{location}}/{{name}}
+$ terraform import google_cloud_ids_endpoint.default {{location}}/{{name}}
+```
+
+## User Project Overrides
+
+This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override).