From 5685ca1c6bfbe85fa579a53e289480fb3f2b78d8 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Fri, 7 Aug 2020 15:04:50 +0000 Subject: [PATCH] Fixed validation of service_level_indicator.0.windows_based_sli.0.metric_sum_in_range.0.range.0.max (#3826) Signed-off-by: Modular Magician --- .changelog/3826.txt | 3 + ...source_google_container_engine_versions.go | 1 - google-beta/provider.go | 5 +- ...rce_access_context_manager_access_level.go | 6 +- ...esource_app_engine_flexible_app_version.go | 5 +- ...esource_app_engine_standard_app_version.go | 5 +- .../resource_artifact_registry_repository.go | 7 +- .../resource_compute_packet_mirroring.go | 4 +- ...e_compute_region_network_endpoint_group.go | 645 ++++++++++++++++++ ...n_network_endpoint_group_generated_test.go | 262 +++++++ ...ion_network_endpoint_group_sweeper_test.go | 124 ++++ google-beta/resource_dialogflow_intent.go | 3 +- google-beta/resource_filestore_instance.go | 3 +- google-beta/resource_monitoring_slo.go | 2 +- .../resource_os_config_patch_deployment.go | 3 +- .../resource_security_scanner_scan_config.go | 3 +- .../d/container_engine_versions.html.markdown | 2 +- ..._engine_flexible_app_version.html.markdown | 3 +- ..._engine_standard_app_version.html.markdown | 3 +- ...artifact_registry_repository.html.markdown | 7 +- ...egion_network_endpoint_group.html.markdown | 359 ++++++++++ website/google.erb | 4 + 22 files changed, 1435 insertions(+), 24 deletions(-) create mode 100644 .changelog/3826.txt create mode 100644 google-beta/resource_compute_region_network_endpoint_group.go create mode 100644 google-beta/resource_compute_region_network_endpoint_group_generated_test.go create mode 100644 google-beta/resource_compute_region_network_endpoint_group_sweeper_test.go create mode 100644 website/docs/r/compute_region_network_endpoint_group.html.markdown diff --git a/.changelog/3826.txt b/.changelog/3826.txt new file mode 100644 index 00000000000..98b90672536 --- /dev/null +++ b/.changelog/3826.txt @@ -0,0 +1,3 @@ +```release-note:bug +monitoring: fixed validation rules for `google_monitoring_slo` `windows_based_sli.metric_sum_in_range.max` field +``` diff --git a/google-beta/data_source_google_container_engine_versions.go b/google-beta/data_source_google_container_engine_versions.go index c66f1ad9d5e..79ef2c95a56 100644 --- a/google-beta/data_source_google_container_engine_versions.go +++ b/google-beta/data_source_google_container_engine_versions.go @@ -58,7 +58,6 @@ func dataSourceGoogleContainerEngineVersions() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "release_channel_default_version": { Type: schema.TypeMap, Computed: true, diff --git a/google-beta/provider.go b/google-beta/provider.go index 75b54f7eca3..234285725d0 100644 --- a/google-beta/provider.go +++ b/google-beta/provider.go @@ -700,9 +700,9 @@ func Provider() terraform.ResourceProvider { return provider } -// Generated resources: 179 +// Generated resources: 180 // Generated IAM resources: 66 -// Total generated resources: 245 +// Total generated resources: 246 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -786,6 +786,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_compute_network_endpoint_group": resourceComputeNetworkEndpointGroup(), "google_compute_global_network_endpoint": resourceComputeGlobalNetworkEndpoint(), "google_compute_global_network_endpoint_group": resourceComputeGlobalNetworkEndpointGroup(), + "google_compute_region_network_endpoint_group": resourceComputeRegionNetworkEndpointGroup(), "google_compute_node_group": resourceComputeNodeGroup(), "google_compute_network_peering_routes_config": resourceComputeNetworkPeeringRoutesConfig(), "google_compute_node_template": resourceComputeNodeTemplate(), diff --git a/google-beta/resource_access_context_manager_access_level.go b/google-beta/resource_access_context_manager_access_level.go index edf45f5f22f..84d3534a154 100644 --- a/google-beta/resource_access_context_manager_access_level.go +++ b/google-beta/resource_access_context_manager_access_level.go @@ -92,7 +92,8 @@ allowed.`, Description: `A list of allowed device management levels. An empty list allows all management levels. Possible values: ["MANAGEMENT_UNSPECIFIED", "NONE", "BASIC", "COMPLETE"]`, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"MANAGEMENT_UNSPECIFIED", "NONE", "BASIC", "COMPLETE"}, false), }, }, "allowed_encryption_statuses": { @@ -101,7 +102,8 @@ An empty list allows all management levels. Possible values: ["MANAGEMENT_UNSPEC Description: `A list of allowed encryptions statuses. An empty list allows all statuses. Possible values: ["ENCRYPTION_UNSPECIFIED", "ENCRYPTION_UNSUPPORTED", "UNENCRYPTED", "ENCRYPTED"]`, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"ENCRYPTION_UNSPECIFIED", "ENCRYPTION_UNSUPPORTED", "UNENCRYPTED", "ENCRYPTED"}, false), }, }, "os_constraints": { diff --git a/google-beta/resource_app_engine_flexible_app_version.go b/google-beta/resource_app_engine_flexible_app_version.go index 2cfe686e6d4..9b6de57df88 100644 --- a/google-beta/resource_app_engine_flexible_app_version.go +++ b/google-beta/resource_app_engine_flexible_app_version.go @@ -649,9 +649,10 @@ All URLs that begin with this prefix are handled by this handler, using the port "inbound_services": { Type: schema.TypeSet, Optional: true, - Description: `Before an application can receive email or XMPP messages, the application must be configured to enable the service.`, + Description: `A list of the types of messages that this application is able to receive. Possible values: ["INBOUND_SERVICE_MAIL", "INBOUND_SERVICE_MAIL_BOUNCE", "INBOUND_SERVICE_XMPP_ERROR", "INBOUND_SERVICE_XMPP_MESSAGE", "INBOUND_SERVICE_XMPP_SUBSCRIBE", "INBOUND_SERVICE_XMPP_PRESENCE", "INBOUND_SERVICE_CHANNEL_PRESENCE", "INBOUND_SERVICE_WARMUP"]`, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"INBOUND_SERVICE_MAIL", "INBOUND_SERVICE_MAIL_BOUNCE", "INBOUND_SERVICE_XMPP_ERROR", "INBOUND_SERVICE_XMPP_MESSAGE", "INBOUND_SERVICE_XMPP_SUBSCRIBE", "INBOUND_SERVICE_XMPP_PRESENCE", "INBOUND_SERVICE_CHANNEL_PRESENCE", "INBOUND_SERVICE_WARMUP"}, false), }, Set: schema.HashString, }, diff --git a/google-beta/resource_app_engine_standard_app_version.go b/google-beta/resource_app_engine_standard_app_version.go index cbc32aece64..922efa54c5c 100644 --- a/google-beta/resource_app_engine_standard_app_version.go +++ b/google-beta/resource_app_engine_standard_app_version.go @@ -335,9 +335,10 @@ All URLs that begin with this prefix are handled by this handler, using the port "inbound_services": { Type: schema.TypeSet, Optional: true, - Description: `Before an application can receive email or XMPP messages, the application must be configured to enable the service.`, + Description: `A list of the types of messages that this application is able to receive. Possible values: ["INBOUND_SERVICE_MAIL", "INBOUND_SERVICE_MAIL_BOUNCE", "INBOUND_SERVICE_XMPP_ERROR", "INBOUND_SERVICE_XMPP_MESSAGE", "INBOUND_SERVICE_XMPP_SUBSCRIBE", "INBOUND_SERVICE_XMPP_PRESENCE", "INBOUND_SERVICE_CHANNEL_PRESENCE", "INBOUND_SERVICE_WARMUP"]`, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"INBOUND_SERVICE_MAIL", "INBOUND_SERVICE_MAIL_BOUNCE", "INBOUND_SERVICE_XMPP_ERROR", "INBOUND_SERVICE_XMPP_MESSAGE", "INBOUND_SERVICE_XMPP_SUBSCRIBE", "INBOUND_SERVICE_XMPP_PRESENCE", "INBOUND_SERVICE_CHANNEL_PRESENCE", "INBOUND_SERVICE_WARMUP"}, false), }, Set: schema.HashString, }, diff --git a/google-beta/resource_artifact_registry_repository.go b/google-beta/resource_artifact_registry_repository.go index 814af5ed8cf..06495af86ce 100644 --- a/google-beta/resource_artifact_registry_repository.go +++ b/google-beta/resource_artifact_registry_repository.go @@ -333,9 +333,10 @@ func resourceArtifactRegistryRepositoryDelete(d *schema.ResourceData, meta inter func resourceArtifactRegistryRepositoryImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { config := meta.(*Config) if err := parseImportId([]string{ - "projects/(?P[^/]+)/locations/(?P[^/]+)/repositories/(?P[^/]+)", - "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", - "(?P[^/]+)/(?P[^/]+)", + "projects/(?P[^/]+)/locations/(?P[^/]+)/repositories/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)", }, d, config); err != nil { return nil, err } diff --git a/google-beta/resource_compute_packet_mirroring.go b/google-beta/resource_compute_packet_mirroring.go index 1115c40abf9..616ffbb5a17 100644 --- a/google-beta/resource_compute_packet_mirroring.go +++ b/google-beta/resource_compute_packet_mirroring.go @@ -22,6 +22,7 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func resourceComputePacketMirroring() *schema.Resource { @@ -163,7 +164,8 @@ destination (egress) IP in the IP header. Only IPv4 is supported.`, Optional: true, Description: `Protocols that apply as a filter on mirrored traffic. Possible values: ["tcp", "udp", "icmp"]`, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"tcp", "udp", "icmp"}, false), }, }, }, diff --git a/google-beta/resource_compute_region_network_endpoint_group.go b/google-beta/resource_compute_region_network_endpoint_group.go new file mode 100644 index 00000000000..21b9b0f2f90 --- /dev/null +++ b/google-beta/resource_compute_region_network_endpoint_group.go @@ -0,0 +1,645 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func resourceComputeRegionNetworkEndpointGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeRegionNetworkEndpointGroupCreate, + Read: resourceComputeRegionNetworkEndpointGroupRead, + Delete: resourceComputeRegionNetworkEndpointGroupDelete, + + Importer: &schema.ResourceImporter{ + State: resourceComputeRegionNetworkEndpointGroupImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateGCPName, + Description: `Name of the resource; provided by the client when the resource is +created. The name must be 1-63 characters long, and comply with +RFC1035. Specifically, the name must be 1-63 characters long and match +the regular expression '[a-z]([-a-z0-9]*[a-z0-9])?' which means the +first character must be a lowercase letter, and all following +characters must be a dash, lowercase letter, or digit, except the last +character, which cannot be a dash.`, + }, + "region": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: `A reference to the region where the Serverless NEGs Reside.`, + }, + "app_engine": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: `Only valid when networkEndpointType is "SERVERLESS". +Only one of cloud_run, app_engine or cloud_function may be set.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Optional serving service. +The service name must be 1-63 characters long, and comply with RFC1035. +Example value: "default", "my-service".`, + }, + "url_mask": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `A template to parse service and version fields from a request URL. +URL mask allows for routing to multiple App Engine services without +having to create multiple Network Endpoint Groups and backend services. + +For example, the request URLs "foo1-dot-appname.appspot.com/v1" and +"foo1-dot-appname.appspot.com/v2" can be backed by the same Serverless NEG with +URL mask "-dot-appname.appspot.com/". The URL mask will parse +them to { service = "foo1", version = "v1" } and { service = "foo1", version = "v2" } respectively.`, + }, + "version": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Optional serving version. +The version must be 1-63 characters long, and comply with RFC1035. +Example value: "v1", "v2".`, + }, + }, + }, + ExactlyOneOf: []string{"app_engine", "cloud_function", "cloud_run"}, + }, + "cloud_function": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: `Only valid when networkEndpointType is "SERVERLESS". +Only one of cloud_run, app_engine or cloud_function may be set.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "function": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `A user-defined name of the Cloud Function. +The function name is case-sensitive and must be 1-63 characters long. +Example value: "func1".`, + AtLeastOneOf: []string{"cloud_function.0.function", "cloud_function.0.url_mask"}, + }, + "url_mask": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `A template to parse function field from a request URL. URL mask allows +for routing to multiple Cloud Functions without having to create +multiple Network Endpoint Groups and backend services. + +For example, request URLs "mydomain.com/function1" and "mydomain.com/function2" +can be backed by the same Serverless NEG with URL mask "/". The URL mask +will parse them to { function = "function1" } and { function = "function2" } respectively.`, + AtLeastOneOf: []string{"cloud_function.0.function", "cloud_function.0.url_mask"}, + }, + }, + }, + ExactlyOneOf: []string{"app_engine", "cloud_function", "cloud_run"}, + }, + "cloud_run": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: `Only valid when networkEndpointType is "SERVERLESS". +Only one of cloud_run, app_engine or cloud_function may be set.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Cloud Run service is the main resource of Cloud Run. +The service must be 1-63 characters long, and comply with RFC1035. +Example value: "run-service".`, + AtLeastOneOf: []string{"cloud_run.0.service", "cloud_run.0.url_mask"}, + }, + "tag": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Cloud Run tag represents the "named-revision" to provide +additional fine-grained traffic routing information. +The tag must be 1-63 characters long, and comply with RFC1035. +Example value: "revision-0010".`, + }, + "url_mask": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `A template to parse service and tag fields from a request URL. +URL mask allows for routing to multiple Run services without having +to create multiple network endpoint groups and backend services. + +For example, request URLs "foo1.domain.com/bar1" and "foo1.domain.com/bar2" +an be backed by the same Serverless Network Endpoint Group (NEG) with +URL mask ".domain.com/". The URL mask will parse them to { service="bar1", tag="foo1" } +and { service="bar2", tag="foo2" } respectively.`, + AtLeastOneOf: []string{"cloud_run.0.service", "cloud_run.0.url_mask"}, + }, + }, + }, + ExactlyOneOf: []string{"cloud_run", "cloud_function", "app_engine"}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `An optional description of this resource. Provide this property when +you create the resource.`, + }, + "network_endpoint_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"SERVERLESS", ""}, false), + Description: `Type of network endpoints in this network endpoint group. Defaults to SERVERLESS Default value: "SERVERLESS" Possible values: ["SERVERLESS"]`, + Default: "SERVERLESS", + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceComputeRegionNetworkEndpointGroupCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandComputeRegionNetworkEndpointGroupName(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 + } + descriptionProp, err := expandComputeRegionNetworkEndpointGroupDescription(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 + } + networkEndpointTypeProp, err := expandComputeRegionNetworkEndpointGroupNetworkEndpointType(d.Get("network_endpoint_type"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("network_endpoint_type"); !isEmptyValue(reflect.ValueOf(networkEndpointTypeProp)) && (ok || !reflect.DeepEqual(v, networkEndpointTypeProp)) { + obj["networkEndpointType"] = networkEndpointTypeProp + } + cloudRunProp, err := expandComputeRegionNetworkEndpointGroupCloudRun(d.Get("cloud_run"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("cloud_run"); !isEmptyValue(reflect.ValueOf(cloudRunProp)) && (ok || !reflect.DeepEqual(v, cloudRunProp)) { + obj["cloudRun"] = cloudRunProp + } + appEngineProp, err := expandComputeRegionNetworkEndpointGroupAppEngine(d.Get("app_engine"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("app_engine"); !isEmptyValue(reflect.ValueOf(appEngineProp)) && (ok || !reflect.DeepEqual(v, appEngineProp)) { + obj["appEngine"] = appEngineProp + } + cloudFunctionProp, err := expandComputeRegionNetworkEndpointGroupCloudFunction(d.Get("cloud_function"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("cloud_function"); !isEmptyValue(reflect.ValueOf(cloudFunctionProp)) && (ok || !reflect.DeepEqual(v, cloudFunctionProp)) { + obj["cloudFunction"] = cloudFunctionProp + } + regionProp, err := expandComputeRegionNetworkEndpointGroupRegion(d.Get("region"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("region"); !isEmptyValue(reflect.ValueOf(regionProp)) && (ok || !reflect.DeepEqual(v, regionProp)) { + obj["region"] = regionProp + } + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/networkEndpointGroups") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new RegionNetworkEndpointGroup: %#v", obj) + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequestWithTimeout(config, "POST", project, url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating RegionNetworkEndpointGroup: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "projects/{{project}}/regions/{{region}}/networkEndpointGroups/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = computeOperationWaitTime( + config, res, project, "Creating RegionNetworkEndpointGroup", + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create RegionNetworkEndpointGroup: %s", err) + } + + log.Printf("[DEBUG] Finished creating RegionNetworkEndpointGroup %q: %#v", d.Id(), res) + + return resourceComputeRegionNetworkEndpointGroupRead(d, meta) +} + +func resourceComputeRegionNetworkEndpointGroupRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/networkEndpointGroups/{{name}}") + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequest(config, "GET", project, url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeRegionNetworkEndpointGroup %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading RegionNetworkEndpointGroup: %s", err) + } + + if err := d.Set("name", flattenComputeRegionNetworkEndpointGroupName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionNetworkEndpointGroup: %s", err) + } + if err := d.Set("description", flattenComputeRegionNetworkEndpointGroupDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionNetworkEndpointGroup: %s", err) + } + if err := d.Set("network_endpoint_type", flattenComputeRegionNetworkEndpointGroupNetworkEndpointType(res["networkEndpointType"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionNetworkEndpointGroup: %s", err) + } + if err := d.Set("cloud_run", flattenComputeRegionNetworkEndpointGroupCloudRun(res["cloudRun"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionNetworkEndpointGroup: %s", err) + } + if err := d.Set("app_engine", flattenComputeRegionNetworkEndpointGroupAppEngine(res["appEngine"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionNetworkEndpointGroup: %s", err) + } + if err := d.Set("cloud_function", flattenComputeRegionNetworkEndpointGroupCloudFunction(res["cloudFunction"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionNetworkEndpointGroup: %s", err) + } + if err := d.Set("region", flattenComputeRegionNetworkEndpointGroupRegion(res["region"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionNetworkEndpointGroup: %s", err) + } + if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { + return fmt.Errorf("Error reading RegionNetworkEndpointGroup: %s", err) + } + + return nil +} + +func resourceComputeRegionNetworkEndpointGroupDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/networkEndpointGroups/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting RegionNetworkEndpointGroup %q", d.Id()) + + res, err := sendRequestWithTimeout(config, "DELETE", project, url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "RegionNetworkEndpointGroup") + } + + err = computeOperationWaitTime( + config, res, project, "Deleting RegionNetworkEndpointGroup", + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting RegionNetworkEndpointGroup %q: %#v", d.Id(), res) + return nil +} + +func resourceComputeRegionNetworkEndpointGroupImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)/regions/(?P[^/]+)/networkEndpointGroups/(?P[^/]+)", + "(?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}}/regions/{{region}}/networkEndpointGroups/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeRegionNetworkEndpointGroupName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupNetworkEndpointType(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupCloudRun(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["service"] = + flattenComputeRegionNetworkEndpointGroupCloudRunService(original["service"], d, config) + transformed["tag"] = + flattenComputeRegionNetworkEndpointGroupCloudRunTag(original["tag"], d, config) + transformed["url_mask"] = + flattenComputeRegionNetworkEndpointGroupCloudRunUrlMask(original["urlMask"], d, config) + return []interface{}{transformed} +} +func flattenComputeRegionNetworkEndpointGroupCloudRunService(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupCloudRunTag(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupCloudRunUrlMask(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupAppEngine(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + transformed := make(map[string]interface{}) + transformed["service"] = + flattenComputeRegionNetworkEndpointGroupAppEngineService(original["service"], d, config) + transformed["version"] = + flattenComputeRegionNetworkEndpointGroupAppEngineVersion(original["version"], d, config) + transformed["url_mask"] = + flattenComputeRegionNetworkEndpointGroupAppEngineUrlMask(original["urlMask"], d, config) + return []interface{}{transformed} +} +func flattenComputeRegionNetworkEndpointGroupAppEngineService(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupAppEngineVersion(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupAppEngineUrlMask(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupCloudFunction(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["function"] = + flattenComputeRegionNetworkEndpointGroupCloudFunctionFunction(original["function"], d, config) + transformed["url_mask"] = + flattenComputeRegionNetworkEndpointGroupCloudFunctionUrlMask(original["urlMask"], d, config) + return []interface{}{transformed} +} +func flattenComputeRegionNetworkEndpointGroupCloudFunctionFunction(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupCloudFunctionUrlMask(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeRegionNetworkEndpointGroupRegion(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + +func expandComputeRegionNetworkEndpointGroupName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupNetworkEndpointType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupCloudRun(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedService, err := expandComputeRegionNetworkEndpointGroupCloudRunService(original["service"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedService); val.IsValid() && !isEmptyValue(val) { + transformed["service"] = transformedService + } + + transformedTag, err := expandComputeRegionNetworkEndpointGroupCloudRunTag(original["tag"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTag); val.IsValid() && !isEmptyValue(val) { + transformed["tag"] = transformedTag + } + + transformedUrlMask, err := expandComputeRegionNetworkEndpointGroupCloudRunUrlMask(original["url_mask"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedUrlMask); val.IsValid() && !isEmptyValue(val) { + transformed["urlMask"] = transformedUrlMask + } + + return transformed, nil +} + +func expandComputeRegionNetworkEndpointGroupCloudRunService(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupCloudRunTag(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupCloudRunUrlMask(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupAppEngine(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 { + return nil, nil + } + + if l[0] == nil { + transformed := make(map[string]interface{}) + return transformed, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedService, err := expandComputeRegionNetworkEndpointGroupAppEngineService(original["service"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedService); val.IsValid() && !isEmptyValue(val) { + transformed["service"] = transformedService + } + + transformedVersion, err := expandComputeRegionNetworkEndpointGroupAppEngineVersion(original["version"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedVersion); val.IsValid() && !isEmptyValue(val) { + transformed["version"] = transformedVersion + } + + transformedUrlMask, err := expandComputeRegionNetworkEndpointGroupAppEngineUrlMask(original["url_mask"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedUrlMask); val.IsValid() && !isEmptyValue(val) { + transformed["urlMask"] = transformedUrlMask + } + + return transformed, nil +} + +func expandComputeRegionNetworkEndpointGroupAppEngineService(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupAppEngineVersion(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupAppEngineUrlMask(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupCloudFunction(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedFunction, err := expandComputeRegionNetworkEndpointGroupCloudFunctionFunction(original["function"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedFunction); val.IsValid() && !isEmptyValue(val) { + transformed["function"] = transformedFunction + } + + transformedUrlMask, err := expandComputeRegionNetworkEndpointGroupCloudFunctionUrlMask(original["url_mask"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedUrlMask); val.IsValid() && !isEmptyValue(val) { + transformed["urlMask"] = transformedUrlMask + } + + return transformed, nil +} + +func expandComputeRegionNetworkEndpointGroupCloudFunctionFunction(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupCloudFunctionUrlMask(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionNetworkEndpointGroupRegion(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("regions", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for region: %s", err) + } + return f.RelativeLink(), nil +} diff --git a/google-beta/resource_compute_region_network_endpoint_group_generated_test.go b/google-beta/resource_compute_region_network_endpoint_group_generated_test.go new file mode 100644 index 00000000000..cfdc026a9ee --- /dev/null +++ b/google-beta/resource_compute_region_network_endpoint_group_generated_test.go @@ -0,0 +1,262 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccComputeRegionNetworkEndpointGroup_regionNetworkEndpointGroupFunctionsExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "zip_path": createZIPArchiveForCloudFunctionSource(t, testHTTPTriggerPath), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + CheckDestroy: testAccCheckComputeRegionNetworkEndpointGroupDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionNetworkEndpointGroup_regionNetworkEndpointGroupFunctionsExample(context), + }, + }, + }) +} + +func testAccComputeRegionNetworkEndpointGroup_regionNetworkEndpointGroupFunctionsExample(context map[string]interface{}) string { + return Nprintf(` +// Cloud Functions Example +resource "google_compute_region_network_endpoint_group" "function_neg" { + provider = google-beta + name = "tf-test-function-neg%{random_suffix}" + network_endpoint_type = "SERVERLESS" + region = "us-central1" + cloud_function { + function = google_cloudfunctions_function.function_neg.name + } +} + +resource "google_cloudfunctions_function" "function_neg" { + provider = google-beta + name = "tf-test-function-neg%{random_suffix}" + description = "My function" + runtime = "nodejs10" + + available_memory_mb = 128 + source_archive_bucket = google_storage_bucket.bucket.name + source_archive_object = google_storage_bucket_object.archive.name + trigger_http = true + timeout = 60 + entry_point = "helloGET" +} + +resource "google_storage_bucket" "bucket" { + provider = google-beta + name = "tf-test-cloudfunctions-function-example-bucket%{random_suffix}" +} + +resource "google_storage_bucket_object" "archive" { + provider = google-beta + name = "index.zip" + bucket = google_storage_bucket.bucket.name + source = "%{zip_path}" +} +`, context) +} + +func TestAccComputeRegionNetworkEndpointGroup_regionNetworkEndpointGroupCloudrunExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + CheckDestroy: testAccCheckComputeRegionNetworkEndpointGroupDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionNetworkEndpointGroup_regionNetworkEndpointGroupCloudrunExample(context), + }, + }, + }) +} + +func testAccComputeRegionNetworkEndpointGroup_regionNetworkEndpointGroupCloudrunExample(context map[string]interface{}) string { + return Nprintf(` +// Cloud Run Example +resource "google_compute_region_network_endpoint_group" "cloudrun_neg" { + provider = google-beta + name = "tf-test-cloudrun-neg%{random_suffix}" + network_endpoint_type = "SERVERLESS" + region = "us-central1" + cloud_run { + service = google_cloud_run_service.cloudrun_neg.name + } +} + +resource "google_cloud_run_service" "cloudrun_neg" { + provider = google-beta + name = "tf-test-cloudrun-neg%{random_suffix}" + location = "us-central1" + + template { + spec { + containers { + image = "gcr.io/cloudrun/hello" + } + } + } + + traffic { + percent = 100 + latest_revision = true + } +} +`, context) +} + +func TestAccComputeRegionNetworkEndpointGroup_regionNetworkEndpointGroupAppengineExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + CheckDestroy: testAccCheckComputeRegionNetworkEndpointGroupDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionNetworkEndpointGroup_regionNetworkEndpointGroupAppengineExample(context), + }, + }, + }) +} + +func testAccComputeRegionNetworkEndpointGroup_regionNetworkEndpointGroupAppengineExample(context map[string]interface{}) string { + return Nprintf(` +// App Engine Example +resource "google_compute_region_network_endpoint_group" "appengine_neg" { + provider = google-beta + name = "tf-test-appengine-neg%{random_suffix}" + network_endpoint_type = "SERVERLESS" + region = "us-central1" + app_engine { + service = google_app_engine_flexible_app_version.appengine_neg.service + version = google_app_engine_flexible_app_version.appengine_neg.version_id + } +} + +resource "google_app_engine_flexible_app_version" "appengine_neg" { + provider = google-beta + version_id = "v1" + service = "default" + runtime = "nodejs" + + entrypoint { + shell = "node ./app.js" + } + + deployment { + zip { + source_url = "https://storage.googleapis.com/${google_storage_bucket.appengine_neg.name}/${google_storage_bucket_object.appengine_neg.name}" + } + } + + liveness_check { + path = "/" + } + + readiness_check { + path = "/" + } + + env_variables = { + port = "8080" + } + + handlers { + url_regex = ".*\\/my-path\\/*" + security_level = "SECURE_ALWAYS" + login = "LOGIN_REQUIRED" + auth_fail_action = "AUTH_FAIL_ACTION_REDIRECT" + + static_files { + path = "my-other-path" + upload_path_regex = ".*\\/my-path\\/*" + } + } + + automatic_scaling { + cool_down_period = "120s" + cpu_utilization { + target_utilization = 0.5 + } + } + + noop_on_destroy = true +} + +resource "google_storage_bucket" "appengine_neg" { + provider = google-beta + name = "tf-test-appengine-neg%{random_suffix}" +} + +resource "google_storage_bucket_object" "appengine_neg" { + provider = google-beta + name = "hello-world.zip" + bucket = google_storage_bucket.appengine_neg.name + source = "./test-fixtures/appengine/hello-world.zip" +} +`, context) +} + +func testAccCheckComputeRegionNetworkEndpointGroupDestroyProducer(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_compute_region_network_endpoint_group" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := googleProviderConfig(t) + + url, err := replaceVarsForTest(config, rs, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/networkEndpointGroups/{{name}}") + if err != nil { + return err + } + + _, err = sendRequest(config, "GET", "", url, nil) + if err == nil { + return fmt.Errorf("ComputeRegionNetworkEndpointGroup still exists at %s", url) + } + } + + return nil + } +} diff --git a/google-beta/resource_compute_region_network_endpoint_group_sweeper_test.go b/google-beta/resource_compute_region_network_endpoint_group_sweeper_test.go new file mode 100644 index 00000000000..8694ab5c85b --- /dev/null +++ b/google-beta/resource_compute_region_network_endpoint_group_sweeper_test.go @@ -0,0 +1,124 @@ +// ---------------------------------------------------------------------------- +// +// *** 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 ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func init() { + resource.AddTestSweepers("ComputeRegionNetworkEndpointGroup", &resource.Sweeper{ + Name: "ComputeRegionNetworkEndpointGroup", + F: testSweepComputeRegionNetworkEndpointGroup, + }) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepComputeRegionNetworkEndpointGroup(region string) error { + resourceName := "ComputeRegionNetworkEndpointGroup" + 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://www.googleapis.com/compute/beta/projects/{{project}}/regions/{{region}}/networkEndpointGroups", "?")[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, nil) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["items"] + 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://www.googleapis.com/compute/beta/projects/{{project}}/regions/{{region}}/networkEndpointGroups/{{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, 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-beta/resource_dialogflow_intent.go b/google-beta/resource_dialogflow_intent.go index 90dcf115f3c..c6f168f2405 100644 --- a/google-beta/resource_dialogflow_intent.go +++ b/google-beta/resource_dialogflow_intent.go @@ -62,7 +62,8 @@ Note: The action name must not contain whitespaces.`, Description: `The list of platforms for which the first responses will be copied from the messages in PLATFORM_UNSPECIFIED (i.e. default platform). Possible values: ["FACEBOOK", "SLACK", "TELEGRAM", "KIK", "SKYPE", "LINE", "VIBER", "ACTIONS_ON_GOOGLE", "GOOGLE_HANGOUTS"]`, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"FACEBOOK", "SLACK", "TELEGRAM", "KIK", "SKYPE", "LINE", "VIBER", "ACTIONS_ON_GOOGLE", "GOOGLE_HANGOUTS"}, false), }, }, "events": { diff --git a/google-beta/resource_filestore_instance.go b/google-beta/resource_filestore_instance.go index 88770ecb98f..7a21a83108a 100644 --- a/google-beta/resource_filestore_instance.go +++ b/google-beta/resource_filestore_instance.go @@ -138,7 +138,8 @@ only a single network is supported.`, Description: `IP versions for which the instance has IP addresses assigned. Possible values: ["ADDRESS_MODE_UNSPECIFIED", "MODE_IPV4", "MODE_IPV6"]`, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"ADDRESS_MODE_UNSPECIFIED", "MODE_IPV4", "MODE_IPV6"}, false), }, }, "network": { diff --git a/google-beta/resource_monitoring_slo.go b/google-beta/resource_monitoring_slo.go index e531e7bfa48..2e832e17841 100644 --- a/google-beta/resource_monitoring_slo.go +++ b/google-beta/resource_monitoring_slo.go @@ -621,7 +621,7 @@ just one of min or max. Summed value 'X' should satisfy Description: `max value for the range (inclusive). If not given, will be set to "infinity", defining an open range ">= range.min"`, - AtLeastOneOf: []string{"windows_based_sli.0.metric_mean_in_range.0.range.0.min", "windows_based_sli.0.metric_mean_in_range.0.range.0.max"}, + AtLeastOneOf: []string{"windows_based_sli.0.metric_sum_in_range.0.range.0.min", "windows_based_sli.0.metric_sum_in_range.0.range.0.max"}, }, "min": { Type: schema.TypeInt, diff --git a/google-beta/resource_os_config_patch_deployment.go b/google-beta/resource_os_config_patch_deployment.go index 52b6f0af1bf..22865e0ea62 100644 --- a/google-beta/resource_os_config_patch_deployment.go +++ b/google-beta/resource_os_config_patch_deployment.go @@ -532,7 +532,8 @@ be executed directly, which will likely only succeed for scripts with shebang li ForceNew: true, Description: `Only apply updates of these windows update classifications. If empty, all updates are applied. Possible values: ["CRITICAL", "SECURITY", "DEFINITION", "DRIVER", "FEATURE_PACK", "SERVICE_PACK", "TOOL", "UPDATE_ROLLUP", "UPDATE"]`, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"CRITICAL", "SECURITY", "DEFINITION", "DRIVER", "FEATURE_PACK", "SERVICE_PACK", "TOOL", "UPDATE_ROLLUP", "UPDATE"}, false), }, ExactlyOneOf: []string{}, }, diff --git a/google-beta/resource_security_scanner_scan_config.go b/google-beta/resource_security_scanner_scan_config.go index c3a7648b26e..5704d5200f5 100644 --- a/google-beta/resource_security_scanner_scan_config.go +++ b/google-beta/resource_security_scanner_scan_config.go @@ -172,7 +172,8 @@ which means the scan will be scheduled to start immediately.`, Optional: true, Description: `Set of Cloud Platforms targeted by the scan. If empty, APP_ENGINE will be used as a default. Possible values: ["APP_ENGINE", "COMPUTE"]`, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"APP_ENGINE", "COMPUTE"}, false), }, }, "user_agent": { diff --git a/website/docs/d/container_engine_versions.html.markdown b/website/docs/d/container_engine_versions.html.markdown index 31cfddf323f..77a76d5b335 100644 --- a/website/docs/d/container_engine_versions.html.markdown +++ b/website/docs/d/container_engine_versions.html.markdown @@ -71,4 +71,4 @@ The following attributes are exported: * `latest_master_version` - The latest version available in the given zone for use with master instances. * `latest_node_version` - The latest version available in the given zone for use with node instances. * `default_cluster_version` - Version of Kubernetes the service deploys by default. -* `release_channel_default_version` ([Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) - A map from a release channel name to the channel's default version. +* `release_channel_default_version` - A map from a release channel name to the channel's default version. diff --git a/website/docs/r/app_engine_flexible_app_version.html.markdown b/website/docs/r/app_engine_flexible_app_version.html.markdown index 987da454761..3309a0c8d7a 100644 --- a/website/docs/r/app_engine_flexible_app_version.html.markdown +++ b/website/docs/r/app_engine_flexible_app_version.html.markdown @@ -228,7 +228,8 @@ The `liveness_check` block supports: * `inbound_services` - (Optional) - Before an application can receive email or XMPP messages, the application must be configured to enable the service. + A list of the types of messages that this application is able to receive. + Each value may be one of `INBOUND_SERVICE_MAIL`, `INBOUND_SERVICE_MAIL_BOUNCE`, `INBOUND_SERVICE_XMPP_ERROR`, `INBOUND_SERVICE_XMPP_MESSAGE`, `INBOUND_SERVICE_XMPP_SUBSCRIBE`, `INBOUND_SERVICE_XMPP_PRESENCE`, `INBOUND_SERVICE_CHANNEL_PRESENCE`, and `INBOUND_SERVICE_WARMUP`. * `instance_class` - (Optional) diff --git a/website/docs/r/app_engine_standard_app_version.html.markdown b/website/docs/r/app_engine_standard_app_version.html.markdown index 73396789bfb..615d692b1ca 100644 --- a/website/docs/r/app_engine_standard_app_version.html.markdown +++ b/website/docs/r/app_engine_standard_app_version.html.markdown @@ -209,7 +209,8 @@ The `files` block supports: * `inbound_services` - (Optional) - Before an application can receive email or XMPP messages, the application must be configured to enable the service. + A list of the types of messages that this application is able to receive. + Each value may be one of `INBOUND_SERVICE_MAIL`, `INBOUND_SERVICE_MAIL_BOUNCE`, `INBOUND_SERVICE_XMPP_ERROR`, `INBOUND_SERVICE_XMPP_MESSAGE`, `INBOUND_SERVICE_XMPP_SUBSCRIBE`, `INBOUND_SERVICE_XMPP_PRESENCE`, `INBOUND_SERVICE_CHANNEL_PRESENCE`, and `INBOUND_SERVICE_WARMUP`. * `instance_class` - (Optional) diff --git a/website/docs/r/artifact_registry_repository.html.markdown b/website/docs/r/artifact_registry_repository.html.markdown index f86581fc0a2..f17a9c2dc37 100644 --- a/website/docs/r/artifact_registry_repository.html.markdown +++ b/website/docs/r/artifact_registry_repository.html.markdown @@ -182,9 +182,10 @@ This resource provides the following Repository can be imported using any of these accepted formats: ``` -$ terraform import -provider=google-beta google_artifact_registry_repository.default projects/{{project}}/locations/{{location}}/repositories/{{name}} -$ terraform import -provider=google-beta google_artifact_registry_repository.default {{project}}/{{location}}/{{name}} -$ terraform import -provider=google-beta google_artifact_registry_repository.default {{location}}/{{name}} +$ terraform import -provider=google-beta google_artifact_registry_repository.default projects/{{project}}/locations/{{location}}/repositories/{{repository_id}} +$ terraform import -provider=google-beta google_artifact_registry_repository.default {{project}}/{{location}}/{{repository_id}} +$ terraform import -provider=google-beta google_artifact_registry_repository.default {{location}}/{{repository_id}} +$ terraform import -provider=google-beta google_artifact_registry_repository.default {{repository_id}} ``` -> If you're importing a resource with beta features, make sure to include `-provider=google-beta` diff --git a/website/docs/r/compute_region_network_endpoint_group.html.markdown b/website/docs/r/compute_region_network_endpoint_group.html.markdown new file mode 100644 index 00000000000..b9639619666 --- /dev/null +++ b/website/docs/r/compute_region_network_endpoint_group.html.markdown @@ -0,0 +1,359 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Compute Engine" +layout: "google" +page_title: "Google: google_compute_region_network_endpoint_group" +sidebar_current: "docs-google-compute-region-network-endpoint-group" +description: |- + A regional NEG that can support Serverless Products. +--- + +# google\_compute\_region\_network\_endpoint\_group + +A regional NEG that can support Serverless Products. + +~> **Warning:** This resource is in beta, and should be used with the terraform-provider-google-beta provider. +See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. + +To get more information about RegionNetworkEndpointGroup, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/rest/beta/regionNetworkEndpointGroups) +* How-to Guides + * [Official Documentation](https://cloud.google.com/load-balancing/docs/negs/serverless-neg-concepts) + + +## Example Usage - Region Network Endpoint Group Functions + + +```hcl +// Cloud Functions Example +resource "google_compute_region_network_endpoint_group" "function_neg" { + provider = google-beta + name = "function-neg" + network_endpoint_type = "SERVERLESS" + region = "us-central1" + cloud_function { + function = google_cloudfunctions_function.function_neg.name + } +} + +resource "google_cloudfunctions_function" "function_neg" { + provider = google-beta + name = "function-neg" + description = "My function" + runtime = "nodejs10" + + available_memory_mb = 128 + source_archive_bucket = google_storage_bucket.bucket.name + source_archive_object = google_storage_bucket_object.archive.name + trigger_http = true + timeout = 60 + entry_point = "helloGET" +} + +resource "google_storage_bucket" "bucket" { + provider = google-beta + name = "cloudfunctions-function-example-bucket" +} + +resource "google_storage_bucket_object" "archive" { + provider = google-beta + name = "index.zip" + bucket = google_storage_bucket.bucket.name + source = "path/to/index.zip" +} +``` + +## Example Usage - Region Network Endpoint Group Cloudrun + + +```hcl +// Cloud Run Example +resource "google_compute_region_network_endpoint_group" "cloudrun_neg" { + provider = google-beta + name = "cloudrun-neg" + network_endpoint_type = "SERVERLESS" + region = "us-central1" + cloud_run { + service = google_cloud_run_service.cloudrun_neg.name + } +} + +resource "google_cloud_run_service" "cloudrun_neg" { + provider = google-beta + name = "cloudrun-neg" + location = "us-central1" + + template { + spec { + containers { + image = "gcr.io/cloudrun/hello" + } + } + } + + traffic { + percent = 100 + latest_revision = true + } +} +``` + +## Example Usage - Region Network Endpoint Group Appengine + + +```hcl +// App Engine Example +resource "google_compute_region_network_endpoint_group" "appengine_neg" { + provider = google-beta + name = "appengine-neg" + network_endpoint_type = "SERVERLESS" + region = "us-central1" + app_engine { + service = google_app_engine_flexible_app_version.appengine_neg.service + version = google_app_engine_flexible_app_version.appengine_neg.version_id + } +} + +resource "google_app_engine_flexible_app_version" "appengine_neg" { + provider = google-beta + version_id = "v1" + service = "default" + runtime = "nodejs" + + entrypoint { + shell = "node ./app.js" + } + + deployment { + zip { + source_url = "https://storage.googleapis.com/${google_storage_bucket.appengine_neg.name}/${google_storage_bucket_object.appengine_neg.name}" + } + } + + liveness_check { + path = "/" + } + + readiness_check { + path = "/" + } + + env_variables = { + port = "8080" + } + + handlers { + url_regex = ".*\\/my-path\\/*" + security_level = "SECURE_ALWAYS" + login = "LOGIN_REQUIRED" + auth_fail_action = "AUTH_FAIL_ACTION_REDIRECT" + + static_files { + path = "my-other-path" + upload_path_regex = ".*\\/my-path\\/*" + } + } + + automatic_scaling { + cool_down_period = "120s" + cpu_utilization { + target_utilization = 0.5 + } + } + + noop_on_destroy = true +} + +resource "google_storage_bucket" "appengine_neg" { + provider = google-beta + name = "appengine-neg" +} + +resource "google_storage_bucket_object" "appengine_neg" { + provider = google-beta + name = "hello-world.zip" + bucket = google_storage_bucket.appengine_neg.name + source = "./test-fixtures/appengine/hello-world.zip" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `name` - + (Required) + Name of the resource; provided by the client when the resource is + created. The name must be 1-63 characters long, and comply with + RFC1035. Specifically, the name must be 1-63 characters long and match + the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the + first character must be a lowercase letter, and all following + characters must be a dash, lowercase letter, or digit, except the last + character, which cannot be a dash. + +* `region` - + (Required) + A reference to the region where the Serverless NEGs Reside. + + +- - - + + +* `description` - + (Optional) + An optional description of this resource. Provide this property when + you create the resource. + +* `network_endpoint_type` - + (Optional) + Type of network endpoints in this network endpoint group. Defaults to SERVERLESS + Default value is `SERVERLESS`. + Possible values are `SERVERLESS`. + +* `cloud_run` - + (Optional) + Only valid when networkEndpointType is "SERVERLESS". + Only one of cloud_run, app_engine or cloud_function may be set. + Structure is documented below. + +* `app_engine` - + (Optional) + Only valid when networkEndpointType is "SERVERLESS". + Only one of cloud_run, app_engine or cloud_function may be set. + Structure is documented below. + +* `cloud_function` - + (Optional) + Only valid when networkEndpointType is "SERVERLESS". + Only one of cloud_run, app_engine or cloud_function may be set. + Structure is documented below. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +The `cloud_run` block supports: + +* `service` - + (Optional) + Cloud Run service is the main resource of Cloud Run. + The service must be 1-63 characters long, and comply with RFC1035. + Example value: "run-service". + +* `tag` - + (Optional) + Cloud Run tag represents the "named-revision" to provide + additional fine-grained traffic routing information. + The tag must be 1-63 characters long, and comply with RFC1035. + Example value: "revision-0010". + +* `url_mask` - + (Optional) + A template to parse service and tag fields from a request URL. + URL mask allows for routing to multiple Run services without having + to create multiple network endpoint groups and backend services. + For example, request URLs "foo1.domain.com/bar1" and "foo1.domain.com/bar2" + an be backed by the same Serverless Network Endpoint Group (NEG) with + URL mask ".domain.com/". The URL mask will parse them to { service="bar1", tag="foo1" } + and { service="bar2", tag="foo2" } respectively. + +The `app_engine` block supports: + +* `service` - + (Optional) + Optional serving service. + The service name must be 1-63 characters long, and comply with RFC1035. + Example value: "default", "my-service". + +* `version` - + (Optional) + Optional serving version. + The version must be 1-63 characters long, and comply with RFC1035. + Example value: "v1", "v2". + +* `url_mask` - + (Optional) + A template to parse service and version fields from a request URL. + URL mask allows for routing to multiple App Engine services without + having to create multiple Network Endpoint Groups and backend services. + For example, the request URLs "foo1-dot-appname.appspot.com/v1" and + "foo1-dot-appname.appspot.com/v2" can be backed by the same Serverless NEG with + URL mask "-dot-appname.appspot.com/". The URL mask will parse + them to { service = "foo1", version = "v1" } and { service = "foo1", version = "v2" } respectively. + +The `cloud_function` block supports: + +* `function` - + (Optional) + A user-defined name of the Cloud Function. + The function name is case-sensitive and must be 1-63 characters long. + Example value: "func1". + +* `url_mask` - + (Optional) + A template to parse function field from a request URL. URL mask allows + for routing to multiple Cloud Functions without having to create + multiple Network Endpoint Groups and backend services. + For example, request URLs "mydomain.com/function1" and "mydomain.com/function2" + can be backed by the same Serverless NEG with URL mask "/". The URL mask + will parse them to { function = "function1" } and { function = "function2" } respectively. + +## 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}}/regions/{{region}}/networkEndpointGroups/{{name}}` +* `self_link` - The URI of the created resource. + + +## 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 + +RegionNetworkEndpointGroup can be imported using any of these accepted formats: + +``` +$ terraform import -provider=google-beta google_compute_region_network_endpoint_group.default projects/{{project}}/regions/{{region}}/networkEndpointGroups/{{name}} +$ terraform import -provider=google-beta google_compute_region_network_endpoint_group.default {{project}}/{{region}}/{{name}} +$ terraform import -provider=google-beta google_compute_region_network_endpoint_group.default {{region}}/{{name}} +$ terraform import -provider=google-beta google_compute_region_network_endpoint_group.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. + +## User Project Overrides + +This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override). diff --git a/website/google.erb b/website/google.erb index ba943ea26d7..395cab1fb82 100644 --- a/website/google.erb +++ b/website/google.erb @@ -1579,6 +1579,10 @@ google_compute_region_instance_group_manager +
  • + google_compute_region_network_endpoint_group +
  • +
  • google_compute_region_per_instance_config