package utilities import ( "context" "fmt" "strconv" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-log/tflog" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/flipgroup" "repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/client" "repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/flipgroup/models" "repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/status" ) func CreateResourceFlipgroup(ctx context.Context, plan *models.ResourceFLIPGroupModel, c *client.Client) (uint64, diag.Diagnostics) { tflog.Info(ctx, fmt.Sprintf("Start create ResourceFlipgroup: flipgroup_name %s", plan.Name.ValueString())) diags := diag.Diagnostics{} createReq := flipgroup.CreateRequest{ AccountID: uint64(plan.AccountID.ValueInt64()), Name: plan.Name.ValueString(), NetType: plan.NetType.ValueString(), NetID: uint64(plan.NetID.ValueInt64()), ClientType: plan.ClientType.ValueString(), } if !plan.IP.IsUnknown() { // IP is optional & computed createReq.IP = plan.IP.ValueString() } if !plan.Description.IsNull() { // Description is optional createReq.Description = plan.Description.ValueString() } tflog.Info(ctx, "CreateResourceFlipgroup: before call CloudAPI().FLIPGroup().Create", map[string]any{"req": createReq}) resp, err := c.CloudAPI().FLIPGroup().Create(ctx, createReq) if err != nil { diags.AddError("CreateResourceFlipgroup: unable to create flipgroup", err.Error()) return 0, diags } tflog.Info(ctx, "CreateResourceFlipgroup: flipgroup created", map[string]any{"flipgroup_id": resp.ID, "name": plan.Name.ValueString()}) return resp.ID, nil } // AddClientsFlipgroup add computes in flipgroup for created resource. // In case of failure returns warnings. func AddClientsFlipgroup(ctx context.Context, flipgroupID uint64, plan *models.ResourceFLIPGroupModel, c *client.Client) diag.Diagnostics { diags := diag.Diagnostics{} tflog.Info(ctx, "AddClientsFlipgroup: start add clients", map[string]any{"flipgroup_id": flipgroupID}) clientIDs := make([]int, 0, len(plan.ClientIDs.Elements())) diagsItem := plan.ClientIDs.ElementsAs(ctx, &clientIDs, true) if diagsItem.HasError() { tflog.Error(ctx, fmt.Sprintf("AddClientsFlipgroup: cannot populate clientIDs with plan.ClientIDs list elements: %v", diagsItem)) diags.AddWarning("AddClientsFlipgroup: Unable to read clientIDs for flipgroup", fmt.Sprintf("%v", diagsItem)) return diags } for _, computeID := range clientIDs { addClientsReq := flipgroup.ComputeAddRequest{ FLIPGroupID: flipgroupID, ComputeID: uint64(computeID), } res, err := c.CloudAPI().FLIPGroup().ComputeAdd(ctx, addClientsReq) if err != nil { diags.AddWarning("AddClientsFlipgroup: Unable to add compute for flipgroup", err.Error()) } tflog.Info(ctx, "AddClientsFlipgroup: response from CloudAPI().FLIPGroup().ComputeAdd", map[string]any{ "flipgroup_id": flipgroupID, "response": res}) } return diags } // FlipgroupReadStatus loads flipgroup resource by id, gets it current status // In case of failure returns errors. func FlipgroupReadStatus(ctx context.Context, state *models.ResourceFLIPGroupModel, c *client.Client) diag.Diagnostics { tflog.Info(ctx, "FlipgroupReadStatus: Read status flipgroup with ID", map[string]any{"flipgroup_id": state.ID.ValueString()}) diags := diag.Diagnostics{} flipgroupId, err := strconv.ParseUint(state.ID.ValueString(), 10, 64) if err != nil { diags.AddError("FlipgroupReadStatus: Cannot parse flipgroup ID from state", err.Error()) return diags } recordFG, diags := FlipgroupResourceCheckPresence(ctx, flipgroupId, c) if err != nil { diags.AddError("FlipgroupReadStatus: Unable to Read/Update flipgroup before status check", err.Error()) return diags } //check resource status switch recordFG.Status { case status.Modeled: diags.AddError( "FlipgroupReadStatus: flipgroup is in status Modeled", "please, contact support for more information", ) return diags case status.Destroyed: diags.AddError( "FlipgroupReadStatus: flipgroup is in status Destroyed", fmt.Sprintf("the resource with flipgroup_id %d cannot be read or updated because it has been destroyed", flipgroupId), ) return diags } return nil } func FlipgroupResourceCheckPresence(ctx context.Context, flipgroupId uint64, c *client.Client) (*flipgroup.RecordFLIPGroup, diag.Diagnostics) { tflog.Info(ctx, fmt.Sprintf("FlipgroupResourceCheckPresence: Get info about flipgroup with ID - %v", flipgroupId)) diags := diag.Diagnostics{} recordFG, err := c.CloudAPI().FLIPGroup().Get(ctx, flipgroup.GetRequest{FLIPGroupID: flipgroupId}) if err != nil { diags.AddError(fmt.Sprintf("Cannot get info about flipgroup with ID %v", flipgroupId), err.Error()) return nil, diags } tflog.Info(ctx, "FlipgroupResourceCheckPresence: response from CloudAPI().FLIPGroup().Get", map[string]any{"flipgroup_id": flipgroupId, "response": recordFG}) return recordFG, nil } func EditFlipgroup(ctx context.Context, flipgroupId uint64, plan, state *models.ResourceFLIPGroupModel, c *client.Client) diag.Diagnostics { tflog.Info(ctx, fmt.Sprintf("EditFlipgroup: Start edit flipgroup with ID - %v", flipgroupId)) diags := diag.Diagnostics{} editReq := flipgroup.EditRequest{ FLIPGroupID: flipgroupId, } if !plan.Name.Equal(state.Name) { editReq.Name = plan.Name.ValueString() } if !plan.Description.IsNull() && !plan.Description.Equal(state.Description) { editReq.Description = plan.Description.ValueString() } _, err := c.CloudAPI().FLIPGroup().Edit(ctx, editReq) if err != nil { diags.AddError("EditFlipgroup: cannot edit flipgroup", err.Error()) return diags } tflog.Info(ctx, fmt.Sprintf("EditFlipgroup: Finish edit flipgroup with ID - %v", flipgroupId)) return nil } func UpdateClientIDsFlipgroup(ctx context.Context, flipgroupId uint64, plan, state *models.ResourceFLIPGroupModel, c *client.Client) diag.Diagnostics { tflog.Info(ctx, fmt.Sprintf("UpdateClientIDsFlipgroup: Start update flipgroup with ID - %v", flipgroupId)) diags := diag.Diagnostics{} clientIDsPlan := make([]int, 0, len(plan.ClientIDs.Elements())) diags.Append(plan.ClientIDs.ElementsAs(ctx, &clientIDsPlan, true)...) if diags.HasError() { tflog.Error(ctx, fmt.Sprintf("UpdateClientIDsFlipgroup: cannot populate clientIDs with plan.ClientIDs list elements")) return diags } clientIDsState := make([]int, 0, len(state.ClientIDs.Elements())) diags.Append(state.ClientIDs.ElementsAs(ctx, &clientIDsState, true)...) if diags.HasError() { tflog.Error(ctx, fmt.Sprintf("UpdateClientIDsFlipgroup: cannot populate clientIDs with state.ClientIDs list elements")) return diags } deleteIDs := difference(clientIDsState, clientIDsPlan) addIDs := difference(clientIDsPlan, clientIDsState) for _, id := range deleteIDs { tflog.Info(ctx, fmt.Sprintf("UpdateClientIDsFlipgroup: Start remove client with ID - %v", id)) req := flipgroup.ComputeRemoveRequest{ FLIPGroupID: flipgroupId, ComputeID: id, } res, err := c.CloudAPI().FLIPGroup().ComputeRemove(ctx, req) tflog.Info(ctx, "UpdateClientIDsFlipgroup: response from CloudAPI().FLIPGroup().ComputeRemove", map[string]any{"flipgroup_id": plan.ID.ValueString(), "response": res}) if err != nil { diags.AddError("UpdateClientIDsFlipgroup: can not remove client for flipgroup", err.Error()) } } for _, id := range addIDs { tflog.Info(ctx, fmt.Sprintf("UpdateClientIDsFlipgroup: Start add client with ID - %v", id)) req := flipgroup.ComputeAddRequest{ FLIPGroupID: flipgroupId, ComputeID: id, } res, err := c.CloudAPI().FLIPGroup().ComputeAdd(ctx, req) tflog.Info(ctx, "UpdateClientIDsFlipgroup: response from CloudAPI().FLIPGroup().ComputeAdd", map[string]any{"flipgroup_id": plan.ID.ValueString(), "response": res}) if err != nil { diags.AddError("UpdateClientIDsFlipgroup: can not add client for flipgroup", err.Error()) } } tflog.Info(ctx, fmt.Sprintf("UpdateClientIDsFlipgroup: Finish update flipgroup with ID - %v", flipgroupId)) return diags } func difference(set, check []int) []uint64 { mapCheck := make(map[int]struct{}) for _, id := range check { mapCheck[id] = struct{}{} } var diff []uint64 for _, id := range set { if _, ok := mapCheck[id]; !ok { diff = append(diff, uint64(id)) } } return diff }