package flattens import ( "context" "fmt" "strconv" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" decort "repository.basistech.ru/BASIS/decort-golang-sdk" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/vins" "repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/vins/models" "repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/vins/utilities" ) // VINSResource flattens resource for vins. // Return error in case resource is not found on the platform. // Flatten errors are added to tflog. func VINSResource(ctx context.Context, plan *models.ResourceVINSModel, c *decort.DecortClient) diag.Diagnostics { tflog.Info(ctx, "Start flattens.VINSResource") diags := diag.Diagnostics{} vinsId, err := strconv.ParseUint(plan.Id.ValueString(), 10, 64) if err != nil { diags.AddError("Cannot parse vins ID from state", err.Error()) return diags } recordVins, diags := utilities.VINSResourceCheckPresence(ctx, vinsId, c) if diags.HasError() { return diags } tflog.Info(ctx, "flattens.VINSResource: before flatten", map[string]any{"vins_id": vinsId}) *plan = models.ResourceVINSModel{ Name: types.StringValue(recordVins.Name), RGID: plan.RGID, AccountID: plan.AccountID, IPCIDR: plan.IPCIDR, PreReservationsNum: plan.PreReservationsNum, Description: plan.Description, GID: plan.GID, DNS: plan.DNS, Enable: plan.Enable, Permanently: plan.Permanently, Force: plan.Force, Restore: plan.Restore, VnfdevRestart: plan.VnfdevRestart, VnfdevRedeploy: plan.VnfdevRedeploy, ExtNet: plan.ExtNet, IP: plan.IP, NatRule: plan.NatRule, Timeouts: plan.Timeouts, VinsID: types.Int64Value(int64(vinsId)), Id: types.StringValue(strconv.Itoa(int(recordVins.ID))), LastUpdated: plan.LastUpdated, VNFDev: flattenVNFDev(ctx, &recordVins.VNFDev), AccountName: types.StringValue(recordVins.AccountName), Computes: flattenComputes(ctx, &recordVins.Computes), CreatedBy: types.StringValue(recordVins.CreatedBy), CreatedTime: types.Int64Value(int64(recordVins.CreatedTime)), DefaultGW: types.StringValue(recordVins.DefaultGW), DefaultQOS: flattenQOS(ctx, &recordVins.DefaultQOS), DeletedBy: types.StringValue(recordVins.DeletedBy), DeletedTime: types.Int64Value(int64(recordVins.DeletedTime)), GUID: types.Int64Value(int64(recordVins.GUID)), LockStatus: types.StringValue(recordVins.LockStatus), ManagerID: types.Int64Value(int64(recordVins.ManagerID)), ManagerType: types.StringValue(recordVins.ManagerType), Milestones: types.Int64Value(int64(recordVins.Milestones)), NetMask: types.Int64Value(int64(recordVins.NetMask)), Network: types.StringValue(recordVins.Network), Redundant: types.BoolValue(recordVins.Redundant), RGName: types.StringValue(recordVins.RGName), SecVNFDevID: types.Int64Value(int64(recordVins.SecVNFDevID)), Status: types.StringValue(recordVins.Status), UpdatedBy: types.StringValue(recordVins.UpdatedBy), UpdatedTime: types.Int64Value(int64(recordVins.UpdatedTime)), UserManaged: types.BoolValue(recordVins.UserManaged), VNFs: flattenVNFs(ctx, &recordVins.VNFs), VXLANID: types.Int64Value(int64(recordVins.VXLANID)), } if plan.RGID.IsUnknown() { plan.RGID = types.Int64Value(int64(recordVins.RGID)) } if plan.AccountID.IsUnknown() { plan.AccountID = types.Int64Value(int64(recordVins.AccountID)) } if plan.GID.IsUnknown() { plan.GID = types.Int64Value(int64(recordVins.GID)) } if plan.PreReservationsNum.IsUnknown() { plan.PreReservationsNum = types.Int64Value(int64(recordVins.PreReservaionsNum)) } if plan.Description.IsUnknown() { plan.Description = types.StringValue(recordVins.Description) } if plan.DNS.IsNull() { plan.DNS = types.SetNull(types.StringType) } if !plan.NatRule.IsNull() { plan.NatRule = flattenNatRule(ctx, plan, &recordVins.VNFs.NAT.Config.Rules) } tflog.Info(ctx, "flattens.VINSResource: after flatten", map[string]any{"vins_id": plan.Id.ValueString()}) tflog.Info(ctx, "End flattens.VINSResource", map[string]any{"vins_id": plan.Id.ValueString()}) return nil } // flattenNatRule flattens nat rule parameters: // - rule_id (computed), // - int_port, ext_port_end, proto (optional & computed). // Flatten errors are added to tflog. func flattenNatRule(ctx context.Context, plan *models.ResourceVINSModel, rules *vins.ListNATRulesConfig) types.List { tflog.Info(ctx, "Start flattenRuleIdInNatRule") diags := diag.Diagnostics{} itemsNatRulePlan := make([]models.NatRuleResourceModel, 0, len(plan.NatRule.Elements())) diags.Append(plan.NatRule.ElementsAs(ctx, &itemsNatRulePlan, false)...) if diags.HasError() { tflog.Error(ctx, "flattenRuleIdInNatRule: cannot populate itemsNatRulePlan with plan.NatRule list elements") } for i, natRule := range itemsNatRulePlan { ruleFromPlatform := natRule.GetNatRule(*rules) if ruleFromPlatform == nil { tflog.Error(ctx, fmt.Sprintf("flattenRuleIdInNatRule: rule_id can not be flatten for natRule %v because such nat_rule does not exist", natRule)) continue } itemsNatRulePlan[i].RuleID = types.Int64Value(int64(ruleFromPlatform.ID)) if itemsNatRulePlan[i].IntPort.ValueInt64() == 0 { itemsNatRulePlan[i].IntPort = types.Int64Value(int64(ruleFromPlatform.LocalPort)) } if itemsNatRulePlan[i].ExtPortEnd.ValueInt64() == 0 { itemsNatRulePlan[i].ExtPortEnd = types.Int64Value(int64(ruleFromPlatform.PublicPortEnd)) } if itemsNatRulePlan[i].Proto.ValueString() == "" { itemsNatRulePlan[i].Proto = types.StringValue(ruleFromPlatform.Protocol) } } res, err := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: models.ItemNatRuleResource}, itemsNatRulePlan) if err != nil { tflog.Error(ctx, fmt.Sprint("Error flattenRuleIdInNatRule", err)) } tflog.Info(ctx, "End flattenRuleIdInNatRule") return res }