|
|
|
package utilities
|
|
|
|
|
|
|
|
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"
|
|
|
|
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/vfpool"
|
|
|
|
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/client"
|
|
|
|
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudbroker/ic"
|
|
|
|
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudbroker/vfpool/models"
|
|
|
|
)
|
|
|
|
|
|
|
|
func ResourceVFPoolCheckPresence(ctx context.Context, vfPoolID uint64, c *client.Client) (*vfpool.RecordVFPool,
|
|
|
|
error) {
|
|
|
|
req := vfpool.GetRequest{VFPoolID: vfPoolID}
|
|
|
|
|
|
|
|
tflog.Info(ctx, "ResourceVFPoolCheckPresence: before call CloudBroker().VFPool().Get", map[string]any{"req": req})
|
|
|
|
vfPool, err := c.CloudBroker().VFPool().Get(ctx, req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("VFPoolCheckPresence: cannot get info about vfpool")
|
|
|
|
}
|
|
|
|
|
|
|
|
tflog.Info(ctx, "ResourceVFPoolCheckPresence: response from CloudBroker().VFPool().Get", map[string]any{"response": vfPool})
|
|
|
|
|
|
|
|
return vfPool, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func VFpoolResourceCreate(ctx context.Context, plan *models.ResourceItemVFPoolModel, c *client.Client) (*uint64, diag.Diagnostics) {
|
|
|
|
tflog.Info(ctx, "Start VFpoolResourceCreate", map[string]any{"name": plan.Name.ValueString()})
|
|
|
|
|
|
|
|
diags := diag.Diagnostics{}
|
|
|
|
|
|
|
|
req := vfpool.CreateRequest{
|
|
|
|
Name: plan.Name.ValueString(),
|
|
|
|
}
|
|
|
|
|
|
|
|
if !plan.Description.IsNull() {
|
|
|
|
req.Description = plan.Description.ValueString()
|
|
|
|
}
|
|
|
|
|
|
|
|
if !plan.AccountAccess.IsNull() {
|
|
|
|
|
|
|
|
accountAccessList := make([]uint64, len(plan.AccountAccess.Elements()))
|
|
|
|
|
|
|
|
diags.Append(plan.AccountAccess.ElementsAs(ctx, &accountAccessList, true)...)
|
|
|
|
if diags.HasError() {
|
|
|
|
tflog.Error(ctx, "VFpoolResourceCreate: cannot populate VFpoolResourceCreate with plan.AccountAccess object element")
|
|
|
|
return nil, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
req.AccountAccess = accountAccessList
|
|
|
|
}
|
|
|
|
|
|
|
|
if !plan.RGAccess.IsNull() {
|
|
|
|
|
|
|
|
RGAccessList := make([]uint64, len(plan.RGAccess.Elements()))
|
|
|
|
|
|
|
|
diags.Append(plan.RGAccess.ElementsAs(ctx, &RGAccessList, true)...)
|
|
|
|
if diags.HasError() {
|
|
|
|
tflog.Error(ctx, "VFpoolResourceCreate: cannot populate VFpoolResourceCreate with plan.RGAccess object element")
|
|
|
|
return nil, diags
|
|
|
|
}
|
|
|
|
req.RGAccess = RGAccessList
|
|
|
|
}
|
|
|
|
|
|
|
|
diags.Append(checkParamsExistence(ctx, req.AccountAccess, req.RGAccess, c)...)
|
|
|
|
if diags.HasError() {
|
|
|
|
tflog.Error(ctx, "VFpoolResourceCreate: RGAccess or AccountAccess does not exist")
|
|
|
|
return nil, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
if !plan.Config.IsNull() {
|
|
|
|
configList := make([]models.ResourceItemVFPoolConfigModel, 0, len(plan.Config.Elements()))
|
|
|
|
diags.Append(plan.Config.ElementsAs(ctx, &configList, true)...)
|
|
|
|
if diags.HasError() {
|
|
|
|
tflog.Error(ctx, "VFpoolResourceCreate: cannot populate VFpoolResourceCreate with v.Config object element")
|
|
|
|
return nil, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
config := make([]vfpool.Config, 0, len(configList))
|
|
|
|
|
|
|
|
for _, v := range configList {
|
|
|
|
vfIDs := make([]uint64, 0, len(v.VFIDs.Elements()))
|
|
|
|
diags.Append(v.VFIDs.ElementsAs(ctx, &vfIDs, true)...)
|
|
|
|
if diags.HasError() {
|
|
|
|
tflog.Error(ctx, "VFpoolResourceCreate: cannot populate UpdateVFpool with vfIDs object element")
|
|
|
|
return nil, diags
|
|
|
|
}
|
|
|
|
item := vfpool.Config{
|
|
|
|
NodeID: uint64(v.NodeID.ValueInt64()),
|
|
|
|
NicName: v.NicName.ValueString(),
|
|
|
|
VFIDs: vfIDs}
|
|
|
|
|
|
|
|
config = append(config, item)
|
|
|
|
}
|
|
|
|
req.Config = config
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
vfPoolID, err := c.CloudBroker().VFPool().Create(ctx, req)
|
|
|
|
if err != nil {
|
|
|
|
tflog.Error(ctx, "Error response for create VFpool", map[string]any{"error": err.Error()})
|
|
|
|
diags.AddError("Unable to Create VFpool", err.Error())
|
|
|
|
return nil, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
plan.ID = types.StringValue(strconv.Itoa(int(vfPoolID)))
|
|
|
|
|
|
|
|
if !plan.Enable.IsNull() {
|
|
|
|
EnableDisableVFpool(ctx, plan, c)
|
|
|
|
}
|
|
|
|
|
|
|
|
tflog.Info(ctx, "End VFpoolResourceCreate", map[string]any{"vfpool_id": vfPoolID})
|
|
|
|
return &vfPoolID, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
// EnableDisableVFpool performs VFpool Enable/Disable request.
|
|
|
|
// Returns error in case of failures.
|
|
|
|
func EnableDisableVFpool(ctx context.Context, plan *models.ResourceItemVFPoolModel, c *client.Client) diag.Diagnostics {
|
|
|
|
tflog.Info(ctx, "Start EnableDisableVFpool", map[string]any{"vfpool_id": plan.ID.ValueString()})
|
|
|
|
|
|
|
|
diags := diag.Diagnostics{}
|
|
|
|
|
|
|
|
ID, err := strconv.Atoi(plan.ID.ValueString())
|
|
|
|
if err != nil {
|
|
|
|
diags.AddError("EnableDisableVFpool: Cannot parse ID from state", err.Error())
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
|
|
|
|
if plan.Enable.ValueBool() {
|
|
|
|
tflog.Info(ctx, "EnableDisableVFpool: before calling CloudBroker().VFPool().Enable", map[string]any{"vfpool_id": ID})
|
|
|
|
res, err := c.CloudBroker().VFPool().Enable(ctx, vfpool.EnableRequest{VFPoolID: uint64(ID)})
|
|
|
|
if err != nil {
|
|
|
|
diags.AddError(
|
|
|
|
"EnableDisableVFpool: cannot enable VFpool",
|
|
|
|
err.Error(),
|
|
|
|
)
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
tflog.Info(ctx, "EnableDisableVFpool: response from CloudBroker().VFPool().Enable", map[string]any{"vfpool_id": ID, "response": res})
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
tflog.Info(ctx, "EnableDisableVFpool: before calling CloudBroker().VFPool().Disable", map[string]any{"vfpool_id": ID})
|
|
|
|
res, err := c.CloudBroker().VFPool().Disable(ctx, vfpool.DisableRequest{VFPoolID: uint64(ID)})
|
|
|
|
if err != nil {
|
|
|
|
diags.AddError(
|
|
|
|
"EnableDisableVFpool: cannot disable VFPool",
|
|
|
|
err.Error(),
|
|
|
|
)
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
tflog.Info(ctx, "EnableDisableVFpool: response from CloudBroker().VFPool().Disable", map[string]any{"vfpool_id": ID, "response": res})
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func UpdateVFpool(ctx context.Context, state *models.ResourceItemVFPoolModel, plan *models.ResourceItemVFPoolModel, c *client.Client) diag.Diagnostics {
|
|
|
|
tflog.Info(ctx, "Start UpdateVFpool", map[string]any{"vfpool_id": plan.ID.ValueString()})
|
|
|
|
|
|
|
|
diags := diag.Diagnostics{}
|
|
|
|
|
|
|
|
ID, err := strconv.Atoi(plan.ID.ValueString())
|
|
|
|
if err != nil {
|
|
|
|
diags.AddError("UpdateVFpool: Cannot parse ID from state", err.Error())
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
|
|
|
|
req := vfpool.UpdateRequest{
|
|
|
|
VFPoolID: uint64(ID),
|
|
|
|
}
|
|
|
|
|
|
|
|
if !plan.Name.Equal(state.Name) {
|
|
|
|
req.Name = plan.Name.ValueString()
|
|
|
|
}
|
|
|
|
|
|
|
|
if !plan.Description.Equal(state.Description) {
|
|
|
|
req.Description = plan.Description.ValueString()
|
|
|
|
}
|
|
|
|
|
|
|
|
if !plan.Config.Equal(state.Config) && !plan.Config.IsNull() {
|
|
|
|
configList := make([]models.ResourceItemVFPoolConfigModel, 0, len(plan.Config.Elements()))
|
|
|
|
diags.Append(plan.Config.ElementsAs(ctx, &configList, true)...)
|
|
|
|
if diags.HasError() {
|
|
|
|
tflog.Error(ctx, "UpdateVFpool: cannot populate UpdateVFpool with plan.Config object element")
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
|
|
|
|
config := make([]vfpool.Config, 0, len(configList))
|
|
|
|
|
|
|
|
for _, v := range configList {
|
|
|
|
vfIDs := make([]uint64, 0, len(v.VFIDs.Elements()))
|
|
|
|
diags.Append(v.VFIDs.ElementsAs(ctx, &vfIDs, true)...)
|
|
|
|
if diags.HasError() {
|
|
|
|
tflog.Error(ctx, "UpdateVFpool: cannot populate UpdateVFpool with vfIDs object element")
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
item := vfpool.Config{
|
|
|
|
NodeID: uint64(v.NodeID.ValueInt64()),
|
|
|
|
NicName: v.NicName.ValueString(),
|
|
|
|
VFIDs: vfIDs}
|
|
|
|
|
|
|
|
config = append(config, item)
|
|
|
|
}
|
|
|
|
req.Config = config
|
|
|
|
}
|
|
|
|
|
|
|
|
if !plan.AccountAccess.Equal(state.AccountAccess) && !plan.AccountAccess.IsNull() {
|
|
|
|
aaList := make([]uint64, 0, len(plan.AccountAccess.Elements()))
|
|
|
|
diags.Append(plan.AccountAccess.ElementsAs(ctx, &aaList, true)...)
|
|
|
|
if diags.HasError() {
|
|
|
|
tflog.Error(ctx, "UpdateVFpool: cannot populate UpdateVFpool with plan.AccountAccess object element")
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
|
|
|
|
req.AccountAccess = aaList
|
|
|
|
}
|
|
|
|
|
|
|
|
if !plan.RGAccess.Equal(state.RGAccess) && !plan.RGAccess.IsNull() {
|
|
|
|
rgAccessList := make([]uint64, 0, len(plan.RGAccess.Elements()))
|
|
|
|
diags.Append(plan.RGAccess.ElementsAs(ctx, &rgAccessList, true)...)
|
|
|
|
if diags.HasError() {
|
|
|
|
tflog.Error(ctx, "UpdateVFpool: cannot populate UpdateVFpool with plan.RGAccess object element")
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
|
|
|
|
req.RGAccess = rgAccessList
|
|
|
|
}
|
|
|
|
|
|
|
|
if state.Status.ValueString() == "ENABLED" || state.Status.ValueString() == "CREATED" {
|
|
|
|
reqDisable := vfpool.DisableRequest{
|
|
|
|
VFPoolID: uint64(ID),
|
|
|
|
}
|
|
|
|
tflog.Info(ctx, fmt.Sprintf("UpdateVFpool: need to disable vfPool with ID: %d, after update", ID))
|
|
|
|
_, err = c.CloudBroker().VFPool().Disable(ctx, reqDisable)
|
|
|
|
if err != nil {
|
|
|
|
diags.AddWarning(
|
|
|
|
"UpdateVFpool: cannot disable VFPool",
|
|
|
|
err.Error(),
|
|
|
|
)
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
tflog.Info(ctx, "utilityVFPoolUpdate: disable VFPool with complete")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = c.CloudBroker().VFPool().Update(ctx, req)
|
|
|
|
if err != nil {
|
|
|
|
diags.AddError("EnableDisableVFpool: Cannot update", err.Error())
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
tflog.Info(ctx, fmt.Sprintf("utilityVFPoolUpdate: update vfPool with ID: %d, complete with params=%v", ID, req))
|
|
|
|
|
|
|
|
if plan.Enable.ValueBool() {
|
|
|
|
reqEnable := vfpool.EnableRequest{
|
|
|
|
VFPoolID: uint64(ID),
|
|
|
|
}
|
|
|
|
tflog.Info(ctx, fmt.Sprintf("utilityVFPoolUpdate: start to enable vfPool with ID: %d, after update", ID))
|
|
|
|
_, err = c.CloudBroker().VFPool().Enable(ctx, reqEnable)
|
|
|
|
if err != nil {
|
|
|
|
diags.AddWarning(
|
|
|
|
"UpdateVFpool: cannot enable VFPool",
|
|
|
|
err.Error(),
|
|
|
|
)
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
tflog.Info(ctx, fmt.Sprintf("utilityVFPoolUpdate: enable vfPool with ID: %d, complete", ID))
|
|
|
|
} else {
|
|
|
|
diags.AddWarning(
|
|
|
|
"UpdateVFpool: vfPool is not enabled",
|
|
|
|
"the vfPool is not enabled after update, you must provide configuration for this resource, after enabling it",
|
|
|
|
)
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkParamsExistence(ctx context.Context, accountIDs, rgIDs []uint64, c *client.Client) diag.Diagnostics {
|
|
|
|
diags := diag.Diagnostics{}
|
|
|
|
|
|
|
|
if err := ic.ExistAccounts(ctx, accountIDs, c); err != nil {
|
|
|
|
diags.AddError("Error check input values", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ic.ExistRGs(ctx, rgIDs, c); err != nil {
|
|
|
|
diags.AddError("Error check input values", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
return diags
|
|
|
|
}
|