Skip to content

Commit

Permalink
resource apstra_datacenter_external_gateway tests
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismarget-j committed Nov 3, 2023
1 parent 07b0094 commit 52793d0
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 22 deletions.
54 changes: 35 additions & 19 deletions apstra/blueprint/datacenter_external_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import (
"context"
"fmt"
"github.com/Juniper/apstra-go-sdk/apstra"
customtypes "github.com/Juniper/terraform-provider-apstra/apstra/custom_types"
"github.com/Juniper/terraform-provider-apstra/apstra/utils"
"github.com/hashicorp/terraform-plugin-framework-nettypes/iptypes"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
Expand All @@ -22,16 +23,16 @@ import (
)

type DatacenterExternalGateway struct {
Id types.String `tfsdk:"id"`
BlueprintId types.String `tfsdk:"blueprint_id"`
Name types.String `tfsdk:"name"`
IpAddress customtypes.IPv46Address `tfsdk:"ip_address"`
Asn types.Int64 `tfsdk:"asn"`
Ttl types.Int64 `tfsdk:"ttl"`
KeepaliveTime types.Int64 `tfsdk:"keepalive_time"`
HoldTime types.Int64 `tfsdk:"hold_time"`
EvpnRouteTypes types.String `tfsdk:"evpn_route_types"`
LocalGatewayNodes types.Set `tfsdk:"local_gateway_nodes"`
Id types.String `tfsdk:"id"`
BlueprintId types.String `tfsdk:"blueprint_id"`
Name types.String `tfsdk:"name"`
IpAddress iptypes.IPv4Address `tfsdk:"ip_address"`
Asn types.Int64 `tfsdk:"asn"`
Ttl types.Int64 `tfsdk:"ttl"`
KeepaliveTime types.Int64 `tfsdk:"keepalive_time"`
HoldTime types.Int64 `tfsdk:"hold_time"`
EvpnRouteTypes types.String `tfsdk:"evpn_route_types"`
LocalGatewayNodes types.Set `tfsdk:"local_gateway_nodes"`
}

func (o DatacenterExternalGateway) ResourceAttributes() map[string]resourceSchema.Attribute {
Expand All @@ -55,7 +56,7 @@ func (o DatacenterExternalGateway) ResourceAttributes() map[string]resourceSchem
"ip_address": resourceSchema.StringAttribute{
MarkdownDescription: "External Gateway IP address",
Required: true,
CustomType: customtypes.IPv46AddressType{},
CustomType: iptypes.IPv4AddressType{},
},
"asn": resourceSchema.Int64Attribute{
MarkdownDescription: "External Gateway AS Number",
Expand Down Expand Up @@ -92,6 +93,7 @@ func (o DatacenterExternalGateway) ResourceAttributes() map[string]resourceSchem
"local_gateway_nodes": resourceSchema.SetAttribute{
MarkdownDescription: "Set of IDs of switch nodes which will be configured to peer with the External Gateway",
Required: true,
ElementType: types.StringType,
Validators: []validator.Set{
setvalidator.SizeAtLeast(1),
setvalidator.ValueStringsAre(stringvalidator.LengthAtLeast(1)),
Expand All @@ -110,19 +112,33 @@ func (o *DatacenterExternalGateway) Request(ctx context.Context, diags *diag.Dia
return nil
}

ttl := uint8(o.Ttl.ValueInt64())
keepaliveTimer := uint16(o.KeepaliveTime.ValueInt64())
holdtimeTimer := uint16(o.HoldTime.ValueInt64())
var ttl *uint8
if utils.Known(o.Ttl) {
t := uint8(o.Ttl.ValueInt64())
ttl = &t
}

var keepaliveTimer *uint16
if utils.Known(o.KeepaliveTime) {
t := uint16(o.KeepaliveTime.ValueInt64())
keepaliveTimer = &t
}

var holdtimeTimer *uint16
if utils.Known(o.HoldTime) {
t := uint16(o.HoldTime.ValueInt64())
holdtimeTimer = &t
}

return &apstra.RemoteGatewayData{
RouteTypes: *routeTypes,
LocalGwNodes: localGwNodes,
GwAsn: uint32(o.Asn.ValueInt64()),
GwIp: net.ParseIP(o.IpAddress.ValueString()), // skipping nil check because input
GwName: o.Name.ValueString(), // validation should make that impossible
Ttl: &ttl,
KeepaliveTimer: &keepaliveTimer,
HoldtimeTimer: &holdtimeTimer,
Ttl: ttl,
KeepaliveTimer: keepaliveTimer,
HoldtimeTimer: holdtimeTimer,
}
}

Expand Down Expand Up @@ -161,7 +177,7 @@ func (o *DatacenterExternalGateway) loadApiData(_ context.Context, in *apstra.Re
}

o.Name = types.StringValue(in.GwName)
o.IpAddress = customtypes.NewIPv46AddressValue(in.GwIp.String())
o.IpAddress = iptypes.NewIPv4AddressValue(in.GwIp.String())
o.Asn = types.Int64Value(int64(in.GwAsn))
o.Ttl = ttl
o.KeepaliveTime = keepaliveTime
Expand Down
1 change: 1 addition & 0 deletions apstra/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ func (p *Provider) Resources(_ context.Context) []func() resource.Resource {
func() resource.Resource { return &resourceDatacenterConfiglet{} },
func() resource.Resource { return &resourceDatacenterConnectivityTemplate{} },
func() resource.Resource { return &resourceDatacenterConnectivityTemplateAssignment{} },
func() resource.Resource { return &resourceDatacenterExternalGateway{} },
func() resource.Resource { return &resourceDatacenterGenericSystem{} },
func() resource.Resource { return &resourceDatacenterPropertySet{} },
func() resource.Resource { return &resourceDatacenterRoutingZone{} },
Expand Down
155 changes: 155 additions & 0 deletions apstra/resource_datacenter_external_gateway_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package tfapstra_test

import (
"context"
"errors"
"fmt"
"github.com/Juniper/apstra-go-sdk/apstra"
testutils "github.com/Juniper/terraform-provider-apstra/apstra/test_utils"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"net"
"strconv"
"strings"
"testing"
)

const (
resourceDataCenterExternalGateway = `
resource "apstra_datacenter_external_gateway" "test" {
blueprint_id = "%s"
name = "%s"
ip_address = "%s"
asn = %d
evpn_route_types = "%s"
local_gateway_nodes = ["%s"]
ttl = %s
keepalive_time = %s
hold_time = %s
}
`
)

type testCaseResourceExternalGateway struct {
name string
ipAddress net.IP
asn uint32
routeTypes apstra.RemoteGatewayRouteTypes
nodes string
ttl *uint8
keepaliveTime *uint16
holdTime *uint16
testCheckFunc resource.TestCheckFunc
}

func renderResourceDataCenterExternalGateway(tc testCaseResourceExternalGateway, bp *apstra.TwoStageL3ClosClient) string {
return fmt.Sprintf(resourceDataCenterExternalGateway,
bp.Id(),
tc.name,
tc.ipAddress,
tc.asn,
tc.routeTypes.Value,
tc.nodes,
intPtrOrNull(tc.ttl),
intPtrOrNull(tc.keepaliveTime),
intPtrOrNull(tc.holdTime),
)
}

func TestResourceDatacenterExternalGateway(t *testing.T) {
ctx := context.Background()

bp, bpDelete, err := testutils.BlueprintC(ctx)
if err != nil {
t.Fatal(errors.Join(err, bpDelete(ctx)))
}
defer func() {
err = bpDelete(ctx)
if err != nil {
t.Error(err)
}
}()

leafIds := systemIds(ctx, t, bp, "leaf")
uint8Val3 := uint8(3)
uint16Val1 := uint16(1)
uint16Val3 := uint16(3)

testCases := []testCaseResourceExternalGateway{
{
name: "name1",
ipAddress: net.IP{1, 1, 1, 1},
asn: 1,
routeTypes: apstra.RemoteGatewayRouteTypesAll,
nodes: leafIds[0],
testCheckFunc: resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{
resource.TestCheckResourceAttrSet("apstra_datacenter_external_gateway.test", "id"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "blueprint_id", bp.Id().String()),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "name", "name1"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "ip_address", "1.1.1.1"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "asn", "1"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "evpn_route_types", apstra.RemoteGatewayRouteTypesAll.Value),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "local_gateway_nodes.#", "1"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "local_gateway_nodes.0", leafIds[0]),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "ttl", "30"), // default
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "keepalive_time", "10"), // default
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "hold_time", "30"), // default
}...),
},
{
name: "name2",
ipAddress: net.IP{1, 1, 1, 2},
asn: 2,
routeTypes: apstra.RemoteGatewayRouteTypesFiveOnly,
nodes: strings.Join(leafIds[1:], `","`),
testCheckFunc: resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{
resource.TestCheckResourceAttrSet("apstra_datacenter_external_gateway.test", "id"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "blueprint_id", bp.Id().String()),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "name", "name2"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "ip_address", "1.1.1.2"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "asn", "2"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "evpn_route_types", apstra.RemoteGatewayRouteTypesFiveOnly.Value),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "local_gateway_nodes.#", strconv.Itoa(len(leafIds)-1)),
resource.TestCheckTypeSetElemAttr("apstra_datacenter_external_gateway.test", "local_gateway_nodes.*", leafIds[1]),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "ttl", "30"), // default
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "keepalive_time", "10"), // default
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "hold_time", "30"), // default
}...),
},
{
name: "name3",
ipAddress: net.IP{1, 1, 1, 3},
asn: 3,
routeTypes: apstra.RemoteGatewayRouteTypesAll,
nodes: leafIds[0],
ttl: &uint8Val3,
keepaliveTime: &uint16Val1,
holdTime: &uint16Val3,
testCheckFunc: resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{
resource.TestCheckResourceAttrSet("apstra_datacenter_external_gateway.test", "id"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "blueprint_id", bp.Id().String()),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "name", "name3"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "ip_address", "1.1.1.3"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "asn", "3"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "evpn_route_types", apstra.RemoteGatewayRouteTypesAll.Value),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "local_gateway_nodes.#", "1"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "local_gateway_nodes.0", leafIds[0]),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "ttl", "3"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "keepalive_time", "1"),
resource.TestCheckResourceAttr("apstra_datacenter_external_gateway.test", "hold_time", "3"),
}...),
},
}

steps := make([]resource.TestStep, len(testCases))
for i, tc := range testCases {
steps[i] = resource.TestStep{
Config: insecureProviderConfigHCL + renderResourceDataCenterExternalGateway(tc, bp),
Check: tc.testCheckFunc,
}
}

resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: steps,
})
}
85 changes: 85 additions & 0 deletions apstra/test_helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package tfapstra_test

import (
"context"
"fmt"
"github.com/Juniper/apstra-go-sdk/apstra"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"golang.org/x/exp/constraints"
"net"
"testing"
)

func systemIds(ctx context.Context, t *testing.T, bp *apstra.TwoStageL3ClosClient, role string) []string {
query := new(apstra.PathQuery).
SetBlueprintType(apstra.BlueprintTypeStaging).
SetBlueprintId(bp.Id()).
SetClient(bp.Client()).
Node([]apstra.QEEAttribute{
apstra.NodeTypeSystem.QEEAttribute(),
{Key: "role", Value: apstra.QEStringVal(role)},
{Key: "name", Value: apstra.QEStringVal("n_system")},
})

var result struct {
Items []struct {
System struct {
Id string `json:"id"`
} `json:"n_system"`
} `json:"items"`
}

err := query.Do(ctx, &result)
if err != nil {
t.Fatal(err)
}

ids := make([]string, len(result.Items))
for i, item := range result.Items {
ids[i] = item.System.Id
}

return ids
}

func stringPtrOrNull(in *string) string {

Check failure on line 45 in apstra/test_helpers_test.go

View workflow job for this annotation

GitHub Actions / go-tools

func stringPtrOrNull is unused (U1000)
if in == nil {
return "null"
}
return `"` + *in + `"`
}

func stringOrNull(in string) string {

Check failure on line 52 in apstra/test_helpers_test.go

View workflow job for this annotation

GitHub Actions / go-tools

func stringOrNull is unused (U1000)
if in == "" {
return "null"
}
return `"` + in + `"`
}

func intPtrOrNull[A constraints.Integer](in *A) string {
if in == nil {
return "null"
}
return fmt.Sprintf("%d", *in)
}

func ipOrNull(in *net.IPNet) string {

Check failure on line 66 in apstra/test_helpers_test.go

View workflow job for this annotation

GitHub Actions / go-tools

func ipOrNull is unused (U1000)
if in == nil {
return "null"
}
return `"` + in.String() + `"`
}

func randIpAddressMust(t *testing.T, cidrBlock string) net.IP {

Check failure on line 73 in apstra/test_helpers_test.go

View workflow job for this annotation

GitHub Actions / go-tools

func randIpAddressMust is unused (U1000)
s, err := acctest.RandIpAddress(cidrBlock)
if err != nil {
t.Fatal(err)
}

ip := net.ParseIP(s)
if ip == nil {
t.Fatalf("randIpAddressMust failed to parse IP address %q", s)
}

return ip
}
22 changes: 22 additions & 0 deletions apstra/test_provider_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package tfapstra_test

import (
tfapstra "github.com/Juniper/terraform-provider-apstra/apstra"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
)

const (
insecureProviderConfigHCL = `
provider "apstra" {
tls_validation_disabled = true
blueprint_mutex_enabled = false
}
`
)

var (
testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
"apstra": providerserver.NewProtocol6WithError(tfapstra.NewProvider()),
}
)
1 change: 1 addition & 0 deletions apstra/test_utils/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func GetTestClient(ctx context.Context) (*apstra.Client, error) {
if err != nil {
return nil, err
}
clientCfg.Experimental = true
clientCfg.HttpClient.Transport.(*http.Transport).TLSClientConfig.InsecureSkipVerify = true

sharedClient, err = clientCfg.NewClient(ctx)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.20

require (
github.com/IBM/netaddr v1.5.0
github.com/Juniper/apstra-go-sdk v0.0.0-20231102202421-a97e1d145d70
github.com/Juniper/apstra-go-sdk v0.0.0-20231103220718-53fe09973dda
github.com/chrismarget-j/go-licenses v0.0.0-20230424163011-d60082a506e0
github.com/google/go-cmp v0.5.9
github.com/hashicorp/go-version v1.6.0
Expand Down
Loading

0 comments on commit 52793d0

Please sign in to comment.