From b305a8bc4a9a52ee12c917928de17fe74adc6554 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Tue, 25 Nov 2025 15:52:51 +0530 Subject: [PATCH] feat(is): support for endpoint gateway resource bindings --- go.mod | 2 +- go.sum | 6 +- ibm/acctest/acctest.go | 20 + ibm/provider/provider.go | 36 +- ..._source_ibm_is_virtual_endpoint_gateway.go | 34 +- ...rtual_endpoint_gateway_resource_binding.go | 214 ++++++++++ ..._endpoint_gateway_resource_binding_test.go | 52 +++ ...tual_endpoint_gateway_resource_bindings.go | 226 ++++++++++ ...endpoint_gateway_resource_bindings_test.go | 52 +++ ...source_ibm_is_virtual_endpoint_gateways.go | 16 +- ...esource_ibm_is_virtual_endpoint_gateway.go | 113 ++++- ...rtual_endpoint_gateway_resource_binding.go | 404 ++++++++++++++++++ ..._endpoint_gateway_resource_binding_test.go | 165 +++++++ ...ce_ibm_is_virtual_endpoint_gateway_test.go | 303 +++++++++++++ .../is_virtual_endpoint_gateway.html.markdown | 14 +- ...int_gateway_resource_binding.html.markdown | 61 +++ ...nt_gateway_resource_bindings.html.markdown | 62 +++ ...is_virtual_endpoint_gateways.html.markdown | 16 +- .../is_virtual_endpoint_gateway.html.markdown | 18 +- ...int_gateway_resource_binding.html.markdown | 80 ++++ 20 files changed, 1861 insertions(+), 33 deletions(-) create mode 100644 ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_binding.go create mode 100644 ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_binding_test.go create mode 100644 ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_bindings.go create mode 100644 ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_bindings_test.go create mode 100644 ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_resource_binding.go create mode 100644 ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_resource_binding_test.go create mode 100644 website/docs/d/is_virtual_endpoint_gateway_resource_binding.html.markdown create mode 100644 website/docs/d/is_virtual_endpoint_gateway_resource_bindings.html.markdown create mode 100644 website/docs/r/is_virtual_endpoint_gateway_resource_binding.html.markdown diff --git a/go.mod b/go.mod index dd713e7107..2d585d40c7 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/IBM/secrets-manager-go-sdk/v2 v2.0.15 github.com/IBM/vmware-go-sdk v0.1.5 github.com/IBM/vpc-beta-go-sdk v0.8.0 - github.com/IBM/vpc-go-sdk v0.75.0 + github.com/IBM/vpc-go-sdk v0.76.0 github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/akamai/AkamaiOPEN-edgegrid-golang/v5 v5.0.0 diff --git a/go.sum b/go.sum index 2adaa1b62f..7e5f16a923 100644 --- a/go.sum +++ b/go.sum @@ -168,10 +168,8 @@ github.com/IBM/vmware-go-sdk v0.1.5 h1:aQbwcJBceaaauuIoJ0OJn+ttwjb+QTX6XV9Jbrdpj github.com/IBM/vmware-go-sdk v0.1.5/go.mod h1:OyQKRInGGsBaOyE5LIZCqH7b1DZ01BvIYa8BgGy+wWo= github.com/IBM/vpc-beta-go-sdk v0.8.0 h1:cEPpv4iw3Ba5W2d0AWg3TIbKeJ8y1nPuUuibR5Jt9eE= github.com/IBM/vpc-beta-go-sdk v0.8.0/go.mod h1:hORgIyTFRzXrZIK9IohaWmCRBBlYiDRagsufi7M6akE= -github.com/IBM/vpc-go-sdk v0.74.1 h1:qkWwdlILx3ZVNWht96CdlPKwhKL/y3ItN6XmwJ1rShM= -github.com/IBM/vpc-go-sdk v0.74.1/go.mod h1:8lX6TpeYBbx1Vd4KTgM3PPQ4y3auGOPuD6qq3UBDdug= -github.com/IBM/vpc-go-sdk v0.75.0 h1:8s11vR30n0eY9ptf6Osh9Bw13okhMVasb/KX9M52LEg= -github.com/IBM/vpc-go-sdk v0.75.0/go.mod h1:8lX6TpeYBbx1Vd4KTgM3PPQ4y3auGOPuD6qq3UBDdug= +github.com/IBM/vpc-go-sdk v0.76.0 h1:iuiUaGPs9ngfMZ4HkT9fVz/GX/03S2vB9BZ7Rgj+/4U= +github.com/IBM/vpc-go-sdk v0.76.0/go.mod h1:8lX6TpeYBbx1Vd4KTgM3PPQ4y3auGOPuD6qq3UBDdug= github.com/Logicalis/asn1 v0.0.0-20190312173541-d60463189a56 h1:vuquMR410psHNax14XKNWa0Ae/kYgWJcXi0IFuX60N0= github.com/Logicalis/asn1 v0.0.0-20190312173541-d60463189a56/go.mod h1:Zb3OT4l0mf7P/GOs2w2Ilj5sdm5Whoq3pa24dAEBHFc= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index c744e35a65..5ee98a9131 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -143,6 +143,13 @@ var ( trustedMachineType string ) +// For VPC Endpoint Gateway +var ( + IsResourceBindingCRN string + IsEndpointGatewayTargetCRN string + IsEndpointGatewayTargetType string +) + // MQ on Cloud var ( MqcloudConfigEndpoint string @@ -809,6 +816,19 @@ func init() { fmt.Println("[INFO] Set the environment variable SL_REGION for testing ibm_is_region datasource else it is set to default value 'us-south'") } + IsResourceBindingCRN = os.Getenv("IBM_IS_RESOURCE_BINDING_CRN") + if IsResourceBindingCRN == "" { + fmt.Println("[WARN] Set the environment variable IBM_IS_RESOURCE_BINDING_CRN for testing IBM VPC Endpoint gateway resources, the tests will fail if this is not set") + } + IsEndpointGatewayTargetCRN = os.Getenv("IBM_IS_ENDPOINT_BINDING_TARGET_CRN") + if IsEndpointGatewayTargetCRN == "" { + fmt.Println("[WARN] Set the environment variable IBM_IS_ENDPOINT_BINDING_TARGET_CRN for testing IBM VPC Endpoint gateway resources, the tests will fail if this is not set") + } + IsEndpointGatewayTargetType = os.Getenv("IBM_IS_ENDPOINT_BINDING_TARGET_TYPE") + if IsEndpointGatewayTargetType == "" { + fmt.Println("[WARN] Set the environment variable IBM_IS_ENDPOINT_BINDING_TARGET_TYPE for testing IBM VPC Endpoint gateway resources, the tests will fail if this is not set") + } + ISZoneName = os.Getenv("SL_ZONE") if ISZoneName == "" { ISZoneName = "us-south-1" diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index ac52d600d9..0372bd4300 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -539,21 +539,25 @@ func Provider() *schema.Provider { "ibm_is_instance_group_manager_policy": vpc.DataSourceIBMISInstanceGroupManagerPolicy(), "ibm_is_instance_group_manager_action": vpc.DataSourceIBMISInstanceGroupManagerAction(), "ibm_is_instance_group_manager_actions": vpc.DataSourceIBMISInstanceGroupManagerActions(), - "ibm_is_virtual_endpoint_gateways": vpc.DataSourceIBMISEndpointGateways(), - "ibm_is_virtual_endpoint_gateway_ips": vpc.DataSourceIBMISEndpointGatewayIPs(), - "ibm_is_virtual_endpoint_gateway": vpc.DataSourceIBMISEndpointGateway(), - "ibm_is_instance_template": vpc.DataSourceIBMISInstanceTemplate(), - "ibm_is_instance_templates": vpc.DataSourceIBMISInstanceTemplates(), - "ibm_is_instance_profile": vpc.DataSourceIBMISInstanceProfile(), - "ibm_is_instance_profiles": vpc.DataSourceIBMISInstanceProfiles(), - "ibm_is_instance": vpc.DataSourceIBMISInstance(), - "ibm_is_instances": vpc.DataSourceIBMISInstances(), - "ibm_is_instance_network_attachment": vpc.DataSourceIBMIsInstanceNetworkAttachment(), - "ibm_is_instance_network_attachments": vpc.DataSourceIBMIsInstanceNetworkAttachments(), - "ibm_is_instance_network_interface": vpc.DataSourceIBMIsInstanceNetworkInterface(), - "ibm_is_instance_network_interfaces": vpc.DataSourceIBMIsInstanceNetworkInterfaces(), - "ibm_is_instance_disk": vpc.DataSourceIbmIsInstanceDisk(), - "ibm_is_instance_disks": vpc.DataSourceIbmIsInstanceDisks(), + // vpe resource bindings + "ibm_is_virtual_endpoint_gateway_resource_binding": vpc.DataSourceIBMIsVirtualEndpointGatewayResourceBinding(), + "ibm_is_virtual_endpoint_gateway_resource_bindings": vpc.DataSourceIBMIsVirtualEndpointGatewayResourceBindings(), + + "ibm_is_virtual_endpoint_gateways": vpc.DataSourceIBMISEndpointGateways(), + "ibm_is_virtual_endpoint_gateway_ips": vpc.DataSourceIBMISEndpointGatewayIPs(), + "ibm_is_virtual_endpoint_gateway": vpc.DataSourceIBMISEndpointGateway(), + "ibm_is_instance_template": vpc.DataSourceIBMISInstanceTemplate(), + "ibm_is_instance_templates": vpc.DataSourceIBMISInstanceTemplates(), + "ibm_is_instance_profile": vpc.DataSourceIBMISInstanceProfile(), + "ibm_is_instance_profiles": vpc.DataSourceIBMISInstanceProfiles(), + "ibm_is_instance": vpc.DataSourceIBMISInstance(), + "ibm_is_instances": vpc.DataSourceIBMISInstances(), + "ibm_is_instance_network_attachment": vpc.DataSourceIBMIsInstanceNetworkAttachment(), + "ibm_is_instance_network_attachments": vpc.DataSourceIBMIsInstanceNetworkAttachments(), + "ibm_is_instance_network_interface": vpc.DataSourceIBMIsInstanceNetworkInterface(), + "ibm_is_instance_network_interfaces": vpc.DataSourceIBMIsInstanceNetworkInterfaces(), + "ibm_is_instance_disk": vpc.DataSourceIbmIsInstanceDisk(), + "ibm_is_instance_disks": vpc.DataSourceIbmIsInstanceDisks(), // reserved ips "ibm_is_instance_network_interface_reserved_ip": vpc.DataSourceIBMISInstanceNICReservedIP(), @@ -1367,6 +1371,7 @@ func Provider() *schema.Provider { "ibm_is_instance_group_manager_policy": vpc.ResourceIBMISInstanceGroupManagerPolicy(), "ibm_is_instance_group_manager_action": vpc.ResourceIBMISInstanceGroupManagerAction(), "ibm_is_instance_volume_attachment": vpc.ResourceIBMISInstanceVolumeAttachment(), + "ibm_is_virtual_endpoint_gateway_resource_binding": vpc.ResourceIBMIsVirtualEndpointGatewayResourceBinding(), "ibm_is_virtual_endpoint_gateway": vpc.ResourceIBMISEndpointGateway(), "ibm_is_virtual_endpoint_gateway_ip": vpc.ResourceIBMISEndpointGatewayIP(), "ibm_is_instance_template": vpc.ResourceIBMISInstanceTemplate(), @@ -2161,6 +2166,7 @@ func Validator() validate.ValidatorDict { "ibm_schematics_policy": schematics.ResourceIbmSchematicsPolicyValidator(), "ibm_resource_instance": resourcecontroller.ResourceIBMResourceInstanceValidator(), "ibm_resource_key": resourcecontroller.ResourceIBMResourceKeyValidator(), + "ibm_is_virtual_endpoint_gateway_resource_binding": vpc.ResourceIBMIsVirtualEndpointGatewayResourceBindingValidator(), "ibm_is_virtual_endpoint_gateway": vpc.ResourceIBMISEndpointGatewayValidator(), "ibm_resource_tag": globaltagging.ResourceIBMResourceTagValidator(), "ibm_iam_access_tag": globaltagging.ResourceIBMIamAccessTagValidator(), diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway.go index 9dde90f607..74242339d2 100644 --- a/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway.go +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway.go @@ -99,8 +99,14 @@ func DataSourceIBMISEndpointGateway() *schema.Resource { isVirtualEndpointGatewayAllowDnsResolutionBinding: { Type: schema.TypeBool, Computed: true, + Deprecated: "This property has been deprecated in favor of dns_resolution_binding_mode.", Description: "Indicates whether to allow this endpoint gateway to participate in DNS resolution bindings with a VPC that has dns.enable_hub set to true.", }, + "dns_resolution_binding_mode": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The DNS resolution binding mode used for this endpoint gateway:- `disabled`: The endpoint gateway is not participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing).- `primary`: The endpoint gateway is participating in [DNS sharing for VPE gateways] (/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC.- `per_resource_binding`: The endpoint gateway is participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC, and resource binding is enabled for the `target` service.", + }, isVirtualEndpointGatewayIPs: { Type: schema.TypeList, Computed: true, @@ -209,7 +215,20 @@ func dataSourceIBMISEndpointGatewayRead( result := allrecs[0] d.SetId(*result.ID) d.Set(isVirtualEndpointGatewayName, result.Name) - d.Set(isVirtualEndpointGatewayAllowDnsResolutionBinding, result.AllowDnsResolutionBinding) + // Handle the new dns_resolution_binding_mode field + // Handle the new dns_resolution_binding_mode field (API now only returns this field) + if result.DnsResolutionBindingMode != nil && *result.DnsResolutionBindingMode != "" { + if err = d.Set("dns_resolution_binding_mode", *result.DnsResolutionBindingMode); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting dns_resolution_binding_mode: %s", err), "(Data) ibm_is_virtual_endpoint_gateway", "read", "set-dns_resolution_binding_mode").GetDiag() + } + + // Compute and set deprecated field for backward compatibility in Terraform state + allowDnsResolutionBinding := mapDnsResolutionBindingModeToBoolean(*result.DnsResolutionBindingMode) + if err = d.Set(isVirtualEndpointGatewayAllowDnsResolutionBinding, allowDnsResolutionBinding); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allow_dns_resolution_binding: %s", err), "(Data) ibm_is_virtual_endpoint_gateway", "read", "set-allow_dns_resolution_binding").GetDiag() + } + } + d.Set(isVirtualEndpointGatewayCRN, result.CRN) d.Set(isVirtualEndpointGatewayHealthState, result.HealthState) d.Set(isVirtualEndpointGatewayCreatedAt, result.CreatedAt.String()) @@ -243,3 +262,16 @@ func dataSourceIBMISEndpointGatewayRead( } return nil } + +// Helper functions for field mapping during migration period +func mapDnsResolutionBindingModeToBoolean(mode string) bool { + switch mode { + case "disabled": + return false + case "primary", "per_resource_binding": + return true + default: + // Default to false for unknown values + return false + } +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_binding.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_binding.go new file mode 100644 index 0000000000..eebc5d9a5c --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_binding.go @@ -0,0 +1,214 @@ +// Copyright IBM Corp. 2025 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVirtualEndpointGatewayResourceBinding() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVirtualEndpointGatewayResourceBindingRead, + + Schema: map[string]*schema.Schema{ + "endpoint_gateway_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The endpoint gateway identifier.", + }, + "endpoint_gateway_resource_binding_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The resource binding identifier.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the resource binding was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this endpoint gateway resource binding.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the resource binding.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this resource binding. The name is unique across all resource bindings for the endpoint gateway.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "service_endpoint": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The fully qualified domain name of the service endpoint for the resource targeted by this resource binding.", + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The target for this endpoint gateway resource binding.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource binding:- `weak`: The binding is not dependent on the existence of the target resource.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + }, + } +} + +func dataSourceIBMIsVirtualEndpointGatewayResourceBindingRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getEndpointGatewayResourceBindingOptions := &vpcv1.GetEndpointGatewayResourceBindingOptions{} + + getEndpointGatewayResourceBindingOptions.SetEndpointGatewayID(d.Get("endpoint_gateway_id").(string)) + getEndpointGatewayResourceBindingOptions.SetID(d.Get("endpoint_gateway_resource_binding_id").(string)) + + endpointGatewayResourceBinding, _, err := vpcClient.GetEndpointGatewayResourceBindingWithContext(context, getEndpointGatewayResourceBindingOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetEndpointGatewayResourceBindingWithContext failed: %s", err.Error()), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *getEndpointGatewayResourceBindingOptions.EndpointGatewayID, *getEndpointGatewayResourceBindingOptions.ID)) + + if err = d.Set("created_at", flex.DateTimeToString(endpointGatewayResourceBinding.CreatedAt)); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting created_at: %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-created_at").GetDiag() + } + + if err = d.Set("href", endpointGatewayResourceBinding.Href); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting href: %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-href").GetDiag() + } + + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range endpointGatewayResourceBinding.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_reasons: %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-lifecycle_reasons").GetDiag() + } + + if err = d.Set("lifecycle_state", endpointGatewayResourceBinding.LifecycleState); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_state: %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-lifecycle_state").GetDiag() + } + + if err = d.Set("name", endpointGatewayResourceBinding.Name); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting name: %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-name").GetDiag() + } + + if err = d.Set("resource_type", endpointGatewayResourceBinding.ResourceType); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting resource_type: %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-resource_type").GetDiag() + } + + if err = d.Set("service_endpoint", endpointGatewayResourceBinding.ServiceEndpoint); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting service_endpoint: %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-service_endpoint").GetDiag() + } + + target := []map[string]interface{}{} + targetMap, err := DataSourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingTargetToMap(endpointGatewayResourceBinding.Target) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "target-to-map").GetDiag() + } + target = append(target, targetMap) + if err = d.Set("target", target); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting target: %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-target").GetDiag() + } + + if err = d.Set("type", endpointGatewayResourceBinding.Type); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting type: %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-type").GetDiag() + } + + return nil +} + +func DataSourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingLifecycleReasonToMap(model *vpcv1.EndpointGatewayResourceBindingLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingTargetToMap(model vpcv1.EndpointGatewayResourceBindingTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.EndpointGatewayResourceBindingTargetCRN); ok { + return DataSourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingTargetCRNToMap(model.(*vpcv1.EndpointGatewayResourceBindingTargetCRN)) + } else if _, ok := model.(*vpcv1.EndpointGatewayResourceBindingTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.EndpointGatewayResourceBindingTarget) + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.EndpointGatewayResourceBindingTargetIntf subtype encountered") + } +} + +func DataSourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingTargetCRNToMap(model *vpcv1.EndpointGatewayResourceBindingTargetCRN) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_binding_test.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_binding_test.go new file mode 100644 index 0000000000..d66d5c7134 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_binding_test.go @@ -0,0 +1,52 @@ +// Copyright IBM Corp. 2025 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsVirtualEndpointGatewayResourceBindingDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-eg-%d-test", acctest.RandIntRange(10, 100)) + endpointGatewayName := fmt.Sprintf("tf-eg-%d-test", acctest.RandIntRange(10, 100)) + endpointGatewayRBName := fmt.Sprintf("tf-rb-eg-%d-test", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualEndpointGatewayResourceBindingDataSourceConfigBasic(vpcname, endpointGatewayName, endpointGatewayRBName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "endpoint_gateway_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "endpoint_gateway_resource_binding_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "service_endpoint"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "target.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb_ds", "type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVirtualEndpointGatewayResourceBindingDataSourceConfigBasic(vpcname, endpointGatewayName, endpointGatewayRBName string) string { + return testAccCheckIBMIsVirtualEndpointGatewayResourceBindingConfigBasic(vpcname, endpointGatewayName, endpointGatewayRBName) + fmt.Sprintf(` + data "ibm_is_virtual_endpoint_gateway_resource_binding" "testacc_vpe_rb_ds" { + endpoint_gateway_id = ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb.endpoint_gateway_id + endpoint_gateway_resource_binding_id = ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb.endpoint_gateway_resource_binding_id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_bindings.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_bindings.go new file mode 100644 index 0000000000..08843d2583 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_bindings.go @@ -0,0 +1,226 @@ +// Copyright IBM Corp. 2025 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVirtualEndpointGatewayResourceBindings() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVirtualEndpointGatewayResourceBindingsRead, + + Schema: map[string]*schema.Schema{ + "endpoint_gateway_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The endpoint gateway identifier.", + }, + "resource_bindings": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of resource bindings for the endpoint gateway.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the resource binding was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this endpoint gateway resource binding.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this endpoint gateway resource binding.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the resource binding.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this resource binding. The name is unique across all resource bindings for the endpoint gateway.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "service_endpoint": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The fully qualified domain name of the service endpoint for the resource targeted by this resource binding.", + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The target for this endpoint gateway resource binding.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource binding:- `weak`: The binding is not dependent on the existence of the target resource.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVirtualEndpointGatewayResourceBindingsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_virtual_endpoint_gateway_resource_bindings", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listEndpointGatewayResourceBindingsOptions := &vpcv1.ListEndpointGatewayResourceBindingsOptions{} + + listEndpointGatewayResourceBindingsOptions.SetEndpointGatewayID(d.Get("endpoint_gateway_id").(string)) + + var pager *vpcv1.EndpointGatewayResourceBindingsPager + pager, err = vpcClient.NewEndpointGatewayResourceBindingsPager(listEndpointGatewayResourceBindingsOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_virtual_endpoint_gateway_resource_bindings", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + allItems, err := pager.GetAll() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("EndpointGatewayResourceBindingsPager.GetAll() failed %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_bindings", "read") + log.Printf("[DEBUG] %s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(dataSourceIBMIsVirtualEndpointGatewayResourceBindingsID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelMap, err := DataSourceIBMIsVirtualEndpointGatewayResourceBindingsEndpointGatewayResourceBindingToMap(&modelItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_virtual_endpoint_gateway_resource_bindings", "read", "EndpointGateways-to-map").GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("resource_bindings", mapSlice); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting resource_bindings %s", err), "(Data) ibm_is_virtual_endpoint_gateway_resource_bindings", "read", "resource_bindings-set").GetDiag() + } + + return nil +} + +// dataSourceIBMIsVirtualEndpointGatewayResourceBindingsID returns a reasonable ID for the list. +func dataSourceIBMIsVirtualEndpointGatewayResourceBindingsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsVirtualEndpointGatewayResourceBindingsEndpointGatewayResourceBindingToMap(model *vpcv1.EndpointGatewayResourceBinding) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["created_at"] = model.CreatedAt.String() + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range model.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsVirtualEndpointGatewayResourceBindingsEndpointGatewayResourceBindingLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return modelMap, err + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + modelMap["lifecycle_reasons"] = lifecycleReasons + modelMap["lifecycle_state"] = *model.LifecycleState + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + modelMap["service_endpoint"] = *model.ServiceEndpoint + targetMap, err := DataSourceIBMIsVirtualEndpointGatewayResourceBindingsEndpointGatewayResourceBindingTargetToMap(model.Target) + if err != nil { + return modelMap, err + } + modelMap["target"] = []map[string]interface{}{targetMap} + modelMap["type"] = *model.Type + return modelMap, nil +} + +func DataSourceIBMIsVirtualEndpointGatewayResourceBindingsEndpointGatewayResourceBindingLifecycleReasonToMap(model *vpcv1.EndpointGatewayResourceBindingLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsVirtualEndpointGatewayResourceBindingsEndpointGatewayResourceBindingTargetToMap(model vpcv1.EndpointGatewayResourceBindingTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.EndpointGatewayResourceBindingTargetCRN); ok { + return DataSourceIBMIsVirtualEndpointGatewayResourceBindingsEndpointGatewayResourceBindingTargetCRNToMap(model.(*vpcv1.EndpointGatewayResourceBindingTargetCRN)) + } else if _, ok := model.(*vpcv1.EndpointGatewayResourceBindingTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.EndpointGatewayResourceBindingTarget) + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.EndpointGatewayResourceBindingTargetIntf subtype encountered") + } +} + +func DataSourceIBMIsVirtualEndpointGatewayResourceBindingsEndpointGatewayResourceBindingTargetCRNToMap(model *vpcv1.EndpointGatewayResourceBindingTargetCRN) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_bindings_test.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_bindings_test.go new file mode 100644 index 0000000000..d92135141d --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_resource_bindings_test.go @@ -0,0 +1,52 @@ +// Copyright IBM Corp. 2025 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsVirtualEndpointGatewayResourceBindingsDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-eg-%d-test", acctest.RandIntRange(10, 100)) + endpointGatewayName := fmt.Sprintf("tf-eg-%d-test", acctest.RandIntRange(10, 100)) + endpointGatewayRBName := fmt.Sprintf("tf-rb-eg-%d-test", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualEndpointGatewayResourceBindingsDataSourceConfigBasic(vpcname, endpointGatewayName, endpointGatewayRBName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "endpoint_gateway_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "resource_bindings.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "resource_bindings.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "resource_bindings.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "resource_bindings.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "resource_bindings.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "resource_bindings.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "resource_bindings.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "resource_bindings.0.service_endpoint"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "resource_bindings.0.target.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_endpoint_gateway_resource_bindings.testacc_vpe_rb_ds", "resource_bindings.0.type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVirtualEndpointGatewayResourceBindingsDataSourceConfigBasic(vpcname, endpointGatewayName, endpointGatewayRBName string) string { + return testAccCheckIBMIsVirtualEndpointGatewayResourceBindingConfigBasic(vpcname, endpointGatewayName, endpointGatewayRBName) + fmt.Sprintf(` + data "ibm_is_virtual_endpoint_gateway_resource_bindings" "testacc_vpe_rb_ds" { + depends_on = [ ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb ] + endpoint_gateway_id = ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb.endpoint_gateway_id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways.go index 6ff54a3b6d..aeef842b3c 100644 --- a/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways.go +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways.go @@ -53,8 +53,14 @@ func DataSourceIBMISEndpointGateways() *schema.Resource { isVirtualEndpointGatewayAllowDnsResolutionBinding: { Type: schema.TypeBool, Computed: true, + Deprecated: "This property has been deprecated in favor of dns_resolution_binding_mode.", Description: "Indicates whether to allow this endpoint gateway to participate in DNS resolution bindings with a VPC that has dns.enable_hub set to true.", }, + "dns_resolution_binding_mode": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The DNS resolution binding mode used for this endpoint gateway:- `disabled`: The endpoint gateway is not participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing).- `primary`: The endpoint gateway is participating in [DNS sharing for VPE gateways] (/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC.- `per_resource_binding`: The endpoint gateway is participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC, and resource binding is enabled for the `target` service.", + }, isVirtualEndpointGatewayResourceType: { Type: schema.TypeString, Computed: true, @@ -248,7 +254,15 @@ func dataSourceIBMISEndpointGatewaysRead(context context.Context, d *schema.Reso endpointGatewayOutput[isVirtualEndpointGatewayResourceGroupID] = *endpointGateway.ResourceGroup.ID endpointGatewayOutput[isVirtualEndpointGatewayCRN] = *endpointGateway.CRN endpointGatewayOutput[isVirtualEndpointGatewayVpcID] = *endpointGateway.VPC.ID - endpointGatewayOutput[isVirtualEndpointGatewayAllowDnsResolutionBinding] = endpointGateway.AllowDnsResolutionBinding + endpointGatewayOutput["dns_resolution_binding_mode"] = endpointGateway.DnsResolutionBindingMode + // Compute and set deprecated field for backward compatibility + if endpointGateway.DnsResolutionBindingMode != nil { + allowDnsResolutionBinding := mapDnsResolutionBindingModeToBoolean(*endpointGateway.DnsResolutionBindingMode) + endpointGatewayOutput[isVirtualEndpointGatewayAllowDnsResolutionBinding] = allowDnsResolutionBinding + } else { + // Handle case where new field might be nil/empty - default to false for backward compatibility + endpointGatewayOutput[isVirtualEndpointGatewayAllowDnsResolutionBinding] = false + } endpointGatewayOutput[isVirtualEndpointGatewayTarget] = flattenEndpointGatewayTarget(endpointGateway.Target.(*vpcv1.EndpointGatewayTarget)) if endpointGateway.SecurityGroups != nil { diff --git a/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway.go b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway.go index 1a48e54ae1..9e4e760a36 100644 --- a/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway.go +++ b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway.go @@ -243,11 +243,24 @@ func ResourceIBMISEndpointGateway() *schema.Resource { Description: "The VPC id", }, isVirtualEndpointGatewayAllowDnsResolutionBinding: { - Type: schema.TypeBool, - Optional: true, - Computed: true, + Type: schema.TypeBool, + Optional: true, + Computed: true, + ConflictsWith: []string{"dns_resolution_binding_mode"}, + Deprecated: "This field has been deprecated in favor of `dns_resolution_binding_mode` and will be removed in a future version. " + + "Migration: false='disabled', true='primary'. " + + "The new field also supports 'per_resource_binding' for advanced DNS sharing scenarios. " + + "Please update your configuration to use `dns_resolution_binding_mode`.", Description: "Indicates whether to allow this endpoint gateway to participate in DNS resolution bindings with a VPC that has dns.enable_hub set to true.", }, + "dns_resolution_binding_mode": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"allow_dns_resolution_binding"}, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_endpoint_gateway", "dns_resolution_binding_mode"), + Description: "The DNS resolution binding mode used for this endpoint gateway:- `disabled`: The endpoint gateway is not participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing).- `primary`: The endpoint gateway is participating in [DNS sharing for VPE gateways] (/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC.- `per_resource_binding`: The endpoint gateway is participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC, and resource binding is enabled for the `target` service.", + }, isVirtualEndpointGatewayTags: { Type: schema.TypeSet, Optional: true, @@ -380,9 +393,40 @@ func resourceIBMisVirtualEndpointGatewayCreate(context context.Context, d *schem } // dns resolution binding change + // Handle both new and deprecated fields with priority to new field + dnsResolutionBindingMode := "" + allowDnsResolutionBindingProvided := false + dnsResolutionBindingModeProvided := false + + // Check if deprecated field is provided if allowDnsResolutionBindingOk, ok := d.GetOkExists(isVirtualEndpointGatewayAllowDnsResolutionBinding); ok { allowDnsResolutionBinding := allowDnsResolutionBindingOk.(bool) - opt.AllowDnsResolutionBinding = &allowDnsResolutionBinding + allowDnsResolutionBindingProvided = true + // Map deprecated boolean to new enum + if allowDnsResolutionBinding { + dnsResolutionBindingMode = "primary" + } else { + dnsResolutionBindingMode = "disabled" + } + } + + // Check if new field is provided (takes priority) + if dnsResolutionBindingModeOk, ok := d.GetOkExists("dns_resolution_binding_mode"); ok { + dnsResolutionBindingModeProvided = true + dnsResolutionBindingMode = dnsResolutionBindingModeOk.(string) + + // Validate that both fields don't conflict if both are provided + if allowDnsResolutionBindingProvided { + allowDnsResolutionBinding := d.Get(isVirtualEndpointGatewayAllowDnsResolutionBinding).(bool) + if !validateFieldConsistency(allowDnsResolutionBinding, dnsResolutionBindingMode) { + return diag.Errorf("Conflicting values for allow_dns_resolution_binding and dns_resolution_binding_mode. Please use only dns_resolution_binding_mode.") + } + } + } + + // Set the new field in the API request if either field was provided + if dnsResolutionBindingModeProvided || allowDnsResolutionBindingProvided { + opt.DnsResolutionBindingMode = &dnsResolutionBindingMode } endpointGateway, response, err := sess.CreateEndpointGateway(opt) if err != nil { @@ -456,9 +500,34 @@ func resourceIBMisVirtualEndpointGatewayUpdate(context context.Context, d *schem name := d.Get(isVirtualEndpointGatewayName).(string) endpointGatewayPatchModel.Name = core.StringPtr(name) } - if d.HasChange(isVirtualEndpointGatewayAllowDnsResolutionBinding) { - allowDnsResolutionBinding := d.Get(isVirtualEndpointGatewayAllowDnsResolutionBinding).(bool) - endpointGatewayPatchModel.AllowDnsResolutionBinding = &allowDnsResolutionBinding + // Check if either field has changed + if d.HasChange(isVirtualEndpointGatewayAllowDnsResolutionBinding) || d.HasChange("dns_resolution_binding_mode") { + dnsResolutionBindingMode := "" + allowDnsResolutionBindingChanged := d.HasChange(isVirtualEndpointGatewayAllowDnsResolutionBinding) + dnsResolutionBindingModeChanged := d.HasChange("dns_resolution_binding_mode") + + // Priority: new field takes precedence over deprecated field + if dnsResolutionBindingModeChanged { + dnsResolutionBindingMode = d.Get("dns_resolution_binding_mode").(string) + + // Validate consistency if both fields changed + if allowDnsResolutionBindingChanged { + allowDnsResolutionBinding := d.Get(isVirtualEndpointGatewayAllowDnsResolutionBinding).(bool) + if !validateFieldConsistency(allowDnsResolutionBinding, dnsResolutionBindingMode) { + return diag.Errorf("Conflicting values for allow_dns_resolution_binding and dns_resolution_binding_mode. Please use only dns_resolution_binding_mode.") + } + } + } else if allowDnsResolutionBindingChanged { + // Only deprecated field changed, map it to new field + allowDnsResolutionBinding := d.Get(isVirtualEndpointGatewayAllowDnsResolutionBinding).(bool) + if allowDnsResolutionBinding { + dnsResolutionBindingMode = "primary" + } else { + dnsResolutionBindingMode = "disabled" + } + } + + endpointGatewayPatchModel.DnsResolutionBindingMode = &dnsResolutionBindingMode } endpointGatewayPatchModelAsPatch, _ := endpointGatewayPatchModel.AsPatch() opt := sess.NewUpdateEndpointGatewayOptions(d.Id(), endpointGatewayPatchModelAsPatch) @@ -574,7 +643,23 @@ func resourceIBMisVirtualEndpointGatewayRead(context context.Context, d *schema. if err := d.Set(isVirtualEndpointGatewayLifecycleReasons, resourceEGWFlattenLifecycleReasons(endpointGateway.LifecycleReasons)); err != nil { return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("[ERROR] Error setting lifecycle_reasons: %s", err), "ibm_is_virtual_endpoint_gateway", "read", "set-lifecycle-reasons").GetDiag() } - d.Set(isVirtualEndpointGatewayAllowDnsResolutionBinding, endpointGateway.AllowDnsResolutionBinding) + // Set the new field from API response + if err = d.Set("dns_resolution_binding_mode", endpointGateway.DnsResolutionBindingMode); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("[ERROR] Error setting dns_resolution_binding_mode: %s", err), "ibm_is_virtual_endpoint_gateway", "read", "set-dns_resolution_binding_mode").GetDiag() + } + + // Compute and set deprecated field for backward compatibility + if endpointGateway.DnsResolutionBindingMode != nil { + allowDnsResolutionBinding := mapDnsResolutionBindingModeToBoolean(*endpointGateway.DnsResolutionBindingMode) + if err = d.Set(isVirtualEndpointGatewayAllowDnsResolutionBinding, allowDnsResolutionBinding); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("[ERROR] Error setting dns_resolution_binding_mode: %s", err), "ibm_is_virtual_endpoint_gateway", "read", "set-allow_dns_resolution_binding").GetDiag() + } + } else { + // Handle case where new field might be nil/empty - default to false for backward compatibility + if err = d.Set(isVirtualEndpointGatewayAllowDnsResolutionBinding, false); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("[ERROR] Error setting dns_resolution_binding_mode: %s", err), "ibm_is_virtual_endpoint_gateway", "read", "set-allow_dns_resolution_binding").GetDiag() + } + } d.Set(isVirtualEndpointGatewayResourceType, endpointGateway.ResourceType) d.Set(isVirtualEndpointGatewayCRN, endpointGateway.CRN) d.Set(isVirtualEndpointGatewayIPs, flattenIPs(endpointGateway.Ips)) @@ -814,3 +899,15 @@ func resourceEGWFlattenLifecycleReasons(lifecycleReasons []vpcv1.EndpointGateway } return lifecycleReasonsList } + +// Validate that deprecated and new fields are consistent +func validateFieldConsistency(allowDnsResolutionBinding bool, dnsResolutionBindingMode string) bool { + switch dnsResolutionBindingMode { + case "disabled": + return !allowDnsResolutionBinding + case "primary", "per_resource_binding": + return allowDnsResolutionBinding + default: + return false // Unknown mode + } +} diff --git a/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_resource_binding.go b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_resource_binding.go new file mode 100644 index 0000000000..b3258bc91a --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_resource_binding.go @@ -0,0 +1,404 @@ +// Copyright IBM Corp. 2025 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsVirtualEndpointGatewayResourceBinding() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsVirtualEndpointGatewayResourceBindingCreate, + ReadContext: resourceIBMIsVirtualEndpointGatewayResourceBindingRead, + UpdateContext: resourceIBMIsVirtualEndpointGatewayResourceBindingUpdate, + DeleteContext: resourceIBMIsVirtualEndpointGatewayResourceBindingDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "endpoint_gateway_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_endpoint_gateway_resource_binding", "endpoint_gateway_id"), + Description: "The endpoint gateway identifier.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_endpoint_gateway_resource_binding", "name"), + Description: "The name for this resource binding. The name is unique across all resource bindings for the endpoint gateway.", + }, + "target": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "The target for this endpoint gateway resource binding.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the resource binding was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this endpoint gateway resource binding.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "A link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the resource binding.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "service_endpoint": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The fully qualified domain name of the service endpoint for the resource targeted by this resource binding.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource binding:- `weak`: The binding is not dependent on the existence of the target resource.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "endpoint_gateway_resource_binding_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this endpoint gateway resource binding.", + }, + }, + } +} + +func ResourceIBMIsVirtualEndpointGatewayResourceBindingValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "endpoint_gateway_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z_]+$`, + MinValueLength: 1, + MaxValueLength: 64, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_virtual_endpoint_gateway_resource_binding", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsVirtualEndpointGatewayResourceBindingCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "create", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + createEndpointGatewayResourceBindingOptions := &vpcv1.CreateEndpointGatewayResourceBindingOptions{} + + createEndpointGatewayResourceBindingOptions.SetEndpointGatewayID(d.Get("endpoint_gateway_id").(string)) + targetModel, err := ResourceIBMIsVirtualEndpointGatewayResourceBindingMapToEndpointGatewayResourceBindingTargetPrototype(d.Get("target.0").(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "create", "parse-target").GetDiag() + } + createEndpointGatewayResourceBindingOptions.SetTarget(targetModel) + if _, ok := d.GetOk("name"); ok { + createEndpointGatewayResourceBindingOptions.SetName(d.Get("name").(string)) + } + + endpointGatewayResourceBinding, _, err := vpcClient.CreateEndpointGatewayResourceBindingWithContext(context, createEndpointGatewayResourceBindingOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateEndpointGatewayResourceBindingWithContext failed: %s", err.Error()), "ibm_is_virtual_endpoint_gateway_resource_binding", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *createEndpointGatewayResourceBindingOptions.EndpointGatewayID, *endpointGatewayResourceBinding.ID)) + + return resourceIBMIsVirtualEndpointGatewayResourceBindingRead(context, d, meta) +} + +func resourceIBMIsVirtualEndpointGatewayResourceBindingRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getEndpointGatewayResourceBindingOptions := &vpcv1.GetEndpointGatewayResourceBindingOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "sep-id-parts").GetDiag() + } + + getEndpointGatewayResourceBindingOptions.SetEndpointGatewayID(parts[0]) + getEndpointGatewayResourceBindingOptions.SetID(parts[1]) + + endpointGatewayResourceBinding, response, err := vpcClient.GetEndpointGatewayResourceBindingWithContext(context, getEndpointGatewayResourceBindingOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetEndpointGatewayResourceBindingWithContext failed: %s", err.Error()), "ibm_is_virtual_endpoint_gateway_resource_binding", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + if !core.IsNil(endpointGatewayResourceBinding.Name) { + if err = d.Set("name", endpointGatewayResourceBinding.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-name").GetDiag() + } + } + targetMap, err := ResourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingTargetToMap(endpointGatewayResourceBinding.Target) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "target-to-map").GetDiag() + } + if err = d.Set("target", []map[string]interface{}{targetMap}); err != nil { + err = fmt.Errorf("Error setting target: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-target").GetDiag() + } + if err = d.Set("created_at", flex.DateTimeToString(endpointGatewayResourceBinding.CreatedAt)); err != nil { + err = fmt.Errorf("Error setting created_at: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-created_at").GetDiag() + } + if err = d.Set("href", endpointGatewayResourceBinding.Href); err != nil { + err = fmt.Errorf("Error setting href: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-href").GetDiag() + } + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range endpointGatewayResourceBinding.LifecycleReasons { + lifecycleReasonsItemMap, err := ResourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + err = fmt.Errorf("Error setting lifecycle_reasons: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-lifecycle_reasons").GetDiag() + } + if err = d.Set("lifecycle_state", endpointGatewayResourceBinding.LifecycleState); err != nil { + err = fmt.Errorf("Error setting lifecycle_state: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-lifecycle_state").GetDiag() + } + if err = d.Set("resource_type", endpointGatewayResourceBinding.ResourceType); err != nil { + err = fmt.Errorf("Error setting resource_type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-resource_type").GetDiag() + } + if err = d.Set("service_endpoint", endpointGatewayResourceBinding.ServiceEndpoint); err != nil { + err = fmt.Errorf("Error setting service_endpoint: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-service_endpoint").GetDiag() + } + if err = d.Set("type", endpointGatewayResourceBinding.Type); err != nil { + err = fmt.Errorf("Error setting type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-type").GetDiag() + } + if err = d.Set("endpoint_gateway_resource_binding_id", endpointGatewayResourceBinding.ID); err != nil { + err = fmt.Errorf("Error setting endpoint_gateway_resource_binding_id: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "read", "set-endpoint_gateway_resource_binding_id").GetDiag() + } + + return nil +} + +func resourceIBMIsVirtualEndpointGatewayResourceBindingUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "update", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + updateEndpointGatewayResourceBindingOptions := &vpcv1.UpdateEndpointGatewayResourceBindingOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "update", "sep-id-parts").GetDiag() + } + + updateEndpointGatewayResourceBindingOptions.SetEndpointGatewayID(parts[0]) + updateEndpointGatewayResourceBindingOptions.SetID(parts[1]) + + hasChange := false + + patchVals := &vpcv1.EndpointGatewayResourceBindingPatch{} + if d.HasChange("endpoint_gateway_id") { + errMsg := fmt.Sprintf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "endpoint_gateway_id") + return flex.DiscriminatedTerraformErrorf(nil, errMsg, "ibm_is_virtual_endpoint_gateway_resource_binding", "update", "endpoint_gateway_id-forces-new").GetDiag() + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + // Fields with `nil` values are omitted from the generic map, + // so we need to re-add them to support removing arguments + // in merge-patch operations sent to the service. + updateEndpointGatewayResourceBindingOptions.EndpointGatewayResourceBindingPatch = ResourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingPatchAsPatch(patchVals, d) + + _, _, err = vpcClient.UpdateEndpointGatewayResourceBindingWithContext(context, updateEndpointGatewayResourceBindingOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateEndpointGatewayResourceBindingWithContext failed: %s", err.Error()), "ibm_is_virtual_endpoint_gateway_resource_binding", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + + return resourceIBMIsVirtualEndpointGatewayResourceBindingRead(context, d, meta) +} + +func resourceIBMIsVirtualEndpointGatewayResourceBindingDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "delete", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + deleteEndpointGatewayResourceBindingOptions := &vpcv1.DeleteEndpointGatewayResourceBindingOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_virtual_endpoint_gateway_resource_binding", "delete", "sep-id-parts").GetDiag() + } + + deleteEndpointGatewayResourceBindingOptions.SetEndpointGatewayID(parts[0]) + deleteEndpointGatewayResourceBindingOptions.SetID(parts[1]) + + _, err = vpcClient.DeleteEndpointGatewayResourceBindingWithContext(context, deleteEndpointGatewayResourceBindingOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeleteEndpointGatewayResourceBindingWithContext failed: %s", err.Error()), "ibm_is_virtual_endpoint_gateway_resource_binding", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId("") + + return nil +} + +func ResourceIBMIsVirtualEndpointGatewayResourceBindingMapToEndpointGatewayResourceBindingTargetPrototype(modelMap map[string]interface{}) (vpcv1.EndpointGatewayResourceBindingTargetPrototypeIntf, error) { + model := &vpcv1.EndpointGatewayResourceBindingTargetPrototype{} + if modelMap["crn"] != nil && modelMap["crn"].(string) != "" { + model.CRN = core.StringPtr(modelMap["crn"].(string)) + } + return model, nil +} + +func ResourceIBMIsVirtualEndpointGatewayResourceBindingMapToEndpointGatewayResourceBindingTargetPrototypeEndpointGatewayResourceBindingTargetByCRN(modelMap map[string]interface{}) (*vpcv1.EndpointGatewayResourceBindingTargetPrototypeEndpointGatewayResourceBindingTargetByCRN, error) { + model := &vpcv1.EndpointGatewayResourceBindingTargetPrototypeEndpointGatewayResourceBindingTargetByCRN{} + model.CRN = core.StringPtr(modelMap["crn"].(string)) + return model, nil +} + +func ResourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingTargetToMap(model vpcv1.EndpointGatewayResourceBindingTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.EndpointGatewayResourceBindingTargetCRN); ok { + return ResourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingTargetCRNToMap(model.(*vpcv1.EndpointGatewayResourceBindingTargetCRN)) + } else if _, ok := model.(*vpcv1.EndpointGatewayResourceBindingTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.EndpointGatewayResourceBindingTarget) + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.EndpointGatewayResourceBindingTargetIntf subtype encountered") + } +} + +func ResourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingTargetCRNToMap(model *vpcv1.EndpointGatewayResourceBindingTargetCRN) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + return modelMap, nil +} + +func ResourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingLifecycleReasonToMap(model *vpcv1.EndpointGatewayResourceBindingLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func ResourceIBMIsVirtualEndpointGatewayResourceBindingEndpointGatewayResourceBindingPatchAsPatch(patchVals *vpcv1.EndpointGatewayResourceBindingPatch, d *schema.ResourceData) map[string]interface{} { + patch, _ := patchVals.AsPatch() + var path string + + path = "name" + if _, exists := d.GetOk(path); d.HasChange(path) && !exists { + patch["name"] = nil + } else if !exists { + delete(patch, "name") + } + + return patch +} diff --git a/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_resource_binding_test.go b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_resource_binding_test.go new file mode 100644 index 0000000000..a3bd41dc11 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_resource_binding_test.go @@ -0,0 +1,165 @@ +// Copyright IBM Corp. 2025 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsVirtualEndpointGatewayResourceBindingBasic(t *testing.T) { + var conf vpcv1.EndpointGatewayResourceBinding + vpcname := fmt.Sprintf("tf-vpc-eg-%d-test", acctest.RandIntRange(10, 100)) + endpointGatewayName := fmt.Sprintf("tf-eg-%d-test", acctest.RandIntRange(10, 100)) + endpointGatewayRBName := fmt.Sprintf("tf-rb-eg-%d-test", acctest.RandIntRange(10, 100)) + endpointGatewayRBNameUpdated := fmt.Sprintf("tf-rb-eg-updated-%d-test", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsVirtualEndpointGatewayResourceBindingDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualEndpointGatewayResourceBindingConfigBasic(vpcname, endpointGatewayName, endpointGatewayRBName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsVirtualEndpointGatewayResourceBindingExists("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", conf), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "endpoint_gateway_id"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "endpoint_gateway_resource_binding_id"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "href"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "id"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "name"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "service_endpoint"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "type"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "target.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "target.0.crn"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "name", endpointGatewayRBName), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsVirtualEndpointGatewayResourceBindingConfigBasic(vpcname, endpointGatewayName, endpointGatewayRBNameUpdated), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsVirtualEndpointGatewayResourceBindingExists("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", conf), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "endpoint_gateway_id"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "endpoint_gateway_resource_binding_id"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "href"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "id"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "name"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "service_endpoint"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "type"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "target.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "target.0.crn"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway_resource_binding.testacc_vpe_rb", "name", endpointGatewayRBNameUpdated), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVirtualEndpointGatewayResourceBindingConfigBasic(vpcName, egname, egResourceBindingName string) string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_virtual_endpoint_gateway" "testacc_vpe" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + + target { + resource_type = "%s" + crn = "%s" + } + dns_resolution_binding_mode = "disabled" + } + + resource "ibm_is_virtual_endpoint_gateway_resource_binding" "testacc_vpe_rb" { + name = "%s" + endpoint_gateway_id = ibm_is_virtual_endpoint_gateway.testacc_vpe.id + target { + crn = "%s" + } + } + `, vpcName, egname, acc.IsEndpointGatewayTargetType, acc.IsEndpointGatewayTargetCRN, egResourceBindingName, acc.IsResourceBindingCRN) +} + +func testAccCheckIBMIsVirtualEndpointGatewayResourceBindingExists(n string, obj vpcv1.EndpointGatewayResourceBinding) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + + getEndpointGatewayResourceBindingOptions := &vpcv1.GetEndpointGatewayResourceBindingOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getEndpointGatewayResourceBindingOptions.SetEndpointGatewayID(parts[0]) + getEndpointGatewayResourceBindingOptions.SetID(parts[1]) + + endpointGatewayResourceBinding, _, err := vpcClient.GetEndpointGatewayResourceBinding(getEndpointGatewayResourceBindingOptions) + if err != nil { + return err + } + + obj = *endpointGatewayResourceBinding + return nil + } +} + +func testAccCheckIBMIsVirtualEndpointGatewayResourceBindingDestroy(s *terraform.State) error { + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_virtual_endpoint_gateway_resource_binding" { + continue + } + + getEndpointGatewayResourceBindingOptions := &vpcv1.GetEndpointGatewayResourceBindingOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getEndpointGatewayResourceBindingOptions.SetEndpointGatewayID(parts[0]) + getEndpointGatewayResourceBindingOptions.SetID(parts[1]) + + // Try to find the key + _, response, err := vpcClient.GetEndpointGatewayResourceBinding(getEndpointGatewayResourceBindingOptions) + + if err == nil { + return fmt.Errorf("EndpointGatewayResourceBinding still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for EndpointGatewayResourceBinding (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_test.go b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_test.go index 455fa774b6..5652d1fad7 100644 --- a/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_test.go +++ b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_test.go @@ -564,3 +564,306 @@ func TestAccIBMISVirtualEndpointGateway_ServiceEndpoints(t *testing.T) { }, }) } + +// dns resolution binding mode tests +func TestAccIBMISVirtualEndpointGateway_DnsResolutionBindingMode(t *testing.T) { + var endpointGateway string + vpcName := fmt.Sprintf("tf-vpe-vpc-%d", acctest.RandIntRange(10, 100)) + gatewayName1 := fmt.Sprintf("tf-vpe-gateway-1-%d", acctest.RandIntRange(10, 100)) + gatewayName2 := fmt.Sprintf("tf-vpe-gateway-2-%d", acctest.RandIntRange(10, 100)) + gatewayName3 := fmt.Sprintf("tf-vpe-gateway-3-%d", acctest.RandIntRange(10, 100)) + gatewayName4 := fmt.Sprintf("tf-vpe-gateway-4-%d", acctest.RandIntRange(10, 100)) + gatewayName5 := fmt.Sprintf("tf-vpe-gateway-5-%d", acctest.RandIntRange(10, 100)) + gatewayName6 := fmt.Sprintf("tf-vpe-gateway-6-%d", acctest.RandIntRange(10, 100)) + gatewayName7 := fmt.Sprintf("tf-vpe-gateway-7-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + // Step 1: Create VPC only + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveVPCOnly(vpcName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.testacc_vpc", "name", vpcName), + ), + }, + // Step 2: Add VPE Gateway 1 - Deprecated field with allow_dns_resolution_binding = true + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName1, "vpe_gateway_1", "deprecated", "true", ""), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_1", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_1", "name", gatewayName1), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_1", "allow_dns_resolution_binding", "true"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_1", "dns_resolution_binding_mode", "primary"), + ), + }, + // Step 3: Update VPE Gateway 1 - Change deprecated field from true to false (in-place update) + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName1, "vpe_gateway_1", "deprecated", "false", ""), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_1", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_1", "name", gatewayName1), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_1", "allow_dns_resolution_binding", "false"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_1", "dns_resolution_binding_mode", "disabled"), + ), + }, + // Step 4: Remove VPE Gateway 1 - VPC only + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveVPCOnly(vpcName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.testacc_vpc", "name", vpcName), + ), + }, + // Step 5: Add VPE Gateway 2 - Deprecated field with allow_dns_resolution_binding = false + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName2, "vpe_gateway_2", "deprecated", "false", ""), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_2", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_2", "name", gatewayName2), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_2", "allow_dns_resolution_binding", "false"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_2", "dns_resolution_binding_mode", "disabled"), + ), + }, + // Step 6: Remove VPE Gateway 2 - VPC only + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveVPCOnly(vpcName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.testacc_vpc", "name", vpcName), + ), + }, + // Step 7: Add VPE Gateway 3 - New field with dns_resolution_binding_mode = "primary" + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName3, "vpe_gateway_3", "new", "", "primary"), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", "name", gatewayName3), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", "dns_resolution_binding_mode", "primary"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", "allow_dns_resolution_binding", "true"), + ), + }, + // Step 8: Update VPE Gateway 3 - Change new field from primary to disabled (in-place update) + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName3, "vpe_gateway_3", "new", "", "disabled"), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", "name", gatewayName3), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", "dns_resolution_binding_mode", "disabled"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", "allow_dns_resolution_binding", "false"), + ), + }, + // Step 9: Update VPE Gateway 3 - Change to per_resource_binding (in-place update) + // { + // Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName3, "vpe_gateway_3", "new", "", "per_resource_binding"), + // Check: resource.ComposeTestCheckFunc( + // testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", &endpointGateway), + // resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", "name", gatewayName3), + // resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", "dns_resolution_binding_mode", "per_resource_binding"), + // resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_3", "allow_dns_resolution_binding", "true"), + // ), + // }, + // Step 10: Remove VPE Gateway 3 - VPC only + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveVPCOnly(vpcName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.testacc_vpc", "name", vpcName), + ), + }, + // Step 11: Add VPE Gateway 4 - Deprecated field with allow_dns_resolution_binding = true + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName4, "vpe_gateway_4", "deprecated", "true", ""), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", "name", gatewayName4), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", "allow_dns_resolution_binding", "true"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", "dns_resolution_binding_mode", "primary"), + ), + }, + // Step 12: MIGRATION - Remove deprecated field, add new field with equivalent value (primary) + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName4, "vpe_gateway_4", "new", "", "primary"), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", "name", gatewayName4), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", "dns_resolution_binding_mode", "primary"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", "allow_dns_resolution_binding", "true"), + ), + }, + // Step 13: Update to per_resource_binding (new capability not available in deprecated field) + // { + // Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName4, "vpe_gateway_4", "new", "", "per_resource_binding"), + // Check: resource.ComposeTestCheckFunc( + // testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", &endpointGateway), + // resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", "name", gatewayName4), + // resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", "dns_resolution_binding_mode", "per_resource_binding"), + // resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_4", "allow_dns_resolution_binding", "true"), + // ), + // }, + // Step 14: Remove VPE Gateway 4 - VPC only + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveVPCOnly(vpcName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.testacc_vpc", "name", vpcName), + ), + }, + // Step 15: Add VPE Gateway 5 - Deprecated field with allow_dns_resolution_binding = false + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName5, "vpe_gateway_5", "deprecated", "false", ""), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", "name", gatewayName5), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", "allow_dns_resolution_binding", "false"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", "dns_resolution_binding_mode", "disabled"), + ), + }, + // Step 16: MIGRATION - Remove deprecated field (false), add new field with equivalent value (disabled) + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName5, "vpe_gateway_5", "new", "", "disabled"), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", "name", gatewayName5), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", "dns_resolution_binding_mode", "disabled"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", "allow_dns_resolution_binding", "false"), + ), + }, + // Step 17: Update to primary (enabling DNS resolution binding) + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName5, "vpe_gateway_5", "new", "", "primary"), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", "name", gatewayName5), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", "dns_resolution_binding_mode", "primary"), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_5", "allow_dns_resolution_binding", "true"), + ), + }, + // Step 18: Remove VPE Gateway 5 - VPC only + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveVPCOnly(vpcName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.testacc_vpc", "name", vpcName), + ), + }, + // Step 19: Add VPE Gateway 6 - No field specified (test default behavior) + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName6, "vpe_gateway_6", "none", "", ""), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_6", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_6", "name", gatewayName6), + // Should have computed default values from API + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway.vpe_gateway_6", "dns_resolution_binding_mode"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_endpoint_gateway.vpe_gateway_6", "allow_dns_resolution_binding"), + ), + }, + // Step 20: Remove VPE Gateway 6 - VPC only + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveVPCOnly(vpcName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.testacc_vpc", "name", vpcName), + ), + }, + // Step 21: Add VPE Gateway 7 - Test all three modes sequentially via updates + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName7, "vpe_gateway_7", "new", "", "disabled"), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_7", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_7", "dns_resolution_binding_mode", "disabled"), + ), + }, + // Step 22: Update VPE Gateway 7 to primary + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName7, "vpe_gateway_7", "new", "", "primary"), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_7", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_7", "dns_resolution_binding_mode", "primary"), + ), + }, + // Step 23: Update VPE Gateway 7 to per_resource_binding + // { + // Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName7, "vpe_gateway_7", "new", "", "per_resource_binding"), + // Check: resource.ComposeTestCheckFunc( + // testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_7", &endpointGateway), + // resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_7", "dns_resolution_binding_mode", "per_resource_binding"), + // ), + // }, + // Step 24: Update VPE Gateway 7 back to disabled (full cycle) + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName7, "vpe_gateway_7", "new", "", "disabled"), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists("ibm_is_virtual_endpoint_gateway.vpe_gateway_7", &endpointGateway), + resource.TestCheckResourceAttr("ibm_is_virtual_endpoint_gateway.vpe_gateway_7", "dns_resolution_binding_mode", "disabled"), + ), + }, + // Step 25: Final cleanup - Remove VPE Gateway 7, VPC remains + { + Config: testAccCheckIBMISVirtualEndpointGatewayComprehensiveVPCOnly(vpcName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.testacc_vpc", "name", vpcName), + ), + }, + }, + }) +} + +// Helper function for VPC only config +func testAccCheckIBMISVirtualEndpointGatewayComprehensiveVPCOnly(vpcName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + `, vpcName) +} + +// Helper function for VPC + VPE Gateway config +func testAccCheckIBMISVirtualEndpointGatewayComprehensiveConfig(vpcName, gatewayName, resourceName, fieldType, deprecatedValue, newValue string) string { + baseConfig := fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + `, vpcName) + + var gatewayConfig string + + if fieldType == "deprecated" { + // Using deprecated field + gatewayConfig = fmt.Sprintf(` + resource "ibm_is_virtual_endpoint_gateway" "%s" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + + target { + name = "ibm-ntp-server" + resource_type = "provider_infrastructure_service" + } + + allow_dns_resolution_binding = %s + }`, resourceName, gatewayName, deprecatedValue) + } else if fieldType == "new" { + // Using new field + gatewayConfig = fmt.Sprintf(` + resource "ibm_is_virtual_endpoint_gateway" "%s" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + + target { + name = "ibm-ntp-server" + resource_type = "provider_infrastructure_service" + } + + dns_resolution_binding_mode = "%s" + }`, resourceName, gatewayName, newValue) + } else if fieldType == "none" { + // No DNS field specified - test defaults + gatewayConfig = fmt.Sprintf(` + resource "ibm_is_virtual_endpoint_gateway" "%s" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + + target { + name = "ibm-ntp-server" + resource_type = "provider_infrastructure_service" + } + }`, resourceName, gatewayName) + } + + return baseConfig + gatewayConfig +} diff --git a/website/docs/d/is_virtual_endpoint_gateway.html.markdown b/website/docs/d/is_virtual_endpoint_gateway.html.markdown index f94914e725..716a25fc1a 100644 --- a/website/docs/d/is_virtual_endpoint_gateway.html.markdown +++ b/website/docs/d/is_virtual_endpoint_gateway.html.markdown @@ -38,9 +38,21 @@ In addition to the argument reference list, you can access the following attribu - `access_tags` - (List) Access management tags associated for the virtual endpoint gateway. -- `allow_dns_resolution_binding` - (Bool) Indicates whether to allow this endpoint gateway to participate in DNS resolution bindings with a VPC that has dns.enable_hub set to true. +- `allow_dns_resolution_binding` - (**Deprecated**, Optional, bool) **This field has been deprecated in favor of `dns_resolution_binding_mode` and will be removed in a future version.** + + Previously indicated whether to allow this endpoint gateway to participate in DNS resolution bindings with a VPC that has dns.enable_hub set to true. + + **Migration Guide:** + - `false` → use `dns_resolution_binding_mode = "disabled"` + - `true` → use `dns_resolution_binding_mode = "primary"` + + **Note:** The new `dns_resolution_binding_mode` field also supports `"per_resource_binding"` for advanced DNS sharing scenarios not available with this boolean field. + + ~> **Important:** Do not use both `allow_dns_resolution_binding` and `dns_resolution_binding_mode` in the same configuration. Use only `dns_resolution_binding_mode`. - `created_at` - (Timestamp) The created date and time of the endpoint gateway. - `crn` - (String) The CRN for this endpoint gateway. +- `dns_resolution_binding_mode` - (String) The DNS resolution binding mode used for this endpoint gateway:- `disabled`: The endpoint gateway is not participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing).- `primary`: The endpoint gateway is participating in [DNS sharing for VPE gateways] (/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC.- `per_resource_binding`: The endpoint gateway is participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC, and resource binding is enabled for the `target` service. + - Constraints: Allowable values are: `disabled`, `per_resource_binding`, `primary`. - `health_state` - (String) Endpoint gateway health state. `ok: Healthy`, `degraded: Suffering from compromised performance, capacity, or connectivity`, `faulted: Completely unreachable, inoperative, or entirely incapacitated`, `inapplicable: The health state does not apply because of the current lifecycle state`. A resource with a lifecycle state of failed or deleting will have a health state of inapplicable. A pending resource may have this state. - `lifecycle_state` - (String) The endpoint gateway lifecycle state, supported values are **deleted**, **deleting**, **failed**, **pending**, **stable**, **updating**, **waiting**, **suspended**. - `ips` - (List) The unique identifier for the reserved IP. diff --git a/website/docs/d/is_virtual_endpoint_gateway_resource_binding.html.markdown b/website/docs/d/is_virtual_endpoint_gateway_resource_binding.html.markdown new file mode 100644 index 0000000000..1ce33e5ef1 --- /dev/null +++ b/website/docs/d/is_virtual_endpoint_gateway_resource_binding.html.markdown @@ -0,0 +1,61 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_virtual_endpoint_gateway_resource_binding" +description: |- + Get information about EndpointGatewayResourceBinding +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_virtual_endpoint_gateway_resource_binding + +Provides a read-only data source to retrieve information about an EndpointGatewayResourceBinding. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_is_virtual_endpoint_gateway_resource_binding" "is_virtual_endpoint_gateway_resource_binding" { + endpoint_gateway_id = ibm_is_virtual_endpoint_gateway_resource_binding.is_virtual_endpoint_gateway_resource_binding_instance.endpoint_gateway_id + endpoint_gateway_resource_binding_id = ibm_is_virtual_endpoint_gateway_resource_binding.is_virtual_endpoint_gateway_resource_binding_instance.endpoint_gateway_resource_binding_id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `endpoint_gateway_id` - (Required, Forces new resource, String) The endpoint gateway identifier. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. +* `endpoint_gateway_resource_binding_id` - (Required, Forces new resource, String) The resource binding identifier. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the EndpointGatewayResourceBinding. +* `created_at` - (String) The date and time that the resource binding was created. +* `href` - (String) The URL for this endpoint gateway resource binding. + * Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + * Constraints: The minimum length is `0` items. +Nested schema for **lifecycle_reasons**: + * `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + * Constraints: Allowable values are: `internal_error`, `resource_suspended_by_provider`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. + * `message` - (String) An explanation of the reason for this lifecycle state. + * `more_info` - (String) A link to documentation about the reason for this lifecycle state. + * Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `lifecycle_state` - (String) The lifecycle state of the resource binding. + * Constraints: Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. +* `name` - (String) The name for this resource binding. The name is unique across all resource bindings for the endpoint gateway. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. +* `resource_type` - (String) The resource type. + * Constraints: Allowable values are: `endpoint_gateway_resource_binding`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. +* `service_endpoint` - (String) The fully qualified domain name of the service endpoint for the resource targeted by this resource binding. + * Constraints: The maximum length is `255` characters. The minimum length is `4` characters. The value must match regular expression `/^((?=[A-Za-z0-9-]{1,63}\\.)[A-Za-z0-9-]*\\.)+[A-Za-z]{2,63}\\.?$/`. +* `target` - (List) The target for this endpoint gateway resource binding. +Nested schema for **target**: + * `crn` - (String) + * Constraints: The maximum length is `512` characters. The minimum length is `17` characters. The value must match regular expression `/^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\\.\/]*$/`. +* `type` - (String) The type of resource binding:- `weak`: The binding is not dependent on the existence of the target resource.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + * Constraints: Allowable values are: `weak`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. + diff --git a/website/docs/d/is_virtual_endpoint_gateway_resource_bindings.html.markdown b/website/docs/d/is_virtual_endpoint_gateway_resource_bindings.html.markdown new file mode 100644 index 0000000000..0f2f4b01f8 --- /dev/null +++ b/website/docs/d/is_virtual_endpoint_gateway_resource_bindings.html.markdown @@ -0,0 +1,62 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_virtual_endpoint_gateway_resource_bindings" +description: |- + Get information about EndpointGatewayResourceBindingCollection +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_virtual_endpoint_gateway_resource_bindings + +Provides a read-only data source to retrieve information about an EndpointGatewayResourceBindingCollection. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_is_virtual_endpoint_gateway_resource_bindings" "is_virtual_endpoint_gateway_resource_bindings" { + endpoint_gateway_id = ibm_is_virtual_endpoint_gateway_resource_binding.is_virtual_endpoint_gateway_resource_binding_instance.endpoint_gateway_id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `endpoint_gateway_id` - (Required, Forces new resource, String) The endpoint gateway identifier. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the EndpointGatewayResourceBindingCollection. +* `resource_bindings` - (List) A page of resource bindings for the endpoint gateway. +Nested schema for **resource_bindings**: + * `created_at` - (String) The date and time that the resource binding was created. + * `href` - (String) The URL for this endpoint gateway resource binding. + * Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `id` - (String) The unique identifier for this endpoint gateway resource binding. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + * `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + * Constraints: The minimum length is `0` items. + Nested schema for **lifecycle_reasons**: + * `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + * Constraints: Allowable values are: `internal_error`, `resource_suspended_by_provider`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. + * `message` - (String) An explanation of the reason for this lifecycle state. + * `more_info` - (String) A link to documentation about the reason for this lifecycle state. + * Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `lifecycle_state` - (String) The lifecycle state of the resource binding. + * Constraints: Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. + * `name` - (String) The name for this resource binding. The name is unique across all resource bindings for the endpoint gateway. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + * `resource_type` - (String) The resource type. + * Constraints: Allowable values are: `endpoint_gateway_resource_binding`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. + * `service_endpoint` - (String) The fully qualified domain name of the service endpoint for the resource targeted by this resource binding. + * Constraints: The maximum length is `255` characters. The minimum length is `4` characters. The value must match regular expression `/^((?=[A-Za-z0-9-]{1,63}\\.)[A-Za-z0-9-]*\\.)+[A-Za-z]{2,63}\\.?$/`. + * `target` - (List) The target for this endpoint gateway resource binding. + Nested schema for **target**: + * `crn` - (String) + * Constraints: The maximum length is `512` characters. The minimum length is `17` characters. The value must match regular expression `/^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\\.\/]*$/`. + * `type` - (String) The type of resource binding:- `weak`: The binding is not dependent on the existence of the target resource.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + * Constraints: Allowable values are: `weak`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. + diff --git a/website/docs/d/is_virtual_endpoint_gateways.html.markdown b/website/docs/d/is_virtual_endpoint_gateways.html.markdown index 81dbcb7077..00f3d14f72 100644 --- a/website/docs/d/is_virtual_endpoint_gateways.html.markdown +++ b/website/docs/d/is_virtual_endpoint_gateways.html.markdown @@ -31,6 +31,8 @@ data "ibm_is_virtual_endpoint_gateways" "example" { Review the argument references that you can specify for your data source. +- `dns_resolution_binding_mode` - (Optional, List) Filters the collection to endpoint gateways with a `dns_resolution_binding_mode` property matching one of the specified comma-separated values. + - Constraints: Allowable list items are: `disabled`, `per_resource_binding`, `primary`. - `resource_group` - (String) The ID of the Resource group this endpoint gateway belongs to - `name` - (String) The name of the endpoint gateway @@ -42,9 +44,21 @@ In addition to the argument reference list, you can access the following attribu Nested scheme for `virtual_endpoint_gateways`: - `access_tags` - (List) Access management tags associated for the virtual endpoint gateway. - - `allow_dns_resolution_binding` - (Bool) Indicates whether to allow this endpoint gateway to participate in DNS resolution bindings with a VPC that has dns.enable_hub set to true. + - `allow_dns_resolution_binding` - (**Deprecated**, Optional, bool) **This field has been deprecated in favor of `dns_resolution_binding_mode` and will be removed in a future version.** + + Previously indicated whether to allow this endpoint gateway to participate in DNS resolution bindings with a VPC that has dns.enable_hub set to true. + + **Migration Guide:** + - `false` → use `dns_resolution_binding_mode = "disabled"` + - `true` → use `dns_resolution_binding_mode = "primary"` + + **Note:** The new `dns_resolution_binding_mode` field also supports `"per_resource_binding"` for advanced DNS sharing scenarios not available with this boolean field. + + ~> **Important:** Do not use both `allow_dns_resolution_binding` and `dns_resolution_binding_mode` in the same configuration. Use only `dns_resolution_binding_mode`. - `created_at` - (Timestamp) The created date and time of the endpoint gateway. - `crn` - (String) The CRN for this endpoint gateway. + - `dns_resolution_binding_mode` - (String) The DNS resolution binding mode used for this endpoint gateway:- `disabled`: The endpoint gateway is not participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing).- `primary`: The endpoint gateway is participating in [DNS sharing for VPE gateways] (/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC.- `per_resource_binding`: The endpoint gateway is participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC, and resource binding is enabled for the `target` service. + - Constraints: Allowable values are: `disabled`, `per_resource_binding`, `primary`. - `health_state` - (String) The endpoint gateway health state. **ok: Healthy**, **degraded: Suffering from compromised performance, capacity, or connectivity**, **faulted: Completely unreachable, inoperative, or entirely incapacitated**, **inapplicable: The health state does not apply because of the current lifecycle state**. A resource with a lifecycle state of failed or deleting will have a health state of inapplicable. A pending resource may have this state. - `lifecycle_state` - (String) The endpoint gateway lifecycle state, supported values are `deleted`, `deleting`, `failed`, `pending`, `stable`, `updating`, `waiting`, `suspended`. - `id` - (String) The endpoint gateway ID. diff --git a/website/docs/r/is_virtual_endpoint_gateway.html.markdown b/website/docs/r/is_virtual_endpoint_gateway.html.markdown index d766cfcb80..160f92b44c 100644 --- a/website/docs/r/is_virtual_endpoint_gateway.html.markdown +++ b/website/docs/r/is_virtual_endpoint_gateway.html.markdown @@ -127,7 +127,23 @@ Review the argument references that you can specify for your resource. **•** You must have the access listed in the [Granting users access to tag resources](https://cloud.ibm.com/docs/account?topic=account-access) for `access_tags`
**•** `access_tags` must be in the format `key:value`. -- `allow_dns_resolution_binding` - (Optional, bool) Indicates whether to allow this endpoint gateway to participate in DNS resolution bindings with a VPC that has dns.enable\_hub set to true. +- `allow_dns_resolution_binding` - (**Deprecated**, Optional, bool) **This field has been deprecated in favor of `dns_resolution_binding_mode` and will be removed in a future version.** + + Previously indicated whether to allow this endpoint gateway to participate in DNS resolution bindings with a VPC that has dns.enable_hub set to true. + + **Migration Guide:** + - `false` → use `dns_resolution_binding_mode = "disabled"` + - `true` → use `dns_resolution_binding_mode = "primary"` + + **Note:** The new `dns_resolution_binding_mode` field also supports `"per_resource_binding"` for advanced DNS sharing scenarios not available with this boolean field. + + ~> **Important:** Do not use both `allow_dns_resolution_binding` and `dns_resolution_binding_mode` in the same configuration. Use only `dns_resolution_binding_mode`. + +- `dns_resolution_binding_mode` - (Optional, String) The DNS resolution binding mode used for this endpoint gateway: + - `disabled`: The endpoint gateway is not participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing). + - `primary`: The endpoint gateway is participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC. + - `per_resource_binding`: The endpoint gateway is participating in [DNS sharing for VPE gateways](/docs/vpc?topic=vpc-vpe-dns-sharing) if the VPC this endpoint gateway resides in has a DNS resolution binding to another VPC, and resource binding is enabled for the `target` service. + - Constraints: Allowable values are: `disabled`, `per_resource_binding`, `primary`. - `name` - (Required, Forces new resource, String) The endpoint gateway name. diff --git a/website/docs/r/is_virtual_endpoint_gateway_resource_binding.html.markdown b/website/docs/r/is_virtual_endpoint_gateway_resource_binding.html.markdown new file mode 100644 index 0000000000..1d9f458750 --- /dev/null +++ b/website/docs/r/is_virtual_endpoint_gateway_resource_binding.html.markdown @@ -0,0 +1,80 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_virtual_endpoint_gateway_resource_binding" +description: |- + Manages EndpointGatewayResourceBinding. +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_virtual_endpoint_gateway_resource_binding + +Create, update, and delete EndpointGatewayResourceBindings with this resource. + +## Example Usage + +```hcl +resource "ibm_is_virtual_endpoint_gateway_resource_binding" "is_virtual_endpoint_gateway_resource_binding_instance" { + endpoint_gateway_id = "endpoint_gateway_id" + name = "my-resource-binding" + target { + crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/aa2432b1fa4d4ace891e9b80fc104e34:1a0ec336-f391-4091-a6fb-5e084a4c56f4:bucket:bucket-27200-lwx4cfvcue" + } +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +* `endpoint_gateway_id` - (Required, Forces new resource, String) The endpoint gateway identifier. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. +* `name` - (Optional, String) The name for this resource binding. The name is unique across all resource bindings for the endpoint gateway. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. +* `target` - (Required, List) The target for this endpoint gateway resource binding. +Nested schema for **target**: + * `crn` - (Optional, String) + * Constraints: The maximum length is `512` characters. The minimum length is `17` characters. The value must match regular expression `/^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\\.\/]*$/`. + +## Attribute Reference + +After your resource is created, you can read values from the listed arguments and the following attributes. + +* `id` - The unique identifier of the EndpointGatewayResourceBinding. +* `created_at` - (String) The date and time that the resource binding was created. +* `href` - (String) The URL for this endpoint gateway resource binding. + * Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `endpoint_gateway_resource_binding_id` - (String) The unique identifier for this endpoint gateway resource binding. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. +* `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + * Constraints: The minimum length is `0` items. +Nested schema for **lifecycle_reasons**: + * `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + * Constraints: Allowable values are: `internal_error`, `resource_suspended_by_provider`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. + * `message` - (String) An explanation of the reason for this lifecycle state. + * `more_info` - (String) A link to documentation about the reason for this lifecycle state. + * Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `lifecycle_state` - (String) The lifecycle state of the resource binding. + * Constraints: Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. +* `resource_type` - (String) The resource type. + * Constraints: Allowable values are: `endpoint_gateway_resource_binding`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. +* `service_endpoint` - (String) The fully qualified domain name of the service endpoint for the resource targeted by this resource binding. + * Constraints: The maximum length is `255` characters. The minimum length is `4` characters. The value must match regular expression `/^((?=[A-Za-z0-9-]{1,63}\\.)[A-Za-z0-9-]*\\.)+[A-Za-z]{2,63}\\.?$/`. +* `type` - (String) The type of resource binding:- `weak`: The binding is not dependent on the existence of the target resource.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + * Constraints: Allowable values are: `weak`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. + + +## Import + +You can import the `ibm_is_virtual_endpoint_gateway_resource_binding` resource by using `id`. +The `id` property can be formed from `endpoint_gateway_id`, and `endpoint_gateway_resource_binding_id` in the following format: + +
+<endpoint_gateway_id>/<endpoint_gateway_resource_binding_id>
+
+* `endpoint_gateway_id`: A string. The endpoint gateway identifier. +* `endpoint_gateway_resource_binding_id`: A string in the format `r006-a7ba95b6-a254-47e4-b129-10593df8a373`. The unique identifier for this endpoint gateway resource binding. + +# Syntax +
+$ terraform import ibm_is_virtual_endpoint_gateway_resource_binding.is_virtual_endpoint_gateway_resource_binding <endpoint_gateway_id>/<endpoint_gateway_resource_binding_id>
+