diff --git a/go.mod b/go.mod index f0d0da5c6a..8101321fed 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.74.1 + github.com/IBM/vpc-go-sdk v0.75.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 c8c9b45ceb..8c57cc190b 100644 --- a/go.sum +++ b/go.sum @@ -170,6 +170,8 @@ github.com/IBM/vpc-beta-go-sdk v0.8.0 h1:cEPpv4iw3Ba5W2d0AWg3TIbKeJ8y1nPuUuibR5J 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/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/provider/provider.go b/ibm/provider/provider.go index 90f4ed4fe5..5bef0514a5 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -650,6 +650,9 @@ func Provider() *schema.Provider { "ibm_is_vpn_gateway_connection_local_cidrs": vpc.DataSourceIBMIsVPNGatewayConnectionLocalCidrs(), "ibm_is_vpn_gateway_connection_peer_cidrs": vpc.DataSourceIBMIsVPNGatewayConnectionPeerCidrs(), + "ibm_is_vpn_gateway_advertised_cidrs": vpc.DataSourceIBMIsVPNGatewayAdvertisedCidrs(), + "ibm_is_vpn_gateway_service_connection": vpc.DataSourceIBMIsVPNGatewayServiceConnection(), + "ibm_is_vpn_gateway_service_connections": vpc.DataSourceIBMIsVPNGatewayServiceConnections(), "ibm_is_vpc_default_routing_table": vpc.DataSourceIBMISVPCDefaultRoutingTable(), "ibm_is_vpc_routing_table": vpc.DataSourceIBMIsVPCRoutingTable(), @@ -1408,6 +1411,7 @@ func Provider() *schema.Provider { "ibm_is_volume": vpc.ResourceIBMISVolume(), "ibm_is_vpn_gateway": vpc.ResourceIBMISVPNGateway(), "ibm_is_vpn_gateway_connection": vpc.ResourceIBMISVPNGatewayConnection(), + "ibm_is_vpn_gateway_advertised_cidr": vpc.ResourceIBMISVPNGatewayAdvertisedCidr(), "ibm_is_vpc": vpc.ResourceIBMISVPC(), "ibm_is_vpc_address_prefix": vpc.ResourceIBMISVpcAddressPrefix(), "ibm_is_vpc_dns_resolution_binding": vpc.ResourceIBMIsVPCDnsResolutionBinding(), diff --git a/ibm/service/vpc/data_source_ibm_is_lb.go b/ibm/service/vpc/data_source_ibm_is_lb.go index 6e89a8136e..03990be236 100644 --- a/ibm/service/vpc/data_source_ibm_is_lb.go +++ b/ibm/service/vpc/data_source_ibm_is_lb.go @@ -620,7 +620,6 @@ func lbGetByName(context context.Context, d *schema.ResourceData, meta interface healthMonitorInfo[healthMonitorType] = *(poolHealthMonitor.Type) pool[healthMonitor] = healthMonitorInfo } - if p.SessionPersistence != nil { sessionPersistenceInfo := make(map[string]interface{}) sessionPersistenceInfo[sessionType] = *p.SessionPersistence.Type diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go index 4eae836d9b..39abb4b12b 100644 --- a/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go @@ -267,6 +267,20 @@ func DataSourceIBMISVPNGateway() *schema.Resource { Computed: true, Description: "Route mode VPN gateway.", }, + isVPNGatewayLocalAsn: { + Type: schema.TypeInt, + Computed: true, + Description: "The local autonomous system number (ASN) for this VPN gateway and its connections.", + }, + + isVPNGatewayAdvertisedCidrs: { + Type: schema.TypeList, + Computed: true, + Description: "The additional CIDRs advertised through any enabled routing protocol (for example, BGP). The routing protocol will advertise routes with these CIDRs and VPC prefixes as route destinations.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, "vpc": { Type: schema.TypeList, Computed: true, @@ -445,6 +459,16 @@ func dataSourceIBMIsVPNGatewayRead(context context.Context, d *schema.ResourceDa if err = d.Set("mode", vpnGateway.Mode); err != nil { return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting mode: %s", err), "(Data) ibm_is_vpn_gateway", "read", "set-mode").GetDiag() } + if vpnGateway.AdvertisedCIDRs != nil { + if err = d.Set("advertised_cidrs", vpnGateway.AdvertisedCIDRs); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting advertised_cidrs: %s", err), "(Data) ibm_is_vpn_gateway", "read", "set-advertised_cidrs").GetDiag() + } + } + if vpnGateway.LocalAsn != nil { + if err = d.Set("local_asn", vpnGateway.LocalAsn); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting local_asn: %s", err), "(Data) ibm_is_vpn_gateway", "read", "set-local_asn").GetDiag() + } + } if vpnGateway.VPC != nil { err = d.Set("vpc", dataSourceVPNGatewayFlattenVPC(vpnGateway.VPC)) if err != nil { diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_advertised_cidrs.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_advertised_cidrs.go new file mode 100644 index 0000000000..b4fe987c7a --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_advertised_cidrs.go @@ -0,0 +1,112 @@ +// Copyright IBM Corp. 2024 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 DataSourceIBMIsVPNGatewayAdvertisedCidrs() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNGatewayAdvertisedCidrsRead, + + Schema: map[string]*schema.Schema{ + "vpn_gateway": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpn_gateway_name", "vpn_gateway"}, + Description: "The VPN gateway identifier.", + }, + "vpn_gateway_name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpn_gateway_name", "vpn_gateway"}, + Description: "The VPN gateway name.", + }, + "advertised_cidrs": { + Type: schema.TypeList, + Computed: true, + Description: "The additional CIDRs advertised through any enabled routing protocol (for example, BGP). The routing protocol will advertise routes with these CIDRs and VPC prefixes as route destinations.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMIsVPNGatewayAdvertisedCidrsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("vpcClient creation failed: %s", err.Error()), "(Data) ibm_is_vpn_gateway_advertised_cidrs", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + vpn_gateway_id := d.Get("vpn_gateway").(string) + vpn_gateway_name := d.Get("vpn_gateway_name").(string) + + if vpn_gateway_name != "" { + listvpnGWOptions := vpcClient.NewListVPNGatewaysOptions() + + start := "" + allrecs := []vpcv1.VPNGatewayIntf{} + for { + if start != "" { + listvpnGWOptions.Start = &start + } + availableVPNGateways, detail, err := vpcClient.ListVPNGatewaysWithContext(context, listvpnGWOptions) + if err != nil || availableVPNGateways == nil { + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error reading list of VPN Gateways:%s\n%s", err, detail), "(Data) ibm_is_vpn_gateway_advertised_cidrs", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + } + start = flex.GetNext(availableVPNGateways.Next) + allrecs = append(allrecs, availableVPNGateways.VPNGateways...) + if start == "" { + break + } + } + vpn_gateway_found := false + for _, vpnGatewayIntfItem := range allrecs { + if *vpnGatewayIntfItem.(*vpcv1.VPNGateway).Name == vpn_gateway_name { + vpnGateway := vpnGatewayIntfItem.(*vpcv1.VPNGateway) + vpn_gateway_id = *vpnGateway.ID + vpn_gateway_found = true + break + } + } + if !vpn_gateway_found { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("No vpn gateway found with given name %s", vpn_gateway_name), "(Data) ibm_is_vpn_gateway_advertised_cidrs", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + } + + listVPNGatewayAdvertisedCIDRsOptions := &vpcv1.ListVPNGatewayAdvertisedCIDRsOptions{} + + listVPNGatewayAdvertisedCIDRsOptions.SetVPNGatewayID(vpn_gateway_id) + + vpnGatewayAdvertisedCidRs, response, err := vpcClient.ListVPNGatewayAdvertisedCIDRsWithContext(context, listVPNGatewayAdvertisedCIDRsOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("ListVPNGatewayAdvertisedCIDRsWithContext failed %s\n%s", err, response), "(Data) ibm_is_vpn_gateway_advertised_cidrs", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + d.SetId(time.Now().UTC().String()) + d.Set("advertised_cidrs", vpnGatewayAdvertisedCidRs.AdvertisedCIDRs) + + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_advertised_cidrs_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_advertised_cidrs_test.go new file mode 100644 index 0000000000..27c51ca43c --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_advertised_cidrs_test.go @@ -0,0 +1,121 @@ +// Copyright IBM Corp. 2024 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 TestAccIBMIsVPNGatewayAdvertisedCidrsDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(100, 200)) + subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(100, 200)) + vpngwname := fmt.Sprintf("tfvpnuat-vpngw-%d", acctest.RandIntRange(100, 200)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsVPNGatewayAdvertisedCidrsDataSourceConfigBasic(vpcname, subnetname, vpngwname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_advertised_cidrs.is_vpn_gateway_advertised_cidrs", "advertised_cidrs.#"), + ), + }, + }, + }) +} + +func TestAccIBMIsVPNGatewayAdvertisedCidrsVPNGatewayNameDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(100, 200)) + subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(100, 200)) + vpngwname := fmt.Sprintf("tfvpnuat-vpngw-%d", acctest.RandIntRange(100, 200)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsVPNGatewayAdvertisedCidrsWithVPNGatewayNameDataSourceConfigBasic(vpcname, subnetname, vpngwname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_advertised_cidrs.is_vpn_gateway_advertised_cidrs", "advertised_cidrs.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVPNGatewayAdvertisedCidrsDataSourceConfigBasic(vpc, subnet, vpngwname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "example" { + name = "%s" + } + resource "ibm_is_subnet" "example" { + name = "%s" + vpc = ibm_is_vpc.example.id + zone = "%s" + ipv4_cidr_block = "%s" + + } + + resource "ibm_is_vpn_gateway" "example" { + name = "%s" + subnet = ibm_is_subnet.example.id + mode = "route" + local_asn = 64520 + lifecycle { + ignore_changes = [ + advertised_cidrs + ] + } + } + + resource "ibm_is_vpn_gateway_advertised_cidr" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id + cidr = "10.45.0.0/25" + } + data "ibm_is_vpn_gateway_advertised_cidrs" "is_vpn_gateway_advertised_cidrs" { + depends_on = [resource.ibm_is_vpn_gateway_advertised_cidr.example] + vpn_gateway = ibm_is_vpn_gateway.example.id + } + `, vpc, subnet, acc.ISZoneName, acc.ISCIDR, vpngwname) +} + +func testAccCheckIBMIsVPNGatewayAdvertisedCidrsWithVPNGatewayNameDataSourceConfigBasic(vpc, subnet, vpngwname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "example" { + name = "%s" + } + resource "ibm_is_subnet" "example" { + name = "%s" + vpc = ibm_is_vpc.example.id + zone = "%s" + ipv4_cidr_block = "%s" + + } + resource "ibm_is_vpn_gateway" "example" { + name = "%s" + subnet = ibm_is_subnet.example.id + mode = "route" + lifecycle { + ignore_changes = [ + advertised_cidrs + ] + } + } + resource "ibm_is_vpn_gateway_advertised_cidr" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id + cidr = "10.45.0.0/25" + } + data "ibm_is_vpn_gateway_advertised_cidrs" "is_vpn_gateway_advertised_cidrs" { + depends_on = [resource.ibm_is_vpn_gateway_advertised_cidr.example] + vpn_gateway_name = ibm_is_vpn_gateway.example.name + } + `, vpc, subnet, acc.ISZoneName, acc.ISCIDR, vpngwname) +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connection.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connection.go index 10cbb3f155..6fe27ab6df 100644 --- a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connection.go +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connection.go @@ -281,6 +281,12 @@ func DataSourceIBMISVPNGatewayConnection() *schema.Resource { Type: schema.TypeString, }, }, + "asn": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The peer autonomous system number (ASN) for this VPN gateway connection.", + }, }, }, }, @@ -340,6 +346,16 @@ func DataSourceIBMISVPNGatewayConnection() *schema.Resource { Description: "The VPN tunnel configuration for this VPN gateway connection (in static route mode).", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "neighbor_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The IP address of the neighbor on the virtual tunnel interface.", + }, + "protocol_state": { + Type: schema.TypeString, + Computed: true, + Description: "BGP routing protocol state.", + }, "public_ip_address": { Type: schema.TypeString, Computed: true, @@ -350,6 +366,11 @@ func DataSourceIBMISVPNGatewayConnection() *schema.Resource { Computed: true, Description: "The status of the VPN Tunnel.", }, + "tunnel_interface_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The IP address of the virtual tunnel interface.", + }, }, }, }, @@ -468,6 +489,15 @@ func dataSourceIBMIsVPNGatewayConnectionRead(context context.Context, d *schema. break } } + case "*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode": + { + connection := connectionItem.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode) + if *connection.Name == vpn_gateway_connection_name { + vpnGatewayConnection = connectionItem + vpn_gateway_conn_found = true + break + } + } case "*vpcv1.VPNGatewayConnectionPolicyMode": { connection := connectionItem.(*vpcv1.VPNGatewayConnectionPolicyMode) @@ -820,6 +850,109 @@ func setvpnGatewayConnectionIntfDatasourceData(d *schema.ResourceData, vpn_gatew } } } + case "*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode": + { + vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode) + d.SetId(fmt.Sprintf("%s/%s", vpn_gateway_id, *vpnGatewayConnection.ID)) + if err = d.Set("admin_state_up", vpnGatewayConnection.AdminStateUp); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting admin_state_up: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-admin_state_up").GetDiag() + } + if err = d.Set("authentication_mode", vpnGatewayConnection.AuthenticationMode); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting authentication_mode: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-authentication_mode").GetDiag() + } + if err = d.Set("created_at", flex.DateTimeToString(vpnGatewayConnection.CreatedAt)); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting created_at: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-created_at").GetDiag() + } + + if vpnGatewayConnection.DeadPeerDetection != nil { + err = d.Set("dead_peer_detection", dataSourceVPNGatewayConnectionFlattenDeadPeerDetection(*vpnGatewayConnection.DeadPeerDetection)) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting dead_peer_detection: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-dead_peer_detection").GetDiag() + } + } + if err = d.Set("href", vpnGatewayConnection.Href); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting href: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-href").GetDiag() + } + + if vpnGatewayConnection.IkePolicy != nil { + err = d.Set("ike_policy", dataSourceVPNGatewayConnectionFlattenIkePolicy(*vpnGatewayConnection.IkePolicy)) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting ike_policy: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-ike_policy").GetDiag() + } + } + + if vpnGatewayConnection.IpsecPolicy != nil { + err = d.Set("ipsec_policy", dataSourceVPNGatewayConnectionFlattenIpsecPolicy(*vpnGatewayConnection.IpsecPolicy)) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting ipsec_policy: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-ipsec_policy").GetDiag() + } + } + if err = d.Set("mode", vpnGatewayConnection.Mode); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting mode: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-mode").GetDiag() + } + if err = d.Set("name", vpnGatewayConnection.Name); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting name: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-name").GetDiag() + } + + // breaking changes + if err = d.Set("establish_mode", vpnGatewayConnection.EstablishMode); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting establish_mode: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-establish_mode").GetDiag() + } + local := []map[string]interface{}{} + if vpnGatewayConnection.Local != nil { + modelMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModeLocalToMap(vpnGatewayConnection.Local) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_vpn_gateway_connection", "read", "local-to-map").GetDiag() + } + local = append(local, modelMap) + } + if err = d.Set("local", local); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting local: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-local").GetDiag() + } + + peer := []map[string]interface{}{} + if vpnGatewayConnection.Peer != nil { + modelMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModePeerToMap(vpnGatewayConnection.Peer) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_vpn_gateway_connection", "read", "peer-to-map").GetDiag() + } + peer = append(peer, modelMap) + } + if err = d.Set("peer", peer); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting peer: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-peer").GetDiag() + } + if vpnGatewayConnection.Peer != nil { + peer := vpnGatewayConnection.Peer.(*vpcv1.VPNGatewayConnectionDynamicRouteModePeer) + if err = d.Set("peer_address", peer.Address); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting peer_address: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-peer_address").GetDiag() + } + } + if err = d.Set("psk", vpnGatewayConnection.Psk); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting psk: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-psk").GetDiag() + } + if err = d.Set("resource_type", vpnGatewayConnection.ResourceType); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting resource_type: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-resource_type").GetDiag() + } + if err = d.Set("status", vpnGatewayConnection.Status); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting status: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-status").GetDiag() + } + if err = d.Set("distribute_traffic", vpnGatewayConnection.DistributeTraffic); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting distribute_traffic: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-distribute_traffic").GetDiag() + } + if err := d.Set("status_reasons", resourceVPNGatewayConnectionFlattenLifecycleReasons(vpnGatewayConnection.StatusReasons)); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting status_reasons: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-status_reasons").GetDiag() + } + if err = d.Set("routing_protocol", vpnGatewayConnection.RoutingProtocol); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting routing_protocol: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-routing_protocol").GetDiag() + } + + if vpnGatewayConnection.Tunnels != nil { + err = d.Set("tunnels", dataSourceVPNGatewayConnectionFlattenDynamicTunnels(vpnGatewayConnection.Tunnels)) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting tunnels: %s", err), "(Data) ibm_is_vpn_gateway_connection", "read", "set-tunnels").GetDiag() + } + } + } case "*vpcv1.VPNGatewayConnectionPolicyMode": { vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionPolicyMode) @@ -1088,6 +1221,21 @@ func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionStaticRouteModeLocal modelMap["ike_identities"] = ikeIdentities return modelMap, nil } + +func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModeLocalToMap(model *vpcv1.VPNGatewayConnectionDynamicRouteModeLocal) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + ikeIdentities := []map[string]interface{}{} + for _, ikeIdentitiesItem := range model.IkeIdentities { + ikeIdentitiesItemMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionIkeIdentityToMap(ikeIdentitiesItem) + if err != nil { + return modelMap, err + } + ikeIdentities = append(ikeIdentities, ikeIdentitiesItemMap) + } + modelMap["ike_identities"] = ikeIdentities + return modelMap, nil +} + func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionPolicyModeLocalToMap(model *vpcv1.VPNGatewayConnectionPolicyModeLocal) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) ikeIdentities := []map[string]interface{}{} @@ -1177,6 +1325,34 @@ func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionStaticRouteModePeerT return nil, fmt.Errorf("Unrecognized vpcv1.VPNGatewayConnectionStaticRouteModePeerIntf subtype encountered") } } + +func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModePeerToMap(model vpcv1.VPNGatewayConnectionDynamicRouteModePeerIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.VPNGatewayConnectionDynamicRouteModePeerVPNGatewayConnectionPeerByAddress); ok { + return dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModePeerVPNGatewayConnectionPeerByAddressToMap(model.(*vpcv1.VPNGatewayConnectionDynamicRouteModePeerVPNGatewayConnectionPeerByAddress)) + } else if _, ok := model.(*vpcv1.VPNGatewayConnectionDynamicRouteModePeerVPNGatewayConnectionPeerByFqdn); ok { + return dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModePeerVPNGatewayConnectionPeerByFqdnToMap(model.(*vpcv1.VPNGatewayConnectionDynamicRouteModePeerVPNGatewayConnectionPeerByFqdn)) + } else if _, ok := model.(*vpcv1.VPNGatewayConnectionDynamicRouteModePeer); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.VPNGatewayConnectionDynamicRouteModePeer) + ikeIdentityMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionIkeIdentityToMap(model.IkeIdentity) + if err != nil { + return modelMap, err + } + modelMap["ike_identity"] = []map[string]interface{}{ikeIdentityMap} + modelMap["asn"] = model.Asn + modelMap["type"] = model.Type + if model.Address != nil { + modelMap["address"] = model.Address + } + if model.Fqdn != nil { + modelMap["fqdn"] = model.Fqdn + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.VPNGatewayConnectionDynamicRouteModePeerIntf subtype encountered") + } +} + func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionPolicyModePeerToMap(model vpcv1.VPNGatewayConnectionPolicyModePeerIntf) (map[string]interface{}, error) { if _, ok := model.(*vpcv1.VPNGatewayConnectionPolicyModePeerVPNGatewayConnectionPeerByAddress); ok { return dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionPolicyModePeerVPNGatewayConnectionPeerByAddressToMap(model.(*vpcv1.VPNGatewayConnectionPolicyModePeerVPNGatewayConnectionPeerByAddress)) @@ -1217,6 +1393,20 @@ func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionStaticRouteModePeerV modelMap["address"] = model.Address return modelMap, nil } + +func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModePeerVPNGatewayConnectionPeerByAddressToMap(model *vpcv1.VPNGatewayConnectionDynamicRouteModePeerVPNGatewayConnectionPeerByAddress) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + ikeIdentityMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionIkeIdentityToMap(model.IkeIdentity) + if err != nil { + return modelMap, err + } + modelMap["ike_identity"] = []map[string]interface{}{ikeIdentityMap} + modelMap["asn"] = model.Asn + modelMap["type"] = model.Type + modelMap["address"] = model.Address + return modelMap, nil +} + func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionPolicyModePeerVPNGatewayConnectionPeerByAddressToMap(model *vpcv1.VPNGatewayConnectionPolicyModePeerVPNGatewayConnectionPeerByAddress) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) ikeIdentityMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionIkeIdentityToMap(model.IkeIdentity) @@ -1242,6 +1432,20 @@ func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionStaticRouteModePeerV modelMap["fqdn"] = model.Fqdn return modelMap, nil } + +func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModePeerVPNGatewayConnectionPeerByFqdnToMap(model *vpcv1.VPNGatewayConnectionDynamicRouteModePeerVPNGatewayConnectionPeerByFqdn) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + ikeIdentityMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionIkeIdentityToMap(model.IkeIdentity) + if err != nil { + return modelMap, err + } + modelMap["ike_identity"] = []map[string]interface{}{ikeIdentityMap} + modelMap["asn"] = model.Asn + modelMap["type"] = model.Type + modelMap["fqdn"] = model.Fqdn + return modelMap, nil +} + func dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionPolicyModePeerVPNGatewayConnectionPeerByFqdnToMap(model *vpcv1.VPNGatewayConnectionPolicyModePeerVPNGatewayConnectionPeerByFqdn) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) ikeIdentityMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionIkeIdentityToMap(model.IkeIdentity) @@ -1266,3 +1470,33 @@ func PrettifyPrint(result interface{}) string { } return string(output) } + +func dataSourceVPNGatewayConnectionFlattenDynamicTunnels(result []vpcv1.VPNGatewayConnectionDynamicRouteModeTunnel) (tunnels []map[string]interface{}) { + for _, tunnelsItem := range result { + tunnels = append(tunnels, dataSourceVPNGatewayConnectionDynamicTunnelsToMap(tunnelsItem)) + } + + return tunnels +} + +func dataSourceVPNGatewayConnectionDynamicTunnelsToMap(tunnelsItem vpcv1.VPNGatewayConnectionDynamicRouteModeTunnel) (tunnelsMap map[string]interface{}) { + tunnelsMap = map[string]interface{}{} + + if tunnelsItem.NeighborIP != nil { + tunnelsMap["neighbor_ip"] = tunnelsItem.NeighborIP.Address + } + if tunnelsItem.ProtocolState != nil { + tunnelsMap["protocol_state"] = tunnelsItem.ProtocolState + } + if tunnelsItem.PublicIP != nil { + tunnelsMap["public_ip_address"] = tunnelsItem.PublicIP.Address + } + if tunnelsItem.Status != nil { + tunnelsMap["status"] = tunnelsItem.Status + } + if tunnelsItem.TunnelInterfaceIP != nil { + tunnelsMap["tunnel_interface_ip"] = tunnelsItem.TunnelInterfaceIP.Address + } + + return tunnelsMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connections.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connections.go index 8602710ccc..a8373be5c7 100644 --- a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connections.go +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connections.go @@ -203,6 +203,12 @@ func DataSourceIBMISVPNGatewayConnections() *schema.Resource { Computed: true, Description: "The FQDN of the peer VPN gateway for this connection.", }, + "asn": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The peer autonomous system number (ASN) for this VPN gateway connection.", + }, }, }, }, @@ -269,6 +275,21 @@ func DataSourceIBMISVPNGatewayConnections() *schema.Resource { Computed: true, Description: "The status of the VPN Tunnel", }, + "neighbor_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The IP address of the neighbor on the virtual tunnel interface.", + }, + "tunnel_interface_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The IP address of the virtual tunnel interface.", + }, + "protocol_state": { + Type: schema.TypeString, + Computed: true, + Description: "BGP routing protocol state.", + }, }, }, }, @@ -520,6 +541,65 @@ func getvpnGatewayConnectionIntfData(vpnGatewayConnectionIntf vpcv1.VPNGatewayCo gatewayconnection["tunnels"] = dataSourceVPNGatewayConnectionsFlattenTunnels(vpnGatewayConnection.Tunnels) } } + case "*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode": + { + vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode) + gatewayconnection["id"] = vpnGatewayConnection.ID + gatewayconnection["admin_state_up"] = vpnGatewayConnection.AdminStateUp + gatewayconnection["authentication_mode"] = vpnGatewayConnection.AuthenticationMode + gatewayconnection["created_at"] = flex.DateTimeToString(vpnGatewayConnection.CreatedAt) + + if vpnGatewayConnection.DeadPeerDetection != nil { + gatewayconnection[isVPNGatewayConnectionDeadPeerDetectionAction] = vpnGatewayConnection.DeadPeerDetection.Action + gatewayconnection[isVPNGatewayConnectionDeadPeerDetectionInterval] = vpnGatewayConnection.DeadPeerDetection.Interval + gatewayconnection[isVPNGatewayConnectionDeadPeerDetectionTimeout] = vpnGatewayConnection.DeadPeerDetection.Timeout + } + gatewayconnection["distribute_traffic"] = vpnGatewayConnection.DistributeTraffic + gatewayconnection["href"] = vpnGatewayConnection.Href + if vpnGatewayConnection.IkePolicy != nil { + gatewayconnection["ike_policy"] = vpnGatewayConnection.IkePolicy.ID + } + + if vpnGatewayConnection.IpsecPolicy != nil { + gatewayconnection["ipsec_policy"] = vpnGatewayConnection.IpsecPolicy.ID + } + gatewayconnection["mode"] = vpnGatewayConnection.Mode + gatewayconnection["name"] = vpnGatewayConnection.Name + + gatewayconnection["establish_mode"] = vpnGatewayConnection.EstablishMode + local := []map[string]interface{}{} + if vpnGatewayConnection.Local != nil { + modelMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModeLocalToMap(vpnGatewayConnection.Local) + if err != nil { + return gatewayconnection, err + } + local = append(local, modelMap) + } + gatewayconnection["local"] = local + + peer := []map[string]interface{}{} + if vpnGatewayConnection.Peer != nil { + modelMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModePeerToMap(vpnGatewayConnection.Peer) + if err != nil { + return gatewayconnection, err + } + peer = append(peer, modelMap) + } + gatewayconnection["peer"] = peer + if vpnGatewayConnection.Peer != nil { + peer := vpnGatewayConnection.Peer.(*vpcv1.VPNGatewayConnectionDynamicRouteModePeer) + gatewayconnection["peer_address"] = peer.Address + } + gatewayconnection["psk"] = vpnGatewayConnection.Psk + gatewayconnection["resource_type"] = vpnGatewayConnection.ResourceType + gatewayconnection["status"] = vpnGatewayConnection.Status + gatewayconnection["status_reasons"] = resourceVPNGatewayConnectionFlattenLifecycleReasons(vpnGatewayConnection.StatusReasons) + gatewayconnection["routing_protocol"] = vpnGatewayConnection.RoutingProtocol + + if vpnGatewayConnection.Tunnels != nil { + gatewayconnection["tunnels"] = dataSourceVPNGatewayConnectionsFlattenDynamicTunnels(vpnGatewayConnection.Tunnels) + } + } case "*vpcv1.VPNGatewayConnectionPolicyMode": { vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionPolicyMode) @@ -728,3 +808,33 @@ func dataSourceVPNGatewayConnectionsTunnelsToMap(tunnelsItem vpcv1.VPNGatewayCon return tunnelsMap } + +func dataSourceVPNGatewayConnectionsFlattenDynamicTunnels(result []vpcv1.VPNGatewayConnectionDynamicRouteModeTunnel) (tunnels []map[string]interface{}) { + for _, tunnelsItem := range result { + tunnels = append(tunnels, dataSourceVPNGatewayConnectionsDynamicTunnelsToMap(tunnelsItem)) + } + + return tunnels +} + +func dataSourceVPNGatewayConnectionsDynamicTunnelsToMap(tunnelsItem vpcv1.VPNGatewayConnectionDynamicRouteModeTunnel) (tunnelsMap map[string]interface{}) { + tunnelsMap = map[string]interface{}{} + + if tunnelsItem.NeighborIP != nil { + tunnelsMap["neighbor_ip"] = tunnelsItem.NeighborIP.Address + } + if tunnelsItem.ProtocolState != nil { + tunnelsMap["protocol_state"] = tunnelsItem.ProtocolState + } + if tunnelsItem.PublicIP != nil { + tunnelsMap["address"] = tunnelsItem.PublicIP.Address + } + if tunnelsItem.Status != nil { + tunnelsMap["status"] = tunnelsItem.Status + } + if tunnelsItem.TunnelInterfaceIP != nil { + tunnelsMap["tunnel_interface_ip"] = tunnelsItem.TunnelInterfaceIP.Address + } + + return tunnelsMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connection.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connection.go new file mode 100644 index 0000000000..292ff06f13 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connection.go @@ -0,0 +1,232 @@ +// Copyright IBM Corp. 2024 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 DataSourceIBMIsVPNGatewayServiceConnection() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNGatewayServiceConnectionRead, + + Schema: map[string]*schema.Schema{ + "vpn_gateway": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpn_gateway_name", "vpn_gateway"}, + Description: "The VPN gateway identifier.", + }, + "vpn_gateway_name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpn_gateway_name", "vpn_gateway"}, + Description: "The VPN gateway name.", + }, + "vpn_gateway_service_connection": { + Type: schema.TypeString, + Required: true, + Description: "The VPN gateway connection identifier.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this VPN service connection was created.", + }, + "creator": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for transit gateway resource.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for transit gateway resource.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN gateway service connection", + }, + "lifecycle_reasons": { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + 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": { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the VPN service connection.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of this service connection:- `up`: operating normally- `degraded`: operating with compromised performance- `down`: not operational.", + }, + "status_reasons": { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current VPN service connection status (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason. The enumerated values for this property may https://cloud.ibm.com/apidocs/vpc#property-value-expansion in the future.", + }, + "message": { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this VPN service connection's status.", + }, + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVPNGatewayServiceConnectionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("vpcClient creation failed: %s", err.Error()), "(Data) ibm_is_vpn_gateway_service_connection", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + vpn_gateway_id := d.Get("vpn_gateway").(string) + vpn_gateway_name := d.Get("vpn_gateway_name").(string) + vpn_gateway_service_connection := d.Get("vpn_gateway_service_connection").(string) + + var vpnGatewayServiceConn vpcv1.VPNGatewayServiceConnection + + if vpn_gateway_name != "" { + listvpnGWOptions := vpcClient.NewListVPNGatewaysOptions() + + start := "" + allrecs := []vpcv1.VPNGatewayIntf{} + for { + if start != "" { + listvpnGWOptions.Start = &start + } + availableVPNGateways, detail, err := vpcClient.ListVPNGatewaysWithContext(context, listvpnGWOptions) + if err != nil || availableVPNGateways == nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error reading list of VPN Gateways:%s\n%s", err, detail), "(Data) ibm_is_vpn_gateway_service_connection", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + start = flex.GetNext(availableVPNGateways.Next) + allrecs = append(allrecs, availableVPNGateways.VPNGateways...) + if start == "" { + break + } + } + vpn_gateway_found := false + for _, vpnGatewayIntfItem := range allrecs { + if *vpnGatewayIntfItem.(*vpcv1.VPNGateway).Name == vpn_gateway_name { + vpnGateway := vpnGatewayIntfItem.(*vpcv1.VPNGateway) + vpn_gateway_id = *vpnGateway.ID + vpn_gateway_found = true + break + } + } + if !vpn_gateway_found { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("No vpn gateway found with given name %s", vpn_gateway_name), "(Data) ibm_is_vpn_gateway_service_connection", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + } + + getVPNGatewayServiceConnectionOptions := &vpcv1.GetVPNGatewayServiceConnectionOptions{} + + getVPNGatewayServiceConnectionOptions.SetVPNGatewayID(vpn_gateway_id) + getVPNGatewayServiceConnectionOptions.SetID(vpn_gateway_service_connection) + + vpnGatewayServiceConnection, response, err := vpcClient.GetVPNGatewayServiceConnectionWithContext(context, getVPNGatewayServiceConnectionOptions) + if err != nil || vpnGatewayServiceConnection == nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVPNGatewayServiceConnectionWithContext failed %s\n%s", err, response), "(Data) ibm_is_vpn_gateway_service_connection", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + vpnGatewayServiceConn = *vpnGatewayServiceConnection + + d.SetId(*vpnGatewayServiceConn.ID) + + if err = d.Set("created_at", flex.DateTimeToString(vpnGatewayServiceConn.CreatedAt)); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting created_at: %s", err), "(Data) ibm_is_vpn_gateway_service_connection", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + if err := d.Set("creator", resourceVPNGatewayServiceConnectionFlattenCreator(vpnGatewayServiceConn.Creator)); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting creator: %s", err), "(Data) ibm_is_vpn_gateway_service_connection", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + if err := d.Set("lifecycle_reasons", resourceVPNGatewayServiceConnectionFlattenLifecycleReasons(vpnGatewayServiceConn.LifecycleReasons)); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_reasons: %s", err), "(Data) ibm_is_vpn_gateway_service_connection", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + if err = d.Set("lifecycle_state", vpnGatewayServiceConn.LifecycleState); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_state: %s", err), "(Data) ibm_is_vpn_gateway_service_connection", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + if err = d.Set("status", vpnGatewayServiceConn.Status); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf(" Error setting status: %s", err), "(Data) ibm_is_vpn_gateway_service_connection", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + if err := d.Set("status_reasons", resourceVPNGatewayServiceConnectionFlattenStateReasons(vpnGatewayServiceConn.StatusReasons)); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting status_reasons: %s", err), "(Data) ibm_is_vpn_gateway_service_connection", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connection_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connection_test.go new file mode 100644 index 0000000000..6fb1120ff0 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connection_test.go @@ -0,0 +1,83 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsVPNGatewayServiceConnectionDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(100, 200)) + subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(100, 200)) + vpngwname := fmt.Sprintf("tfvpnuat-vpngw-%d", acctest.RandIntRange(100, 200)) + name := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(100, 200)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsVPNGatewayServiceConnectionDataSourceConfigBasic(vpcname, subnetname, vpngwname, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_service_connection.example", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_service_connection.example", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_service_connection.example", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_service_connection.example", "status"), + ), + }, + { + Config: testAccCheckIBMIsVPNGatewayServiceConnectionDataSourceConfigBasic(vpcname, subnetname, vpngwname, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_service_connection.example1", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_service_connection.example1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_service_connection.example1", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_service_connection.example1", "status"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVPNGatewayServiceConnectionDataSourceConfigBasic(vpc, subnet, vpngwname, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "example" { + name = "%s" + + } + resource "ibm_is_subnet" "example" { + name = "%s" + vpc = ibm_is_vpc.example.id + zone = "%s" + ipv4_cidr_block = "%s" + + } + resource "ibm_is_vpn_gateway" "example" { + name = "%s" + subnet = ibm_is_subnet.example.id + mode = "policy" + + } + resource "ibm_is_vpn_gateway_connection" "example" { + name = "%s" + vpn_gateway = ibm_is_vpn_gateway.example.id + peer_address = "1.2.3.4" + peer_cidrs = [ibm_is_subnet.example.ipv4_cidr_block] + local_cidrs = [ibm_is_subnet.example.ipv4_cidr_block] + preshared_key = "VPNDemoPassword" + } + data "ibm_is_vpn_gateway_service_connection" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id + vpn_gateway_service_connection = ibm_is_vpn_gateway_connection.example.gateway_connection + } + data "ibm_is_vpn_gateway_service_connection" "example1" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name + vpn_gateway_service_connection = ibm_is_vpn_gateway_connection.example.gateway_connection + } + `, vpc, subnet, acc.ISZoneName, acc.ISCIDR, vpngwname, name) +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connections.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connections.go new file mode 100644 index 0000000000..d88af825ab --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connections.go @@ -0,0 +1,255 @@ +// Copyright IBM Corp. 2024 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/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +const ( + isVPNGatewayServiceConnectionId = "id" + isVPNGatewayServiceConnectionCreatedAt = "created_at" + isVPNGatewayServiceConnectionResourceGroup = "resource_group" + isVPNGatewayServiceConnections = "service_connections" + isVPNGatewayServiceConnectionCreator = "creator" + isVPNGatewayServiceConnectionStatus = "status" + isVPNGatewayServiceConnectionStatusReasons = "status_reasons" + isVPNGatewayServiceConnectionLifecycleState = "lifecycle_state" + isVPNGatewayServiceConnectionLifecycleReasons = "lifecycle_reasons" +) + +func DataSourceIBMIsVPNGatewayServiceConnections() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNGatewayServiceConnectionsRead, + + Schema: map[string]*schema.Schema{ + "vpn_gateway": { + Type: schema.TypeString, + Required: true, + Description: "The VPN gateway identifier.", + }, + isVPNGatewayServiceConnections: { + Type: schema.TypeList, + Description: "Collection of VPN Gateway service connections", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this VPN service connection was created.", + }, + "creator": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for transit gateway resource.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for transit gateway resource.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN gateway service connection", + }, + "lifecycle_reasons": { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + 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": { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the VPN service connection.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of this service connection:- `up`: operating normally- `degraded`: operating with compromised performance- `down`: not operational.", + }, + "status_reasons": { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current VPN service connection status (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason. The enumerated values for this property may https://cloud.ibm.com/apidocs/vpc#property-value-expansion in the future.", + }, + "message": { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this VPN service connection's status.", + }, + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVPNGatewayServiceConnectionsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := vpcClient(meta) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("vpcClient creation failed: %s", err.Error()), "(Data) ibm_is_vpn_gateway_service_connections", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + + vpnGateway := "" + if vpnGatewayIntf, ok := d.GetOk("vpn_gateway"); ok { + vpnGateway = vpnGatewayIntf.(string) + } + + start := "" + allrecs := []vpcv1.VPNGatewayServiceConnection{} + for { + listvpnGWServiceConnectionsOptions := sess.NewListVPNGatewayServiceConnectionsOptions(vpnGateway) + listvpnGWServiceConnectionsOptions.VPNGatewayID = &vpnGateway + if start != "" { + listvpnGWServiceConnectionsOptions.Start = &start + } + availableVPNGatewayServiceConnections, detail, err := sess.ListVPNGatewayServiceConnections(listvpnGWServiceConnectionsOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error reading list of VPN Gateway service connections:%s\n%s", err, detail), "(Data) ibm_is_vpn_gateway_service_connections", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + start = flex.GetNext(availableVPNGatewayServiceConnections.Next) + allrecs = append(allrecs, availableVPNGatewayServiceConnections.ServiceConnections...) + if start == "" { + break + } + } + + vpngatewayServiceConnections := make([]map[string]interface{}, 0) + for _, serviceConnection := range allrecs { + connection := map[string]interface{}{} + connection[isVPNGatewayServiceConnectionCreatedAt] = serviceConnection.CreatedAt.String() + connection[isVPNGatewayServiceConnectionId] = *serviceConnection.ID + connection[isVPNGatewayServiceConnectionCreator] = resourceVPNGatewayServiceConnectionFlattenCreator(serviceConnection.Creator) + connection[isVPNGatewayServiceConnectionLifecycleReasons] = resourceVPNGatewayServiceConnectionFlattenLifecycleReasons(serviceConnection.LifecycleReasons) + connection[isVPNGatewayServiceConnectionLifecycleState] = *serviceConnection.LifecycleState + connection[isVPNGatewayServiceConnectionStatus] = *serviceConnection.Status + connection[isVPNGatewayServiceConnectionStatusReasons] = resourceVPNGatewayServiceConnectionFlattenStateReasons(serviceConnection.StatusReasons) + + vpngatewayServiceConnections = append(vpngatewayServiceConnections, connection) + } + + d.SetId(dataSourceIBMVPNGatewayServiceConnectionsID(d)) + if err = d.Set(isVPNGatewayServiceConnections, vpngatewayServiceConnections); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting service_connections %s", err), "(Data) ibm_is_vpn_gateway_service_connections", "read", "vpn_gateway-service-connections-set").GetDiag() + } + return nil +} + +// dataSourceIBMVPNGatewayServiceConnectionsID returns a reasonable ID list. +func dataSourceIBMVPNGatewayServiceConnectionsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func resourceVPNGatewayServiceConnectionFlattenLifecycleReasons(lifecycleReasons []vpcv1.VPNGatewayServiceConnectionLifecycleReason) (lifecycleReasonsList []map[string]interface{}) { + lifecycleReasonsList = make([]map[string]interface{}, 0) + for _, lr := range lifecycleReasons { + currentLR := map[string]interface{}{} + if lr.Code != nil && lr.Message != nil { + currentLR[isInstanceLifecycleReasonsCode] = *lr.Code + currentLR[isInstanceLifecycleReasonsMessage] = *lr.Message + if lr.MoreInfo != nil { + currentLR[isInstanceLifecycleReasonsMoreInfo] = *lr.MoreInfo + } + lifecycleReasonsList = append(lifecycleReasonsList, currentLR) + } + } + return lifecycleReasonsList +} + +func resourceVPNGatewayServiceConnectionFlattenStateReasons(healthReasons []vpcv1.VPNGatewayServiceConnectionStatusReason) (statusReasonsList []map[string]interface{}) { + statusReasonsList = make([]map[string]interface{}, 0) + for _, lr := range healthReasons { + currentLR := map[string]interface{}{} + if lr.Code != nil && lr.Message != nil { + currentLR[isInstanceLifecycleReasonsCode] = *lr.Code + currentLR[isInstanceLifecycleReasonsMessage] = *lr.Message + if lr.MoreInfo != nil { + currentLR[isInstanceLifecycleReasonsMoreInfo] = *lr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentLR) + } + } + return statusReasonsList +} + +func resourceVPNGatewayServiceConnectionFlattenCreator(model vpcv1.VPNGatewayServiceConnectionCreatorIntf) []map[string]interface{} { + modelMap := make(map[string]interface{}) + + connectionCreatorItem, ok := model.(*vpcv1.VPNGatewayServiceConnectionCreator) + if !ok || connectionCreatorItem == nil { + return nil + } + if connectionCreatorItem.CRN != nil { + modelMap["crn"] = *connectionCreatorItem.CRN + } + if connectionCreatorItem.ID != nil { + modelMap["id"] = *connectionCreatorItem.ID + } + if connectionCreatorItem.ResourceType != nil { + modelMap["resource_type"] = *connectionCreatorItem.ResourceType + } + return []map[string]interface{}{modelMap} +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connections_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connections_test.go new file mode 100644 index 0000000000..8278c8a39d --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_service_connections_test.go @@ -0,0 +1,66 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISVpnGatewayServoceConnectionsDataSource_basic(t *testing.T) { + conn := "data.ibm_is_vpn_gateway_service_connections.test1" + vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(100, 200)) + subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(100, 200)) + vpngwname := fmt.Sprintf("tfvpnuat-vpngw-%d", acctest.RandIntRange(100, 200)) + name := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(100, 200)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVpnGatewayServiceconnectionsDataSourceConfig(vpcname, subnetname, vpngwname, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(conn, "service_connections.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMISVpnGatewayServiceconnectionsDataSourceConfig(vpc, subnet, vpngwname, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet.id}" + resource_group = data.ibm_resource_group.rg.id + + } + resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.testacc_vpnGateway.id}" + peer_address = "1.2.3.4" + preshared_key = "VPNDemoPassword" + } + data "ibm_is_vpn_gateway_service_connections" "test1" { + vpn_gateway = ibm_is_vpn_gateway.testacc_vpnGateway.id + }`, vpc, subnet, acc.ISZoneName, acc.ISCIDR, vpngwname, name) + +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_test.go index fe4ae5b454..535749b726 100644 --- a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_test.go +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_test.go @@ -33,13 +33,13 @@ func TestAccIBMIsVPNGatewayDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "href"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "members.0.public_ip_address"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "members.0.role"), - resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "members.0.status"), + // resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "members.0.status"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "name"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "resource_group.0.id"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "resource_group.0.href"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "resource_group.0.name"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "resource_type"), - resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "status"), + // resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "status"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "subnet.0.href"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "subnet.0.id"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "subnet.0.name"), @@ -47,6 +47,8 @@ func TestAccIBMIsVPNGatewayDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "vpc.0.crn"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "vpc.0.href"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "vpc.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "local_asn"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "advertised_cidrs.#"), ), }, { @@ -60,7 +62,7 @@ func TestAccIBMIsVPNGatewayDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "name"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "resource_group.#"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "resource_type"), - resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "status"), + // resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "status"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "subnet.#"), ), }, @@ -82,7 +84,18 @@ func testAccCheckIBMIsVPNGatewayDataSourceConfigBasic(vpc, subnet, vpngwname, vp resource "ibm_is_vpn_gateway" "example" { name = "%s" subnet = "${ibm_is_subnet.example.id}" - } + mode = "route" + local_asn = 64520 + lifecycle { + ignore_changes = [ + advertised_cidrs + ] + } + } + resource "ibm_is_vpn_gateway_advertised_cidr" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id + cidr = "10.45.0.0/25" + } resource "ibm_is_vpn_gateway_connection" "example" { name = "%s" vpn_gateway = ibm_is_vpn_gateway.example.id diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go index 37f8372720..cf52190b10 100644 --- a/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go @@ -176,6 +176,19 @@ func DataSourceIBMISVPNGateways() *schema.Resource { Computed: true, Description: " VPN gateway mode(policy/route) ", }, + isVPNGatewayLocalAsn: { + Type: schema.TypeInt, + Computed: true, + Description: "The local autonomous system number (ASN) for this VPN gateway and its connections.", + }, + isVPNGatewayAdvertisedCidrs: { + Type: schema.TypeList, + Computed: true, + Description: "The additional CIDRs advertised through any enabled routing protocol (for example, BGP). The routing protocol will advertise routes with these CIDRs and VPC prefixes as route destinations.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, "vpc": { Type: schema.TypeList, Computed: true, @@ -289,6 +302,12 @@ func dataSourceIBMVPNGatewaysRead(context context.Context, d *schema.ResourceDat gateway[isVPNGatewayLifecycleState] = *data.LifecycleState gateway[isVPNGatewayLifecycleReasons] = resourceVPNGatewayFlattenLifecycleReasons(data.LifecycleReasons) gateway[isVPNGatewayMode] = *data.Mode + if data.LocalAsn != nil { + gateway[isVPNGatewayLocalAsn] = *data.LocalAsn + } + if data.AdvertisedCIDRs != nil { + gateway[isVPNGatewayAdvertisedCidrs] = data.AdvertisedCIDRs + } gateway[isVPNGatewayResourceGroup] = *data.ResourceGroup.ID gateway[isVPNGatewaySubnet] = *data.Subnet.ID gateway[isVPNGatewayCrn] = *data.CRN diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateways_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateways_test.go index a973338165..8ae2855970 100644 --- a/ibm/service/vpc/data_source_ibm_is_vpn_gateways_test.go +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateways_test.go @@ -39,6 +39,8 @@ func TestAccIBMISVpnGatewaysDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateways.test1", "vpn_gateways.0.vpc.0.crn"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateways.test1", "vpn_gateways.0.vpc.0.href"), resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateways.test1", "vpn_gateways.0.vpc.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateways.test1", "vpn_gateways.0.local_asn"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateways.test1", "vpn_gateways.0.advertised_cidrs.#"), ), }, }, @@ -60,9 +62,20 @@ func testAccCheckIBMISVpnGatewaysDataSourceConfig(vpc, subnet, name string) stri } resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet.id}" + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + mode = "route" + local_asn = 64520 + lifecycle { + ignore_changes = [ + advertised_cidrs + ] + } } + resource "ibm_is_vpn_gateway_advertised_cidr" "example" { + vpn_gateway = ibm_is_vpn_gateway.testacc_vpnGateway.id + cidr = "10.45.0.0/25" + } data "ibm_is_vpn_gateways" "test1" { }`, vpc, subnet, acc.ISZoneName, acc.ISCIDR, name) diff --git a/ibm/service/vpc/resource_ibm_is_vpn_gateway.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway.go index 5c9fbf5164..0fcefcc73e 100644 --- a/ibm/service/vpc/resource_ibm_is_vpn_gateway.go +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway.go @@ -24,6 +24,8 @@ const ( isVPNGatewayName = "name" isVPNGatewayResourceGroup = "resource_group" isVPNGatewayMode = "mode" + isVPNGatewayLocalAsn = "local_asn" + isVPNGatewayAdvertisedCidrs = "advertised_cidrs" isVPNGatewayCRN = "crn" isVPNGatewayTags = "tags" isVPNGatewaySubnet = "subnet" @@ -255,6 +257,23 @@ func ResourceIBMISVPNGateway() *schema.Resource { Description: "mode in VPN gateway(route/policy)", }, + isVPNGatewayLocalAsn: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The local autonomous system number (ASN) for this VPN gateway and its connections.", + }, + + isVPNGatewayAdvertisedCidrs: { + Type: schema.TypeList, + // Optional: true, + Computed: true, + Description: "The additional CIDRs advertised through any enabled routing protocol (for example, BGP). The routing protocol will advertise routes with these CIDRs and VPC prefixes as route destinations.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + isVPNGatewayMembers: { Type: schema.TypeList, Computed: true, @@ -407,6 +426,11 @@ func vpngwCreate(context context.Context, d *schema.ResourceData, meta interface Name: &name, Mode: &mode, } + if localAsnIntf, ok := d.GetOk(isVPNGatewayLocalAsn); ok { + localAsn := int64(localAsnIntf.(int)) + vpnGatewayPrototype.LocalAsn = &localAsn + } + options := &vpcv1.CreateVPNGatewayOptions{ VPNGatewayPrototype: vpnGatewayPrototype, } @@ -633,6 +657,16 @@ func vpngwGet(context context.Context, d *schema.ResourceData, meta interface{}, return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway", "read", "set-resource_group").GetDiag() } } + if err = d.Set(isVPNGatewayAdvertisedCidrs, vpnGateway.AdvertisedCIDRs); err != nil { + err = fmt.Errorf("Error setting advertised_cidrs: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway", "read", "set-advertised_cidrs").GetDiag() + } + if vpnGateway.LocalAsn != nil { + if err = d.Set(isVPNGatewayLocalAsn, *vpnGateway.LocalAsn); err != nil { + err = fmt.Errorf("Error setting local_asn: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway", "read", "set-local_asn").GetDiag() + } + } if err = d.Set(isVPNGatewayMode, *vpnGateway.Mode); err != nil { err = fmt.Errorf("Error setting mode: %s", err) return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway", "read", "set-mode").GetDiag() @@ -672,22 +706,16 @@ func vpngwGet(context context.Context, d *schema.ResourceData, meta interface{}, func resourceIBMISVPNGatewayUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { id := d.Id() - name := "" hasChanged := false - if d.HasChange(isVPNGatewayName) { - name = d.Get(isVPNGatewayName).(string) - hasChanged = true - } - - err := vpngwUpdate(context, d, meta, id, name, hasChanged) + err := vpngwUpdate(context, d, meta, id, hasChanged) if err != nil { return err } return resourceIBMISVPNGatewayRead(context, d, meta) } -func vpngwUpdate(context context.Context, d *schema.ResourceData, meta interface{}, id, name string, hasChanged bool) diag.Diagnostics { +func vpngwUpdate(context context.Context, d *schema.ResourceData, meta interface{}, id string, hasChanged bool) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway", "update", "initialize-client") @@ -732,13 +760,26 @@ func vpngwUpdate(context context.Context, d *schema.ResourceData, meta interface "Error on update of resource VPC VPN Gateway (%s) access tags: %s", d.Id(), err) } } - if hasChanged { - options := &vpcv1.UpdateVPNGatewayOptions{ - ID: &id, - } - vpnGatewayPatchModel := &vpcv1.VPNGatewayPatch{ - Name: &name, + + options := &vpcv1.UpdateVPNGatewayOptions{ + ID: &id, + } + vpnGatewayPatchModel := &vpcv1.VPNGatewayPatch{} + if d.HasChange(isVPNGatewayName) { + name := d.Get(isVPNGatewayName).(string) + vpnGatewayPatchModel.Name = &name + hasChanged = true + } + + if d.HasChange(isVPNGatewayLocalAsn) { + if localAsnIntf, ok := d.GetOk(isVPNGatewayLocalAsn); ok { + localAsn := core.Int64Ptr(int64(localAsnIntf.(int))) + vpnGatewayPatchModel.LocalAsn = localAsn + hasChanged = true } + } + + if hasChanged { vpnGatewayPatch, err := vpnGatewayPatchModel.AsPatch() if err != nil { tfErr := flex.TerraformErrorf(err, fmt.Sprintf("vpnGatewayPatchModel.AsPatch() failed: %s", err.Error()), "ibm_is_vpn_gateway", "update") diff --git a/ibm/service/vpc/resource_ibm_is_vpn_gateway_advertised_cidrs.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway_advertised_cidrs.go new file mode 100644 index 0000000000..e14313a58c --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway_advertised_cidrs.go @@ -0,0 +1,215 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isVPNGatewayAdvertisedCidr = "cidr" + isVPNGatewayAdvertisedCidrVPNGateway = "vpn_gateway" + isVPNGatewayAdvertisedCidrDeleting = "deleting" + isVPNGatewayAdvertisedCidrDeleted = "done" +) + +func ResourceIBMISVPNGatewayAdvertisedCidr() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMISVPNGatewayAdvertisedCidrCreate, + ReadContext: resourceIBMISVPNGatewayAdvertisedCidrRead, + DeleteContext: resourceIBMISVPNGatewayAdvertisedCidrDelete, + + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + isVPNGatewayAdvertisedCidrVPNGateway: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The VPN gateway identifier", + }, + isVPNGatewayAdvertisedCidr: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The IP address range in CIDR block notation.", + }, + }, + } +} + +func resourceIBMISVPNGatewayAdvertisedCidrCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + log.Printf("[DEBUG] Adding advertised cidr to vpn gateway") + + gatewayID := d.Get(isVPNGatewayAdvertisedCidrVPNGateway).(string) + cidr := d.Get(isVPNGatewayAdvertisedCidr).(string) + + options := &vpcv1.AddVPNGatewayAdvertisedCIDROptions{ + VPNGatewayID: &gatewayID, + CIDR: &cidr, + } + + sess, err := vpcClient(meta) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("vpcClient creation failed: %s", err.Error()), "ibm_is_vpn_gateway_advertised_cidr", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + + response, err := sess.AddVPNGatewayAdvertisedCIDR(options) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error adding advertised cidr to VPN Gateway err %s\n%s", err, response), "ibm_is_vpn_gateway_advertised_cidr", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + d.SetId(fmt.Sprintf("%s/%s", gatewayID, cidr)) + + return resourceIBMISVPNGatewayAdvertisedCidrRead(context, d, meta) +} + +func resourceIBMISVPNGatewayAdvertisedCidrRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := vpcClient(meta) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("vpcClient creation failed: %s", err.Error()), "ibm_is_vpn_gateway_advertised_cidr", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_advertised_cidr", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + + gID := parts[0] + gAdvertisedCidr := parts[1] + "/" + parts[2] + + checkVPNGatewayAdvertisedCIDROptions := &vpcv1.CheckVPNGatewayAdvertisedCIDROptions{ + VPNGatewayID: &gID, + CIDR: &gAdvertisedCidr, + } + response, err := sess.CheckVPNGatewayAdvertisedCIDR(checkVPNGatewayAdvertisedCIDROptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error getting advertised cidr : %s\n%s", err, response), "ibm_is_vpn_gateway_advertised_cidr", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + return nil +} + +func resourceIBMISVPNGatewayAdvertisedCidrDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + parts, err := flex.IdParts(d.Id()) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_advertised_cidr", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + + gID := parts[0] + cidr := parts[1] + "/" + parts[2] + + deleteErr := vpngwAdvertisedCidrDelete(d, meta, gID, cidr) + if deleteErr != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error deleting advertised cidr err %s", err), "ibm_is_vpn_gateway_advertised_cidr", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + return nil +} + +func vpngwAdvertisedCidrDelete(d *schema.ResourceData, meta interface{}, gID, gCidr string) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("vpcClient creation failed: %s", err.Error()), "ibm_is_vpn_gateway_advertised_cidr", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + checkVPNGatewayAdvertisedCIDROptions := &vpcv1.CheckVPNGatewayAdvertisedCIDROptions{ + VPNGatewayID: &gID, + CIDR: &gCidr, + } + response, err := sess.CheckVPNGatewayAdvertisedCIDR(checkVPNGatewayAdvertisedCIDROptions) + + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error getting Vpn Gateway advertised cidr(%s): %s\n%s", gCidr, err, response), "ibm_is_vpn_gateway_advertised_cidr", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + + removeVPNGatewayAdvertisedCIDROptions := &vpcv1.RemoveVPNGatewayAdvertisedCIDROptions{ + VPNGatewayID: &gID, + CIDR: &gCidr, + } + response, err = sess.RemoveVPNGatewayAdvertisedCIDR(removeVPNGatewayAdvertisedCIDROptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error removing advertised cidr from Vpn Gateway: %s\n%s", err, response), "ibm_is_vpn_gateway_advertised_cidr", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + + _, err = isWaitForVPNGatewayAdvertisedCIDRDeleted(sess, gID, gCidr, d.Timeout(schema.TimeoutDelete)) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error checking for Vpn Gateway advertised cidr (%s) is deleted: %s", gCidr, err), "ibm_is_vpn_gateway_advertised_cidr", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return diag.FromErr(tfErr) + } + + d.SetId("") + return nil +} + +func isWaitForVPNGatewayAdvertisedCIDRDeleted(vpnGatewayAdverisedCidr *vpcv1.VpcV1, gID, gCidr string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for VPNGatewayAdvertisedCIDR (%s) to be deleted.", gCidr) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isVPNGatewayAdvertisedCidrDeleting}, + Target: []string{"", isVPNGatewayAdvertisedCidrDeleted}, + Refresh: isVPNGatewayAdvertisedCIDRDeleteRefreshFunc(vpnGatewayAdverisedCidr, gID, gCidr), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isVPNGatewayAdvertisedCIDRDeleteRefreshFunc(vpnGatewayAdverisedCidr *vpcv1.VpcV1, gID, gCidr string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + checkVPNGatewayAdvertisedCIDROptions := &vpcv1.CheckVPNGatewayAdvertisedCIDROptions{ + VPNGatewayID: &gID, + CIDR: &gCidr, + } + response, err := vpnGatewayAdverisedCidr.CheckVPNGatewayAdvertisedCIDR(checkVPNGatewayAdvertisedCIDROptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return "", isVPNGatewayConnectionDeleted, nil + } + return "", "", fmt.Errorf("[ERROR] The VPNGateway Advertised CIDR %s failed to delete: %s\n%s", gCidr, err, response) + } + return nil, isVPNGatewayConnectionDeleting, nil + } +} diff --git a/ibm/service/vpc/resource_ibm_is_vpn_gateway_advertised_cidrs_test.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway_advertised_cidrs_test.go new file mode 100644 index 0000000000..8ddc3744ca --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway_advertised_cidrs_test.go @@ -0,0 +1,140 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + 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" + "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" +) + +func TestAccIBMISVPNGatewayAdvertisedCidr_basic(t *testing.T) { + var advertisedCidr string + + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + vpnname := fmt.Sprintf("tfvpngc-vpn-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVPNGatewayAdvertisedCidrDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVPNGatewayAdvertisedCidrConfig(vpcname, subnetname, vpnname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayAdvertisedCidrExists("ibm_is_vpn_gateway_advertised_cidr.example", &advertisedCidr), + ), + }, + }, + }) +} + +func testAccCheckIBMISVPNGatewayAdvertisedCidrDestroy(s *terraform.State) error { + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_vpn_gateway_advertised_cidr" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + gID := parts[0] + gCidr := parts[1] + + removeVPNGatewayAdvertisedCIDROptions := &vpcv1.RemoveVPNGatewayAdvertisedCIDROptions{ + VPNGatewayID: &gID, + CIDR: &gCidr, + } + response, err := sess.RemoveVPNGatewayAdvertisedCIDR(removeVPNGatewayAdvertisedCIDROptions) + if err == nil { + return fmt.Errorf("Advertised Cidr still exists: %v", response) + } + } + return nil +} + +func testAccCheckIBMISVPNGatewayAdvertisedCidrExists(n string, advertisedCidr *string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return fmt.Errorf("[ERROR] No Advertised Cidr is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + gID := parts[0] + gAdvertisedCidr := parts[1] + + checkVPNGatewayAdvertisedCIDROptions := &vpcv1.CheckVPNGatewayAdvertisedCIDROptions{ + VPNGatewayID: &gID, + CIDR: &gAdvertisedCidr, + } + + response, err := sess.CheckVPNGatewayAdvertisedCIDR(checkVPNGatewayAdvertisedCIDROptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + *advertisedCidr = "" + return nil + } + return fmt.Errorf("[ERROR] Error getting Advertised Cidr : %s\n%s", err, response) + } + *advertisedCidr = fmt.Sprintf("%s/%s", gID, gAdvertisedCidr) + return nil + } +} + +func testAccCheckIBMISVPNGatewayAdvertisedCidrConfig(vpcname, subnetname, vpnname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "example" { + name = "%s" + } + resource "ibm_is_subnet" "example" { + name = "%s" + vpc = ibm_is_vpc.example.id + zone = "%s" + ipv4_cidr_block = "%s" + + } + resource "ibm_is_vpn_gateway" "example" { + name = "%s" + subnet = ibm_is_subnet.example.id + mode = "route" + local_asn = 64520 + lifecycle { + ignore_changes = [ + advertised_cidrs + ] + } + } + resource "ibm_is_vpn_gateway_advertised_cidr" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id + cidr = "10.45.0.0/25" + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, vpnname) + +} diff --git a/ibm/service/vpc/resource_ibm_is_vpn_gateway_connection_test.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway_connection_test.go index 8f79ff27d3..4dec6cade3 100644 --- a/ibm/service/vpc/resource_ibm_is_vpn_gateway_connection_test.go +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway_connection_test.go @@ -1371,7 +1371,16 @@ func testAccCheckIBMISVPNGatewayConnectionAdvanceConfig(vpc1, subnet1, vpnname1, vpn_gateway = ibm_is_vpn_gateway.testacc_VPNGateway2.id peer { address = cidrhost(ibm_is_subnet.testacc_subnet4.ipv4_cidr_block, 15) - } + asn = 65533 + } + tunnel { + neighbor_ip = "192.168.1.4" + tunnel_interface_ip = "10.0.0.4" + } + tunnel { + neighbor_ip = "192.168.1.5" + tunnel_interface_ip = "10.0.0.5" + } preshared_key = "VPNDemoPassword" } `, vpc1, subnet1, acc.ISZoneName, subnet3, acc.ISZoneName, vpnname1, name1, name3, vpc2, subnet2, acc.ISZoneName, subnet4, acc.ISZoneName, vpnname2, name2, name4) diff --git a/ibm/service/vpc/resource_ibm_is_vpn_gateway_connections.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway_connections.go index 72deb0a912..e8cedae27d 100644 --- a/ibm/service/vpc/resource_ibm_is_vpn_gateway_connections.go +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway_connections.go @@ -200,6 +200,12 @@ func ResourceIBMISVPNGatewayConnection() *schema.Resource { Set: schema.HashString, Description: "VPN gateway connection peer CIDRs", }, + "asn": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The peer autonomous system number (ASN) for this VPN gateway connection.", + }, }, }, }, @@ -326,9 +332,30 @@ func ResourceIBMISVPNGatewayConnection() *schema.Resource { }, "routing_protocol": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "Routing protocols for this VPN gateway connection.", }, + "tunnel": { + Type: schema.TypeList, + MinItems: 2, + MaxItems: 2, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "neighbor_ip": { + Type: schema.TypeString, + Required: true, + Description: "The IP address of the neighbor on the virtual tunnel interface.", + }, + "tunnel_interface_ip": { + Type: schema.TypeString, + Required: true, + Description: "The IP address of the virtual tunnel interface.", + }, + }, + }, + }, isVPNGatewayConnectionCreatedat: { Type: schema.TypeString, @@ -359,6 +386,21 @@ func ResourceIBMISVPNGatewayConnection() *schema.Resource { Computed: true, Description: "The status of the VPN Tunnel", }, + "neighbor_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The IP address of the neighbor on the virtual tunnel interface.", + }, + "tunnel_interface_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The IP address of the virtual tunnel interface.", + }, + "protocol_state": { + Type: schema.TypeString, + Computed: true, + Description: "BGP routing protocol state.", + }, }, }, }, @@ -471,6 +513,10 @@ func vpngwconCreate(context context.Context, d *schema.ResourceData, meta interf log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) return tfErr.GetDiag() } + var protocol string + if routingProtocolOk, ok := d.GetOk("routing_protocol"); ok { + protocol = routingProtocolOk.(string) + } if *vpngateway.(*vpcv1.VPNGateway).Mode == "policy" { vpnGatewayConnectionPrototypeModel := &vpcv1.VPNGatewayConnectionPrototypeVPNGatewayConnectionPolicyModePrototype{ @@ -570,10 +616,124 @@ func vpngwconCreate(context context.Context, d *schema.ResourceData, meta interf vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionStaticRouteMode) d.SetId(fmt.Sprintf("%s/%s", gatewayID, *vpnGatewayConnection.ID)) log.Printf("[INFO] VPNGatewayConnection : %s/%s", gatewayID, *vpnGatewayConnection.ID) + } else if _, ok := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode); ok { + vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode) + d.SetId(fmt.Sprintf("%s/%s", gatewayID, *vpnGatewayConnection.ID)) + log.Printf("[INFO] VPNGatewayConnection : %s/%s", gatewayID, *vpnGatewayConnection.ID) } else { return flex.DiscriminatedTerraformErrorf(nil, fmt.Sprintf("Unrecognized vpcv1.VPNGatewayConnectionIntf subtype encountered"), "ibm_is_vpn_gateway_connection", "create", "unrecognized-subtype-of-VPNGatewayConnection").GetDiag() } - } else if *vpngateway.(*vpcv1.VPNGateway).Mode == "route" { + } else if *vpngateway.(*vpcv1.VPNGateway).Mode == "route" && protocol == "bgp" { + + vpnGatewayConnectionPrototypeModel := &vpcv1.VPNGatewayConnectionPrototypeVPNGatewayConnectionDynamicRouteModePrototype{ + Psk: &prephasedKey, + DeadPeerDetection: &vpcv1.VPNGatewayConnectionDpdPrototype{ + Action: &action, + Interval: &interval, + Timeout: &timeout, + }, + Name: &name, + } + if _, ok := d.GetOkExists(isVPNGatewayConnectionAdminStateup); ok { + stateUp := d.Get(isVPNGatewayConnectionAdminStateup).(bool) + vpnGatewayConnectionPrototypeModel.AdminStateUp = core.BoolPtr(stateUp) + } + var ikePolicyIdentity, ipsecPolicyIdentity string + if establishModeOk, ok := d.GetOk("establish_mode"); ok { + vpnGatewayConnectionPrototypeModel.EstablishMode = core.StringPtr(establishModeOk.(string)) + } + + if localOk, ok := d.GetOk("local"); ok && len(localOk.([]interface{})) > 0 { + log.Println("[INFO] inside local block") + LocalModel, err := resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionDynamicRouteModeLocalPrototype(localOk.([]interface{})[0].(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "create", "parse-local").GetDiag() + } + vpnGatewayConnectionPrototypeModel.Local = LocalModel + } + if peerOk, ok := d.GetOk("peer"); ok && len(peerOk.([]interface{})) > 0 { + PeerModel, err := resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionDynamicRouteModePeerPrototype(peerOk.([]interface{})[0].(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "create", "parse-peer").GetDiag() + } + vpnGatewayConnectionPrototypeModel.Peer = PeerModel + } else if peerAddress != "" { + model := &vpcv1.VPNGatewayConnectionDynamicRouteModePeerPrototype{} + if peerAddress != "" { + model.Address = &peerAddress + } + vpnGatewayConnectionPrototypeModel.Peer = model + } + + if ikePolicy, ok := d.GetOk(isVPNGatewayConnectionIKEPolicy); ok { + ikePolicyIdentity = ikePolicy.(string) + vpnGatewayConnectionPrototypeModel.IkePolicy = &vpcv1.VPNGatewayConnectionIkePolicyPrototype{ + ID: &ikePolicyIdentity, + } + } else { + vpnGatewayConnectionPrototypeModel.IkePolicy = nil + } + + if ipsecPolicy, ok := d.GetOk(isVPNGatewayConnectionIPSECPolicy); ok { + ipsecPolicyIdentity = ipsecPolicy.(string) + vpnGatewayConnectionPrototypeModel.IpsecPolicy = &vpcv1.VPNGatewayConnectionIPsecPolicyPrototype{ + ID: &ipsecPolicyIdentity, + } + } else { + vpnGatewayConnectionPrototypeModel.IpsecPolicy = nil + } + if distributeTrafficOk, ok := d.GetOkExists("distribute_traffic"); ok { + vpnGatewayConnectionPrototypeModel.DistributeTraffic = core.BoolPtr(distributeTrafficOk.(bool)) + } + if routingProtocolOk, ok := d.GetOk("routing_protocol"); ok { + vpnGatewayConnectionPrototypeModel.RoutingProtocol = core.StringPtr(routingProtocolOk.(string)) + } + + if tunnelOk, ok := d.GetOk("tunnel"); ok && len(tunnelOk.([]interface{})) > 0 { + log.Println("[INFO] inside tunnel block") + tunnelModels := []vpcv1.VPNGatewayConnectionTunnelPrototype{} + for _, tunnelItem := range tunnelOk.([]interface{}) { + tunnelModel := resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionTunnelPrototype(tunnelItem.(map[string]interface{})) + tunnelModels = append(tunnelModels, tunnelModel) + } + vpnGatewayConnectionPrototypeModel.Tunnels = tunnelModels + } + + options := &vpcv1.CreateVPNGatewayConnectionOptions{ + VPNGatewayID: &gatewayID, + VPNGatewayConnectionPrototype: vpnGatewayConnectionPrototypeModel, + } + + vpnGatewayConnectionIntf, _, err := sess.CreateVPNGatewayConnectionWithContext(context, options) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateVPNGatewayConnectionWithContext failed: %s", err.Error()), "ibm_is_vpn_gateway_connection", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + if _, ok := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnection); ok { + vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnection) + d.SetId(fmt.Sprintf("%s/%s", gatewayID, *vpnGatewayConnection.ID)) + log.Printf("[INFO] VPNGatewayConnection : %s/%s", gatewayID, *vpnGatewayConnection.ID) + } else if _, ok := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteMode); ok { + vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteMode) + d.SetId(fmt.Sprintf("%s/%s", gatewayID, *vpnGatewayConnection.ID)) + log.Printf("[INFO] VPNGatewayConnection : %s/%s", gatewayID, *vpnGatewayConnection.ID) + } else if _, ok := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionPolicyMode); ok { + vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionPolicyMode) + d.SetId(fmt.Sprintf("%s/%s", gatewayID, *vpnGatewayConnection.ID)) + log.Printf("[INFO] VPNGatewayConnection : %s/%s", gatewayID, *vpnGatewayConnection.ID) + } else if _, ok := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionStaticRouteMode); ok { + vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionStaticRouteMode) + d.SetId(fmt.Sprintf("%s/%s", gatewayID, *vpnGatewayConnection.ID)) + log.Printf("[INFO] VPNGatewayConnection : %s/%s", gatewayID, *vpnGatewayConnection.ID) + } else if _, ok := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode); ok { + vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode) + d.SetId(fmt.Sprintf("%s/%s", gatewayID, *vpnGatewayConnection.ID)) + log.Printf("[INFO] VPNGatewayConnection : %s/%s", gatewayID, *vpnGatewayConnection.ID) + } else { + return flex.DiscriminatedTerraformErrorf(nil, fmt.Sprintf("Unrecognized vpcv1.VPNGatewayConnectionIntf subtype encountered"), "ibm_is_vpn_gateway_connection", "create", "unrecognized-subtype-of-VPNGatewayConnection").GetDiag() + } + } else { vpnGatewayConnectionPrototypeModel := &vpcv1.VPNGatewayConnectionPrototypeVPNGatewayConnectionStaticRouteModePrototype{ Psk: &prephasedKey, @@ -624,6 +784,7 @@ func vpngwconCreate(context context.Context, d *schema.ResourceData, meta interf } else { vpnGatewayConnectionPrototypeModel.IkePolicy = nil } + if ipsecPolicy, ok := d.GetOk(isVPNGatewayConnectionIPSECPolicy); ok { ipsecPolicyIdentity = ipsecPolicy.(string) vpnGatewayConnectionPrototypeModel.IpsecPolicy = &vpcv1.VPNGatewayConnectionIPsecPolicyPrototype{ @@ -662,6 +823,10 @@ func vpngwconCreate(context context.Context, d *schema.ResourceData, meta interf vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionStaticRouteMode) d.SetId(fmt.Sprintf("%s/%s", gatewayID, *vpnGatewayConnection.ID)) log.Printf("[INFO] VPNGatewayConnection : %s/%s", gatewayID, *vpnGatewayConnection.ID) + } else if _, ok := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode); ok { + vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode) + d.SetId(fmt.Sprintf("%s/%s", gatewayID, *vpnGatewayConnection.ID)) + log.Printf("[INFO] VPNGatewayConnection : %s/%s", gatewayID, *vpnGatewayConnection.ID) } else { return flex.DiscriminatedTerraformErrorf(nil, fmt.Sprintf("Unrecognized vpcv1.VPNGatewayConnectionIntf subtype encountered"), "ibm_is_vpn_gateway_connection", "create", "unrecognized-subtype-of-VPNGatewayConnection").GetDiag() } @@ -766,6 +931,42 @@ func vpngwconUpdate(context context.Context, d *schema.ResourceData, meta interf vpnGatewayConnectionPatchModel.DistributeTraffic = core.BoolPtr(d.Get("distribute_traffic").(bool)) hasChanged = true } + if d.HasChange("routing_protocol") { + vpnGatewayConnectionPatchModel.RoutingProtocol = core.StringPtr(d.Get("routing_protocol").(string)) + hasChanged = true + } + if d.HasChange("tunnel_neighbor_address") { + vpnGatewayConnectionPatchModel.Tunnels[0].NeighborIP.Address = core.StringPtr(d.Get("tunnel_neighbor_address").(string)) + hasChanged = true + } + if d.HasChange("tunnel_interface_address") { + vpnGatewayConnectionPatchModel.Tunnels[0].TunnelInterfaceIP.Address = core.StringPtr(d.Get("tunnel_interface_address").(string)) + hasChanged = true + } + + if d.HasChange("tunnel") { + log.Println("[INFO] inside tunnel block") + options := &vpcv1.GetVPNGatewayConnectionOptions{ + VPNGatewayID: &gID, + ID: &gConnID, + } + _, response, err := sess.GetVPNGatewayConnectionWithContext(context, options) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVPNGatewayConnectionWithContext failed: %s", err.Error()), "ibm_is_vpn_gateway_connection", "get") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + eTag := response.Headers.Get("ETag") + updateVpnGatewayConnectionOptions.IfMatch = &eTag + + tunnelModels := []vpcv1.VPNGatewayConnectionTunnel{} + tunnelOk, _ := d.GetOk("tunnel") + for _, tunnelItem := range tunnelOk.([]interface{}) { + tunnelModel := resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionTunnelPrototypePatch(tunnelItem.(map[string]interface{})) + tunnelModels = append(tunnelModels, tunnelModel) + } + vpnGatewayConnectionPatchModel.Tunnels = tunnelModels + } if d.HasChange(isVPNGatewayConnectionName) { name := d.Get(isVPNGatewayConnectionName).(string) @@ -1171,6 +1372,58 @@ func resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionStaticRouteModeLo return model, nil } +func resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionDynamicRouteModeLocalPrototype(modelMap map[string]interface{}) (*vpcv1.VPNGatewayConnectionDynamicRouteModeLocalPrototype, error) { + model := &vpcv1.VPNGatewayConnectionDynamicRouteModeLocalPrototype{} + if modelMap["ike_identities"] != nil { + ikeIdentities := []vpcv1.VPNGatewayConnectionIkeIdentityPrototypeIntf{} + for _, ikeIdentitiesItem := range modelMap["ike_identities"].([]interface{}) { + ikeIdentitiesItemModel, err := resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionIkeIdentityPrototype(ikeIdentitiesItem.(map[string]interface{})) + if err != nil { + return model, err + } + ikeIdentities = append(ikeIdentities, ikeIdentitiesItemModel) + } + model.IkeIdentities = ikeIdentities + } + return model, nil +} + +func resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionTunnelPrototype(modelMap map[string]interface{}) vpcv1.VPNGatewayConnectionTunnelPrototype { + model := vpcv1.VPNGatewayConnectionTunnelPrototype{} + if model.NeighborIP == nil { + model.NeighborIP = &vpcv1.IP{} + } + if model.TunnelInterfaceIP == nil { + model.TunnelInterfaceIP = &vpcv1.IP{} + } + if neighborIP, ok := modelMap["neighbor_ip"].(string); ok { + model.NeighborIP.Address = core.StringPtr(neighborIP) + } + + if tunnelInterfaceIP, ok := modelMap["tunnel_interface_ip"].(string); ok { + model.TunnelInterfaceIP.Address = core.StringPtr(tunnelInterfaceIP) + } + return model +} + +func resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionTunnelPrototypePatch(modelMap map[string]interface{}) vpcv1.VPNGatewayConnectionTunnel { + model := vpcv1.VPNGatewayConnectionTunnel{} + if model.NeighborIP == nil { + model.NeighborIP = &vpcv1.IP{} + } + if model.TunnelInterfaceIP == nil { + model.TunnelInterfaceIP = &vpcv1.IP{} + } + if neighborIP, ok := modelMap["neighbor_ip"].(string); ok { + model.NeighborIP.Address = core.StringPtr(neighborIP) + } + + if tunnelInterfaceIP, ok := modelMap["tunnel_interface_ip"].(string); ok { + model.TunnelInterfaceIP.Address = core.StringPtr(tunnelInterfaceIP) + } + return model +} + func resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionIkeIdentityPrototype(modelMap map[string]interface{}) (vpcv1.VPNGatewayConnectionIkeIdentityPrototypeIntf, error) { model := &vpcv1.VPNGatewayConnectionIkeIdentityPrototype{} model.Type = core.StringPtr(modelMap["type"].(string)) @@ -1219,6 +1472,27 @@ func resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionStaticRouteModePe return model, nil } +func resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionDynamicRouteModePeerPrototype(modelMap map[string]interface{}) (vpcv1.VPNGatewayConnectionDynamicRouteModePeerPrototypeIntf, error) { + model := &vpcv1.VPNGatewayConnectionDynamicRouteModePeerPrototype{} + if modelMap["asn"] != nil && modelMap["asn"].(int) > 0 { + model.Asn = core.Int64Ptr(int64(modelMap["asn"].(int))) + } + if modelMap["ike_identity"] != nil && len(modelMap["ike_identity"].([]interface{})) > 0 { + IkeIdentityModel, err := resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionIkeIdentityPrototype(modelMap["ike_identity"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.IkeIdentity = IkeIdentityModel + } + if modelMap["address"] != nil && modelMap["address"].(string) != "" { + model.Address = core.StringPtr(modelMap["address"].(string)) + } + if modelMap["fqdn"] != nil && modelMap["fqdn"].(string) != "" { + model.Fqdn = core.StringPtr(modelMap["fqdn"].(string)) + } + return model, nil +} + func resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionPeerPatch(modelMap map[string]interface{}) (vpcv1.VPNGatewayConnectionPeerPatchIntf, error) { model := &vpcv1.VPNGatewayConnectionPeerPatch{} if modelMap["address"] != nil && modelMap["address"].(string) != "" { @@ -1227,6 +1501,10 @@ func resourceIBMIsVPNGatewayConnectionMapToVPNGatewayConnectionPeerPatch(modelMa if modelMap["fqdn"] != nil && modelMap["fqdn"].(string) != "" { model.Fqdn = core.StringPtr(modelMap["fqdn"].(string)) } + if modelMap["asn"] != nil { + localAsn := core.Int64Ptr(int64(modelMap["asn"].(int))) + model.Asn = localAsn + } return model, nil } func resourceIBMIsVPNGatewayConnectionVPNGatewayConnectionStaticRouteModeLocalToMap(model *vpcv1.VPNGatewayConnectionStaticRouteModeLocal) (map[string]interface{}, error) { @@ -1754,6 +2032,142 @@ func setvpnGatewayConnectionIntfResource(context context.Context, d *schema.Reso d.Set("tunnels", []map[string]interface{}{}) } } + case "*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode": + { + vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionRouteModeVPNGatewayConnectionDynamicRouteMode) + d.SetId(fmt.Sprintf("%s/%s", vpn_gateway_id, *vpnGatewayConnection.ID)) + if err = d.Set("admin_state_up", vpnGatewayConnection.AdminStateUp); err != nil { + err = fmt.Errorf("Error setting admin_state_up: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-admin_state_up").GetDiag() + } + if err = d.Set("authentication_mode", vpnGatewayConnection.AuthenticationMode); err != nil { + err = fmt.Errorf("Error setting authentication_mode: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-authentication_mode").GetDiag() + } + if err = d.Set("created_at", flex.DateTimeToString(vpnGatewayConnection.CreatedAt)); err != nil { + err = fmt.Errorf("Error setting created_at: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-created_at").GetDiag() + } + if !core.IsNil(vpnGatewayConnection.DistributeTraffic) { + if err = d.Set("distribute_traffic", vpnGatewayConnection.DistributeTraffic); err != nil { + err = fmt.Errorf("Error setting distribute_traffic: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-distribute_traffic").GetDiag() + } + } + if vpnGatewayConnection.DeadPeerDetection != nil { + if err = d.Set(isVPNGatewayConnectionDeadPeerDetectionAction, vpnGatewayConnection.DeadPeerDetection.Action); err != nil { + err = fmt.Errorf("Error setting action: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-action").GetDiag() + } + + if err = d.Set(isVPNGatewayConnectionDeadPeerDetectionInterval, vpnGatewayConnection.DeadPeerDetection.Interval); err != nil { + err = fmt.Errorf("Error setting interval: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-interval").GetDiag() + } + + if err = d.Set(isVPNGatewayConnectionDeadPeerDetectionTimeout, vpnGatewayConnection.DeadPeerDetection.Timeout); err != nil { + err = fmt.Errorf("Error setting timeout: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-timeout").GetDiag() + } + } + if err = d.Set("href", vpnGatewayConnection.Href); err != nil { + err = fmt.Errorf("Error setting href: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-href").GetDiag() + } + + if vpnGatewayConnection.IkePolicy != nil { + if err = d.Set("ike_policy", vpnGatewayConnection.IkePolicy.ID); err != nil { + err = fmt.Errorf("Error setting ike_policy: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-ike_policy").GetDiag() + } + } + + if vpnGatewayConnection.IpsecPolicy != nil { + if err = d.Set("ipsec_policy", vpnGatewayConnection.IpsecPolicy.ID); err != nil { + err = fmt.Errorf("Error setting ipsec_policy: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-ipsec_policy").GetDiag() + } + } + if err = d.Set("mode", vpnGatewayConnection.Mode); err != nil { + err = fmt.Errorf("Error setting mode: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-mode").GetDiag() + } + if err = d.Set("name", vpnGatewayConnection.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-name").GetDiag() + } + + // breaking changes + if err = d.Set("establish_mode", vpnGatewayConnection.EstablishMode); err != nil { + err = fmt.Errorf("Error setting establish_mode: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-establish_mode").GetDiag() + } + local := []map[string]interface{}{} + if vpnGatewayConnection.Local != nil { + modelMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModeLocalToMap(vpnGatewayConnection.Local) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "local-to-map").GetDiag() + + } + local = append(local, modelMap) + } + if err = d.Set("local", local); err != nil { + err = fmt.Errorf("Error setting status_reasons: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-local").GetDiag() + } + + peer := []map[string]interface{}{} + if vpnGatewayConnection.Peer != nil { + modelMap, err := dataSourceIBMIsVPNGatewayConnectionVPNGatewayConnectionDynamicRouteModePeerToMap(vpnGatewayConnection.Peer) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "peer-to-map").GetDiag() + + } + peer = append(peer, modelMap) + } + if err = d.Set("peer", peer); err != nil { + err = fmt.Errorf("Error setting peer: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-peer").GetDiag() + } + // Deprecated + if vpnGatewayConnection.Peer != nil { + peer := vpnGatewayConnection.Peer.(*vpcv1.VPNGatewayConnectionDynamicRouteModePeer) + if err = d.Set("peer_address", peer.Address); err != nil { + err = fmt.Errorf("Error setting peer_address: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-peer_address").GetDiag() + } + } + if err = d.Set("preshared_key", vpnGatewayConnection.Psk); err != nil { + err = fmt.Errorf("Error setting psk: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-psk").GetDiag() + } + if err = d.Set("resource_type", vpnGatewayConnection.ResourceType); err != nil { + err = fmt.Errorf("Error setting resource_type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-resource_type").GetDiag() + } + if err = d.Set("status", vpnGatewayConnection.Status); err != nil { + err = fmt.Errorf("Error setting status: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-status").GetDiag() + } + if err := d.Set("status_reasons", resourceVPNGatewayConnectionFlattenLifecycleReasons(vpnGatewayConnection.StatusReasons)); err != nil { + err = fmt.Errorf("Error setting status_reasons: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-status_reasons").GetDiag() + } + if err = d.Set("routing_protocol", vpnGatewayConnection.RoutingProtocol); err != nil { + err = fmt.Errorf("Error setting routing_protocol: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-routing_protocol").GetDiag() + } + + if vpnGatewayConnection.Tunnels != nil { + err = d.Set("tunnels", resourceVPNGatewayConnectionsFlattenDynamicTunnels(vpnGatewayConnection.Tunnels)) + if err != nil { + err = fmt.Errorf("Error setting tunnels: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_vpn_gateway_connection", "read", "set-tunnels").GetDiag() + } + } else { + d.Set("tunnels", []map[string]interface{}{}) + } + } case "*vpcv1.VPNGatewayConnectionPolicyMode": { vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnectionPolicyMode) @@ -1921,3 +2335,33 @@ func resourceVPNGatewayConnectionTunnelsToMap(tunnelsItem vpcv1.VPNGatewayConnec return tunnelsMap } + +func resourceVPNGatewayConnectionsFlattenDynamicTunnels(result []vpcv1.VPNGatewayConnectionDynamicRouteModeTunnel) (tunnels []map[string]interface{}) { + for _, tunnelsItem := range result { + tunnels = append(tunnels, resourceVPNGatewayConnectionsDynamicTunnelsToMap(tunnelsItem)) + } + + return tunnels +} + +func resourceVPNGatewayConnectionsDynamicTunnelsToMap(tunnelsItem vpcv1.VPNGatewayConnectionDynamicRouteModeTunnel) (tunnelsMap map[string]interface{}) { + tunnelsMap = map[string]interface{}{} + + if tunnelsItem.NeighborIP != nil { + tunnelsMap["neighbor_ip"] = tunnelsItem.NeighborIP.Address + } + if tunnelsItem.ProtocolState != nil { + tunnelsMap["protocol_state"] = tunnelsItem.ProtocolState + } + if tunnelsItem.PublicIP != nil { + tunnelsMap["address"] = tunnelsItem.PublicIP.Address + } + if tunnelsItem.Status != nil { + tunnelsMap["status"] = tunnelsItem.Status + } + if tunnelsItem.TunnelInterfaceIP != nil { + tunnelsMap["tunnel_interface_ip"] = tunnelsItem.TunnelInterfaceIP.Address + } + + return tunnelsMap +} diff --git a/ibm/service/vpc/resource_ibm_is_vpn_gateway_test.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway_test.go index 4b68e3e4f8..2622a834b1 100644 --- a/ibm/service/vpc/resource_ibm_is_vpn_gateway_test.go +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway_test.go @@ -62,6 +62,8 @@ func TestAccIBMISVPNGateway_route(t *testing.T) { "ibm_is_vpn_gateway.testacc_vpnGateway", "name", name1), resource.TestCheckResourceAttr( "ibm_is_vpn_gateway.testacc_vpnGateway", "mode", "route"), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway.testacc_vpnGateway", "local_asn", "64520"), ), }, { @@ -156,9 +158,15 @@ func testAccCheckIBMISVPNGatewayRouteConfig(vpc, subnet, name string) string { ipv4_cidr_block = "%s" } resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet.id}" - mode = "route" + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet.id}" + mode = "route" + local_asn = 64520 + lifecycle { + ignore_changes = [ + advertised_cidrs + ] + } }`, vpc, subnet, acc.ISZoneName, acc.ISCIDR, name) } diff --git a/website/docs/d/is_vpn_gateway.html.markdown b/website/docs/d/is_vpn_gateway.html.markdown index 12ee7f6fcf..2175a738cb 100644 --- a/website/docs/d/is_vpn_gateway.html.markdown +++ b/website/docs/d/is_vpn_gateway.html.markdown @@ -36,6 +36,7 @@ In addition to all argument references listed, you can access the following attr - `id` - The unique identifier of the is_vpn_gateway. - `access_tags` - (List) Access management tags associated for the vpn gateway. +- `advertised_cidrs` - (Optional, List) The additional CIDRs advertised through any enabled routing protocol (for example, BGP). The routing protocol will advertise routes with these CIDRs and VPC prefixes as route destinations. - `connections` - (List) Connections for this VPN gateway. Nested scheme for **connections**: - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. @@ -51,7 +52,7 @@ In addition to all argument references listed, you can access the following attr - `crn` - (String) The VPN gateway's CRN. - `href` - (String) The VPN gateway's canonical URL. - +- `local_asn` - (Integer) The local autonomous system number (ASN) for this VPN gateway and its connections. - `members` - (List) Collection of VPN gateway members. Nested scheme for **members**: @@ -67,7 +68,6 @@ In addition to all argument references listed, you can access the following attr - `role` - (String) The high availability role assigned to the VPN gateway member. - `mode` - (String) Route mode VPN gateway. - - `name` - (String) The user-defined name for this VPN gateway. - `resource_group` - (List) The resource group object, for this VPN gateway. diff --git a/website/docs/d/is_vpn_gateway_advertised_cidrs.html.markdown b/website/docs/d/is_vpn_gateway_advertised_cidrs.html.markdown new file mode 100644 index 0000000000..4725c35505 --- /dev/null +++ b/website/docs/d/is_vpn_gateway_advertised_cidrs.html.markdown @@ -0,0 +1,39 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_vpn_gateway_advertised_cidrs" +description: |- + Get information about VPNGatewayAdvertisedCIDRs +subcategory: "VPC infrastructure" +--- + +# ibm_is_vpn_gateway_advertised_cidrs + +Provides a read-only data source to retrieve information about VPNGatewayAdvertisedCIDRs. 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_vpn_gateway_advertised_cidrs" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id +} + +data "ibm_is_vpn_gateway_advertised_cidrs" "example-2" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `vpn_gateway` - (Optional, String) The VPN gateway identifier. +- `vpn_gateway_name` - (Optional, String) The VPN gateway name. + + ~> **Note** Provide either one of `vpn_gateway`, `vpn_gateway_name` to identifiy vpn gateway + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `advertised_cidrs` - (List) The additional CIDRs advertised through any enabled routing protocol (for example, BGP). The routing protocol will advertise routes with these CIDRs and VPC prefixes as route destinations. + diff --git a/website/docs/d/is_vpn_gateway_connection.html.markdown b/website/docs/d/is_vpn_gateway_connection.html.markdown index afe9f2fd52..28814ddef7 100644 --- a/website/docs/d/is_vpn_gateway_connection.html.markdown +++ b/website/docs/d/is_vpn_gateway_connection.html.markdown @@ -99,6 +99,7 @@ In addition to all argument references listed, you can access the following attr - `peer` - (List) Nested schema for **peer**: - `address` - (String) The IP address of the peer VPN gateway for this connection. + - `asn` - (Integer) The peer autonomous system number (ASN) for this VPN gateway connection. - `fqdn` - (String) The FQDN of the peer VPN gateway for this connection. - `ike_identity` - (List) The peer IKE identity. Nested schema for **ike_identity**: @@ -127,6 +128,9 @@ In addition to all argument references listed, you can access the following attr - `tunnels` - (List) The VPN tunnel configuration for this VPN gateway connection (in static route mode). Nested scheme for **tunnels**: + - `neighbor_ip` - (String) The IP address of the neighbor on the virtual tunnel interface. + - `protocol_state` - (String) BGP routing protocol state. - `public_ip_address` - (String) The IP address of the VPN gateway member in which the tunnel resides. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. - `status` - (String) The status of the VPN Tunnel. - + - `status_reasons` - (List) Array of reasons for the current status (if any). + - `tunnel_interface_ip` - (String) The IP address of the virtual tunnel interface. \ No newline at end of file diff --git a/website/docs/d/is_vpn_gateway_connections.html.markdown b/website/docs/d/is_vpn_gateway_connections.html.markdown index 6272e5241e..9793a5ec91 100644 --- a/website/docs/d/is_vpn_gateway_connections.html.markdown +++ b/website/docs/d/is_vpn_gateway_connections.html.markdown @@ -61,6 +61,7 @@ In addition to all argument reference list, you can access the following attribu - `peer` - (List) Nested schema for **peer**: - `address` - (String) The IP address of the peer VPN gateway for this connection. + - `asn` - (Integer) The peer autonomous system number (ASN) for this VPN gateway connection. - `fqdn` - (String) The FQDN of the peer VPN gateway for this connection. - `ike_identity` - (List) The peer IKE identity. Nested schema for **ike_identity**: @@ -75,9 +76,11 @@ In addition to all argument reference list, you can access the following attribu - `tunnels` - (List) The VPN tunnel configuration for the VPN gateway connection (in static route mode). Nested scheme for `tunnels`: - - `address` - (String) The IP address of the VPN gateway member in which the tunnel resides. + - `neighbor_ip` - (String) The IP address of the neighbor on the virtual tunnel interface. + - `protocol_state` - (String) BGP routing protocol state. - `status` - (String) The status of the VPN tunnel. -- `status_reasons` - (List) Array of reasons for the current status (if any). + - `status_reasons` - (List) Array of reasons for the current status (if any). + - `tunnel_interface_ip` - (String) The IP address of the virtual tunnel interface. Nested `status_reasons`: - `code` - (String) The status reason code. diff --git a/website/docs/d/is_vpn_gateway_service_connection.html.markdown b/website/docs/d/is_vpn_gateway_service_connection.html.markdown new file mode 100644 index 0000000000..f73a7f9e5a --- /dev/null +++ b/website/docs/d/is_vpn_gateway_service_connection.html.markdown @@ -0,0 +1,60 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_vpn_gateway_service_connection" +description: |- + Get information about IBM Cloud VPN Connection +--- + +# ibm_is_vpn_gateway_service_connection + +Provides a read-only data source for VPN gateway service Connection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_is_vpn_gateway_service_connection" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id + vpn_gateway_service_connection = "3066f374-97f7-4138-b59d-20a8414f49a8" +} +data "ibm_is_vpn_gateway_service_connection" "example-1" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name + vpn_gateway_service_connection = "3066f374-97f7-4138-b59d-20a8414f49a8" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `vpn_gateway` - (Optional, String) The VPN gateway identifier. +- `vpn_gateway_name` - (Optional, String) The VPN gateway name. +- `vpn_gateway_service_connection` - (Required, String) The VPN gateway service connection identifier. + + ~> **Note** Provide either one of `vpn_gateway`, `vpn_gateway_name` to identifiy vpn gateway. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `created_at` - (String) The date and time that this VPN gateway connection was created. +- `creator` - (List) + Nested scheme for **creator**: + - `crn` - (String) The CRN for this transit gateway. + - `id` - (String) The unique identifier for this transit gateway. + - `resource_type` - (String) The resource type. +- `id` - The unique identifier for this VPN gateway service connection. +- `lifecycle_reasons` - (List) The reasons for the current lifecycle_state (if any). + Nested scheme 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. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `message` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state` - (List) The lifecycle state of the VPN service connection. +- `status` - (String) The status of this service connection. +- `status_reasons` - (List) The reasons for the current VPN gateway service connection status (if any). + Nested `status_reasons`: + - `code` - (String) The status reason code. + - `message` - (String) An explanation of the reason for this VPN service connection's status. + - `more_info` - (String) Link to documentation about this status reason + + diff --git a/website/docs/d/is_vpn_gateway_service_connections.html.markdown b/website/docs/d/is_vpn_gateway_service_connections.html.markdown new file mode 100644 index 0000000000..babbc22e8d --- /dev/null +++ b/website/docs/d/is_vpn_gateway_service_connections.html.markdown @@ -0,0 +1,63 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : " +description: |- + Manages IBM VPN gateway connections. +--- + +# ibm_is_vpn_gateway_service_connections +Retrieve information of an existing VPN gateway connections. For more information, see [adding connections to a VPN gateway](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-adding-connections). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform + +data "ibm_is_vpn_gateway_service_connections" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id +} + +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `vpn_gateway` - (Required, String) The VPN gateway ID. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. +- `service_connections` - (List) List VPN gateway service connections. + + - `created_at` - (String) The date and time that this VPN gateway connection was created. + - `creator` - (List) + Nested scheme for **creator**: + - `crn` - (String) The CRN for this transit gateway. + - `id` - (String) The unique identifier for this transit gateway. + - `resource_type` - (String) The resource type. + - `id` - The unique identifier for this VPN gateway service connection. + - `lifecycle_reasons` - (List) The reasons for the current lifecycle_state (if any). + Nested scheme 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. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `message` - (String) Link to documentation about the reason for this lifecycle state. + - `lifecycle_state` - (List) The lifecycle state of the VPN service connection. + - `status` - (String) The status of this service connection. + - `status_reasons` - (List) The reasons for the current VPN gateway service connection status (if any). + Nested `status_reasons`: + - `code` - (String) The status reason code. + - `message` - (String) An explanation of the reason for this VPN service connection's status. + - `more_info` - (String) Link to documentation about this status reason + + diff --git a/website/docs/d/is_vpn_gateways.html.markdown b/website/docs/d/is_vpn_gateways.html.markdown index 457edbcfc7..206fed076d 100644 --- a/website/docs/d/is_vpn_gateways.html.markdown +++ b/website/docs/d/is_vpn_gateways.html.markdown @@ -45,6 +45,7 @@ In addition to all argument reference list, you can access the following attribu - `crn` - (String) The VPN gateway's CRN. - `created_at`- (Timestamp) The date and time the VPN gateway was created. - `id` - (String) The ID of the VPN gateway. + - `advertised_cidrs` - (Optional, List) The additional CIDRs advertised through any enabled routing protocol (for example, BGP). The routing protocol will advertise routes with these CIDRs and VPC prefixes as route destinations. - `name`- (String) The VPN gateway instance name. - `members` - (List) Collection of VPN gateway members. @@ -80,6 +81,7 @@ In addition to all argument reference list, you can access the following attribu - `message` - (String) An explanation of the reason for this lifecycle reason. - `more_info` - (String) Link to documentation about the reason for this lifecycle reason. - `lifecycle_state` - (String) The lifecycle state of the VPN gateway. + - `local_asn` - (Integer) The local autonomous system number (ASN) for this VPN gateway and its connections. - `subnet` - (String) The VPN gateway subnet information. - `tags`- (Optional, Array of Strings) A list of tags associated with the instance. - `vpc` - (String) The VPC this VPN server resides in. diff --git a/website/docs/r/is_vpn_gateway.html.markdown b/website/docs/r/is_vpn_gateway.html.markdown index 13929bfcac..4e44dca9ad 100644 --- a/website/docs/r/is_vpn_gateway.html.markdown +++ b/website/docs/r/is_vpn_gateway.html.markdown @@ -38,9 +38,10 @@ resource "ibm_is_subnet" "example" { } resource "ibm_is_vpn_gateway" "example" { - name = "example-vpn-gateway" - subnet = ibm_is_subnet.example.id - mode = "route" + name = "example-vpn-gateway" + subnet = ibm_is_subnet.example.id + mode = "route" + local_asn = 64520 } ``` @@ -55,6 +56,7 @@ The `ibm_is_vpn_gateway` resource provides the following [Timeouts](https://www. ## Argument reference Review the argument references that you can specify for your resource. +- `local_asn` - (Optional, Integer) The local autonomous system number (ASN) for this VPN gateway and its connections. - `mode`- (Optional, String) Mode in VPN gateway. Supported values are `route` or `policy`. The default value is `route`. - `name` - (Required, String) The name of the VPN gateway. - `resource_group` - (Optional, Forces new resource, String) The resource group (id), where the VPN gateway to be created. @@ -102,6 +104,7 @@ In addition to all argument reference list, you can access the following attribu - `message` - (String) An explanation of the reason for this lifecycle reason. - `more_info` - (String) Link to documentation about the reason for this lifecycle reason. - `lifecycle_state` - (String) The lifecycle state of the VPN gateway. +- `local_asn` - (Integer) The local autonomous system number (ASN) for this VPN gateway and its connections. - `vpc` - (String) The VPC this VPN server resides in. Nested scheme for `vpc`: - `crn` - (String) The CRN for this VPC. diff --git a/website/docs/r/is_vpn_gateway_advertised_cidr.html.markdown b/website/docs/r/is_vpn_gateway_advertised_cidr.html.markdown new file mode 100644 index 0000000000..763ee3b634 --- /dev/null +++ b/website/docs/r/is_vpn_gateway_advertised_cidr.html.markdown @@ -0,0 +1,85 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : VPN-gateway-advertised-cidr" +description: |- + Manages IBM VPN gateway connection. +--- + +# ibm_is_vpn_gateway_advertised_cidr +Update, or delete a VPN gateway advertised cidr. For more information, about VPN gateway, see [adding connections to a VPN gateway](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-adding-connections). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + + +## Example usage +The following example creates a VPN gateway: + +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + ipv4_cidr_block = "10.240.0.0/24" +} + +resource "ibm_is_subnet" "example2" { + name = "example-subnet2" + vpc = ibm_is_vpc.example.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.68.0/24" +} + +resource "ibm_is_vpn_gateway" "example" { + name = "example-vpn-gateway" + subnet = ibm_is_subnet.example.id + mode = "route" +} + +resource "ibm_is_vpn_gateway_advertised_cidr" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id + cidr = "10.45.0.0/24" +} + +``` + +## Timeouts +The `ibm_is_vpn_gateway_advertised_cidr` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **delete** - (Default 10 minutes) Used for deleting instance. + + +## Argument reference +Review the argument references that you can specify for your resource. + +- `cidr` - (Required, Force new resource, String) The IP address range in CIDR block notation. +- `vpn_gateway` - (Required, Force new resource, String) The unique identifier of the VPN gateway. + +## Import +The `ibm_is_vpn_gateway_advertised_cidr` resource can be imported by using the VPN gateway ID and the Advertised Cidr. + +**Syntax** + +``` +$ terraform import ibm_is_vpn_gateway_advertised_cidr.example / +``` + +**Example** + +``` +$ terraform import ibm_is_vpn_gateway_advertised_cidr.example d7bec597-4726-451f-8a63-e62e6f19c32c/10.45.0.0/24 +``` diff --git a/website/docs/r/is_vpn_gateway_connection.html.markdown b/website/docs/r/is_vpn_gateway_connection.html.markdown index 92c84c6ade..49a2de6acc 100644 --- a/website/docs/r/is_vpn_gateway_connection.html.markdown +++ b/website/docs/r/is_vpn_gateway_connection.html.markdown @@ -96,6 +96,53 @@ resource "ibm_is_vpn_gateway_connection" "example" { ``` +## Example usage ( route mode with bgp protocol ) +The following example creates a VPN gateway: + +```terraform +resource "ibm_is_vpn_gateway" "example" { + name = "example-vpn-gateway" + subnet = ibm_is_subnet.example.id + mode = "route" + local_asn = 64522 +} + +resource "ibm_is_vpn_gateway_connection" "example" { + name = "example-vpn-gateway-connection" + vpn_gateway = ibm_is_vpn_gateway.example.id + preshared_key = "VPNDemoPassword" + distribute_traffic = true + routing_protocol = "bgp" + local { + ike_identities { + type = "fqdn" + value = "fqdn.example.com" + } + ike_identities { + type = "fqdn" + value = "fqdn.example.com" + } + } + peer { + ike_identity { + type = "fqdn" + value = "example.fqdn.com" + } + fqdn = "peer-vpn.example.com" + asn = 65534 + } + tunnel { + neighbor_ip = "192.168.1.8" + tunnel_interface_ip = "10.0.0.8" + } + tunnel { + neighbor_ip = "192.168.1.6" + tunnel_interface_ip = "10.0.0.6" + } +} + +``` + ## Timeouts The `ibm_is_vpn_gateway_connection` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: @@ -107,6 +154,7 @@ Review the argument references that you can specify for your resource. - `action` - (Optional, String) Dead peer detection actions. Supported values are **restart**, **clear**, **hold**, or **none**. Default value is `restart`. - `admin_state_up` - (Optional, Bool) The VPN gateway connection status. Default value is **false**. If set to false, the VPN gateway connection is shut down. +- `asn` - (Optional, String) The peer autonomous system number (ASN) for this VPN gateway connection. - `distribute_traffic` - (Optional, Bool) Indicates whether the traffic is distributed between the `up` tunnels of the VPN gateway connection when the VPC route's next hop is a VPN connection. If `false`, the traffic is only routed through the `up` tunnel with the lower `public_ip` address. Distributing traffic across tunnels of route-based VPN gateway connections. Traffic across tunnels can be distributed with a status of up in a route-based VPN gateway connection. When creating or updating a route-based VPN gateway connection, set the distribute_traffic property to true (default is false). Existing connections will have the `distribute_traffic` property set to false. - `establish_mode` - (Optional, String) The establish mode of the VPN gateway connection:- `bidirectional`: Either side of the VPN gateway can initiate IKE protocol negotiations or rekeying processes.- `peer_only`: Only the peer can initiate IKE protocol negotiations for this VPN gateway connection. Additionally, the peer is responsible for initiating the rekeying process after the connection is established. If rekeying does not occur, the VPN gateway connection will be brought down after its lifetime expires. - `ike_policy` - (Optional, String) The ID of the IKE policy. Updating value from ID to `""` or making it `null` or removing it will remove the existing policy. @@ -133,7 +181,12 @@ Review the argument references that you can specify for your resource. - `peer_cidrs` - (Optional, DEPRECATED, Forces new resource, List) List of peer CIDRs for this resource. `peer_cidrs` is deprecated and use `peer` block instead. - `peer_address` - (Optional, DEPRECATED, String) The IP address of the peer VPN gateway. `peer_address` is deprecated and use `peer` block instead. - `preshared_key` - (Required, Forces new resource, String) The preshared key. +- `routing_protocol` - (Optional, String) The peer autonomous system number (ASN) for this VPN gateway connection. - `timeout` - (Optional, Integer) Dead peer detection timeout in seconds. Default value is 10. +- `tunnel` - (Optional, List) + Nested schema for **tunnel**: + - `neighbor_ip` - (Required, String) The IP address of the neighbor on the virtual tunnel interface. + - `tunnel_interface_ip` - (Required, String) The IP address of the virtual tunnel interface. - `vpn_gateway` - (Required, Forces new resource, String) The unique identifier of the VPN gateway. ## Attribute reference