* Merged PR 788126: feat(iaas): Onboard routing tables feat(iaas): Onboard routing tables Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de> * Merged PR 793350: fix(routingtable): region attribute is missing in scheme fix(routingtable): region attribute is missing in scheme Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de> * Merged PR 797968: feat(iaas): onboarding of routing table routes relates to STACKITTPR-241 * use iaasalpha sdk from github * resolve todos * remove routes from routing table model * restructure packages * acc tests routing tables * add acc tests for routes * chore(iaas): mark routing table resources as experimental * chore(deps): use iaasalpha sdk v0.1.19-alpha * Review feedback Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de> --------- Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de> Co-authored-by: Alexander Dahmen (EXT) <Alexander.Dahmen_ext@external.mail.schwarz> Co-authored-by: Alexander Dahmen <alexander.dahmen@inovex.de>
213 lines
6.3 KiB
Go
213 lines
6.3 KiB
Go
package shared
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hashicorp/terraform-plugin-framework/attr"
|
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
|
"github.com/stackitcloud/stackit-sdk-go/services/iaasalpha"
|
|
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
|
|
iaasUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/utils"
|
|
)
|
|
|
|
type RouteReadModel struct {
|
|
RouteId types.String `tfsdk:"route_id"`
|
|
Destination types.Object `tfsdk:"destination"`
|
|
NextHop types.Object `tfsdk:"next_hop"`
|
|
Labels types.Map `tfsdk:"labels"`
|
|
CreatedAt types.String `tfsdk:"created_at"`
|
|
UpdatedAt types.String `tfsdk:"updated_at"`
|
|
}
|
|
|
|
func RouteReadModelTypes() map[string]attr.Type {
|
|
return map[string]attr.Type{
|
|
"route_id": types.StringType,
|
|
"destination": types.ObjectType{AttrTypes: RouteDestinationTypes},
|
|
"next_hop": types.ObjectType{AttrTypes: RouteNextHopTypes},
|
|
"labels": types.MapType{ElemType: types.StringType},
|
|
"created_at": types.StringType,
|
|
"updated_at": types.StringType,
|
|
}
|
|
}
|
|
|
|
type RouteModel struct {
|
|
RouteReadModel
|
|
Id types.String `tfsdk:"id"` // needed by TF
|
|
OrganizationId types.String `tfsdk:"organization_id"`
|
|
RoutingTableId types.String `tfsdk:"routing_table_id"`
|
|
NetworkAreaId types.String `tfsdk:"network_area_id"`
|
|
Region types.String `tfsdk:"region"`
|
|
}
|
|
|
|
func RouteModelTypes() map[string]attr.Type {
|
|
modelTypes := RouteReadModelTypes()
|
|
modelTypes["id"] = types.StringType
|
|
modelTypes["organization_id"] = types.StringType
|
|
modelTypes["routing_table_id"] = types.StringType
|
|
modelTypes["network_area_id"] = types.StringType
|
|
modelTypes["region"] = types.StringType
|
|
return modelTypes
|
|
}
|
|
|
|
// RouteDestination is the struct corresponding to RouteReadModel.Destination
|
|
type RouteDestination struct {
|
|
Type types.String `tfsdk:"type"`
|
|
Value types.String `tfsdk:"value"`
|
|
}
|
|
|
|
// RouteDestinationTypes Types corresponding to routeDestination
|
|
var RouteDestinationTypes = map[string]attr.Type{
|
|
"type": types.StringType,
|
|
"value": types.StringType,
|
|
}
|
|
|
|
// RouteNextHop is the struct corresponding to RouteReadModel.NextHop
|
|
type RouteNextHop struct {
|
|
Type types.String `tfsdk:"type"`
|
|
Value types.String `tfsdk:"value"`
|
|
}
|
|
|
|
// RouteNextHopTypes Types corresponding to routeNextHop
|
|
var RouteNextHopTypes = map[string]attr.Type{
|
|
"type": types.StringType,
|
|
"value": types.StringType,
|
|
}
|
|
|
|
func MapRouteModel(ctx context.Context, route *iaasalpha.Route, model *RouteModel, region string) error {
|
|
if route == nil {
|
|
return fmt.Errorf("response input is nil")
|
|
}
|
|
if model == nil {
|
|
return fmt.Errorf("model input is nil")
|
|
}
|
|
|
|
err := MapRouteReadModel(ctx, route, &model.RouteReadModel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
idParts := []string{
|
|
model.OrganizationId.ValueString(),
|
|
region,
|
|
model.NetworkAreaId.ValueString(),
|
|
model.RoutingTableId.ValueString(),
|
|
model.RouteId.ValueString(),
|
|
}
|
|
model.Id = types.StringValue(
|
|
strings.Join(idParts, core.Separator),
|
|
)
|
|
model.Region = types.StringValue(region)
|
|
|
|
return nil
|
|
}
|
|
|
|
func MapRouteReadModel(ctx context.Context, route *iaasalpha.Route, model *RouteReadModel) error {
|
|
if route == nil {
|
|
return fmt.Errorf("response input is nil")
|
|
}
|
|
if model == nil {
|
|
return fmt.Errorf("model input is nil")
|
|
}
|
|
|
|
var routeId string
|
|
if model.RouteId.ValueString() != "" {
|
|
routeId = model.RouteId.ValueString()
|
|
} else if route.Id != nil {
|
|
routeId = *route.Id
|
|
} else {
|
|
return fmt.Errorf("routing table route id not present")
|
|
}
|
|
|
|
labels, err := iaasUtils.MapLabels(ctx, route.Labels, model.Labels)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// created at and updated at
|
|
createdAtTF, updatedAtTF := types.StringNull(), types.StringNull()
|
|
if route.CreatedAt != nil {
|
|
createdAtValue := *route.CreatedAt
|
|
createdAtTF = types.StringValue(createdAtValue.Format(time.RFC3339))
|
|
}
|
|
if route.UpdatedAt != nil {
|
|
updatedAtValue := *route.UpdatedAt
|
|
updatedAtTF = types.StringValue(updatedAtValue.Format(time.RFC3339))
|
|
}
|
|
|
|
// destination
|
|
model.Destination, err = MapRouteDestination(route)
|
|
if err != nil {
|
|
return fmt.Errorf("error mapping route destination: %w", err)
|
|
}
|
|
|
|
// next hop
|
|
model.NextHop, err = MapRouteNextHop(route)
|
|
if err != nil {
|
|
return fmt.Errorf("error mapping route next hop: %w", err)
|
|
}
|
|
|
|
model.RouteId = types.StringValue(routeId)
|
|
model.CreatedAt = createdAtTF
|
|
model.UpdatedAt = updatedAtTF
|
|
model.Labels = labels
|
|
return nil
|
|
}
|
|
|
|
func MapRouteNextHop(routeResp *iaasalpha.Route) (types.Object, error) {
|
|
if routeResp.Nexthop == nil {
|
|
return types.ObjectNull(RouteNextHopTypes), nil
|
|
}
|
|
|
|
nextHopMap := map[string]attr.Value{}
|
|
switch i := routeResp.Nexthop.GetActualInstance().(type) {
|
|
case *iaasalpha.NexthopIPv4:
|
|
nextHopMap["type"] = types.StringValue(*i.Type)
|
|
nextHopMap["value"] = types.StringPointerValue(i.Value)
|
|
case *iaasalpha.NexthopIPv6:
|
|
nextHopMap["type"] = types.StringValue(*i.Type)
|
|
nextHopMap["value"] = types.StringPointerValue(i.Value)
|
|
case *iaasalpha.NexthopBlackhole:
|
|
nextHopMap["type"] = types.StringValue(*i.Type)
|
|
nextHopMap["value"] = types.StringNull()
|
|
case *iaasalpha.NexthopInternet:
|
|
nextHopMap["type"] = types.StringValue(*i.Type)
|
|
nextHopMap["value"] = types.StringNull()
|
|
default:
|
|
return types.ObjectNull(RouteNextHopTypes), fmt.Errorf("unexpected Nexthop type: %T", i)
|
|
}
|
|
|
|
nextHopTF, diags := types.ObjectValue(RouteNextHopTypes, nextHopMap)
|
|
if diags.HasError() {
|
|
return types.ObjectNull(RouteNextHopTypes), core.DiagsToError(diags)
|
|
}
|
|
|
|
return nextHopTF, nil
|
|
}
|
|
|
|
func MapRouteDestination(routeResp *iaasalpha.Route) (types.Object, error) {
|
|
if routeResp.Destination == nil {
|
|
return types.ObjectNull(RouteDestinationTypes), nil
|
|
}
|
|
|
|
destinationMap := map[string]attr.Value{}
|
|
switch i := routeResp.Destination.GetActualInstance().(type) {
|
|
case *iaasalpha.DestinationCIDRv4:
|
|
destinationMap["type"] = types.StringValue(*i.Type)
|
|
destinationMap["value"] = types.StringPointerValue(i.Value)
|
|
case *iaasalpha.DestinationCIDRv6:
|
|
destinationMap["type"] = types.StringValue(*i.Type)
|
|
destinationMap["value"] = types.StringPointerValue(i.Value)
|
|
default:
|
|
return types.ObjectNull(RouteDestinationTypes), fmt.Errorf("unexpected Destionation type: %T", i)
|
|
}
|
|
|
|
destinationTF, diags := types.ObjectValue(RouteDestinationTypes, destinationMap)
|
|
if diags.HasError() {
|
|
return types.ObjectNull(RouteDestinationTypes), core.DiagsToError(diags)
|
|
}
|
|
|
|
return destinationTF, nil
|
|
}
|