This commit is contained in:
asteam
2024-07-25 14:33:38 +03:00
commit 6f40af6a5f
946 changed files with 98335 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
package utilities
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
)
func DataSourceDiskCheckPresence(ctx context.Context, diskId uint64, c *decort.DecortClient) (*disks.RecordDisk, error) {
tflog.Info(ctx, fmt.Sprintf("DataSourceDiskCheckPresence: Get info about disk with ID - %v", diskId))
recordDisk, err := c.CloudAPI().Disks().Get(ctx, disks.GetRequest{DiskID: diskId})
if err != nil {
return nil, fmt.Errorf("cannot get info about disk with error: %w", err)
}
tflog.Info(ctx, "DataSourceDiskCheckPresence: response from CloudAPI().Disks().Get", map[string]any{
"disk_id": diskId,
"response": recordDisk})
return recordDisk, err
}

View File

@@ -0,0 +1,72 @@
package utilities
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/disks/models"
)
func DataSourceDiskListCheckPresence(ctx context.Context, state *models.DataSourceDiskListModel, c *decort.DecortClient) (*disks.ListDisks, diag.Diagnostics) {
diags := diag.Diagnostics{}
listReq := disks.ListRequest{}
if !state.ByID.IsNull() {
listReq.ByID = uint64(state.ByID.ValueInt64())
}
if !state.Name.IsNull() {
listReq.Name = state.Name.ValueString()
}
if !state.AccountName.IsNull() {
listReq.AccountName = state.AccountName.ValueString()
}
if !state.DiskMaxSize.IsNull() {
listReq.DiskMaxSize = state.DiskMaxSize.ValueInt64()
}
if !state.Status.IsNull() {
listReq.Status = state.Status.ValueString()
}
if !state.Shared.IsNull() {
listReq.Shared = state.Shared.ValueBool()
}
if !state.AccountID.IsNull() {
listReq.AccountID = uint64(state.AccountID.ValueInt64())
}
if !state.Type.IsNull() {
listReq.Type = state.Type.ValueString()
}
if !state.SEPID.IsNull() {
listReq.SEPID = uint64(state.SEPID.ValueInt64())
}
if !state.PoolName.IsNull() {
listReq.Pool = state.PoolName.ValueString()
}
if !state.SortBy.IsNull() {
listReq.SortBy = state.SortBy.ValueString()
}
if !state.Page.IsNull() {
listReq.Page = uint64(state.Page.ValueInt64())
}
if !state.Size.IsNull() {
listReq.Size = uint64(state.Size.ValueInt64())
}
tflog.Info(ctx, "DataSourceDiskListCheckPresence: before call CloudAPI().Disks().List", map[string]any{
"req": listReq,
})
diskList, err := c.CloudAPI().Disks().List(ctx, listReq)
if err != nil {
diags.AddError("Cannot get info about disk list", err.Error())
return nil, diags
}
tflog.Info(ctx, "DataSourceDiskListCheckPresence: got list successfully", map[string]any{
"entry_count": diskList.EntryCount,
})
return diskList, nil
}

View File

@@ -0,0 +1,63 @@
package utilities
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/disks/models"
)
func DataSourceDiskListDeletedCheckPresence(ctx context.Context, state *models.DataSourceDiskListDeletedModel, c *decort.DecortClient) (*disks.ListDisks, diag.Diagnostics) {
diags := diag.Diagnostics{}
listReq := disks.ListDeletedRequest{}
if !state.ByID.IsNull() {
listReq.ByID = uint64(state.ByID.ValueInt64())
}
if !state.Name.IsNull() {
listReq.Name = state.Name.ValueString()
}
if !state.AccountName.IsNull() {
listReq.AccountName = state.AccountName.ValueString()
}
if !state.DiskMaxSize.IsNull() {
listReq.DiskMaxSize = state.DiskMaxSize.ValueInt64()
}
if !state.Shared.IsNull() {
listReq.Shared = state.Shared.ValueBool()
}
if !state.AccountID.IsNull() {
listReq.AccountID = uint64(state.AccountID.ValueInt64())
}
if !state.Type.IsNull() {
listReq.Type = state.Type.ValueString()
}
if !state.SortBy.IsNull() {
listReq.SortBy = state.SortBy.ValueString()
}
if !state.Page.IsNull() {
listReq.Page = uint64(state.Page.ValueInt64())
}
if !state.Size.IsNull() {
listReq.Size = uint64(state.Size.ValueInt64())
}
tflog.Info(ctx, "DataSourceDiskListDeletedCheckPresence: before call CloudAPI().Disks().ListDeleted", map[string]any{
"req": listReq,
})
diskList, err := c.CloudAPI().Disks().ListDeleted(ctx, listReq)
if err != nil {
diags.AddError("Cannot get info about disk list", err.Error())
return nil, diags
}
tflog.Info(ctx, "DataSourceDiskListDeletedCheckPresence: got list successfully", map[string]any{
"entry_count": diskList.EntryCount,
})
return diskList, nil
}

View File

@@ -0,0 +1,42 @@
package utilities
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/disks/models"
)
func DataSourceDiskListTypesCheckPresence(ctx context.Context, state *models.DataSourceDiskListTypesModel, c *decort.DecortClient) (*disks.ListTypes, diag.Diagnostics) {
diags := diag.Diagnostics{}
listTypesReq := disks.ListTypesRequest{Detailed: false}
if !state.SortBy.IsNull() {
listTypesReq.SortBy = state.SortBy.ValueString()
}
if !state.Page.IsNull() {
listTypesReq.Page = uint64(state.Page.ValueInt64())
}
if !state.Size.IsNull() {
listTypesReq.Size = uint64(state.Size.ValueInt64())
}
tflog.Info(ctx, "DataSourceDiskListTypesCheckPresence: before call CloudAPI().Disks().ListTypes", map[string]any{
"req": listTypesReq,
})
listTypes, err := c.CloudAPI().Disks().ListTypes(ctx, listTypesReq)
if err != nil {
diags.AddError("Cannot get info about disk list types", err.Error())
return nil, diags
}
tflog.Info(ctx, "DataSourceDiskListTypesCheckPresence: got list successfully", map[string]any{
"entry_count": listTypes.EntryCount,
})
return listTypes, nil
}

View File

@@ -0,0 +1,42 @@
package utilities
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/disks/models"
)
func DataSourceDiskListTypesDetailedCheckPresence(ctx context.Context, state *models.DataSourceDiskListTypesDetailedModel, c *decort.DecortClient) (*disks.ListTypes, diag.Diagnostics) {
diags := diag.Diagnostics{}
listTypesReq := disks.ListTypesRequest{Detailed: true}
if !state.SortBy.IsNull() {
listTypesReq.SortBy = state.SortBy.ValueString()
}
if !state.Page.IsNull() {
listTypesReq.Page = uint64(state.Page.ValueInt64())
}
if !state.Size.IsNull() {
listTypesReq.Size = uint64(state.Size.ValueInt64())
}
tflog.Info(ctx, "DataSourceDiskListTypesDetailedCheckPresence: before call CloudAPI().Disks().ListTypes", map[string]any{
"req": listTypesReq,
})
listTypes, err := c.CloudAPI().Disks().ListTypes(ctx, listTypesReq)
if err != nil {
diags.AddError("Cannot get info about disk list types", err.Error())
return nil, diags
}
tflog.Info(ctx, "DataSourceDiskListTypesDetailedCheckPresence: got list successfully", map[string]any{
"entry_count": listTypes.EntryCount,
})
return listTypes, nil
}

View File

@@ -0,0 +1,66 @@
package utilities
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/disks/models"
)
func DataSourceDiskListUnattachedCheckPresence(ctx context.Context, state *models.DataSourceDiskListUnattachedModel, c *decort.DecortClient) (*disks.ListDisksUnattached, diag.Diagnostics) {
diags := diag.Diagnostics{}
listReq := disks.ListUnattachedRequest{}
if !state.ByID.IsNull() {
listReq.ByID = uint64(state.ByID.ValueInt64())
}
if !state.AccountName.IsNull() {
listReq.AccountName = state.AccountName.ValueString()
}
if !state.DiskMaxSize.IsNull() {
listReq.DiskMaxSize = state.DiskMaxSize.ValueInt64()
}
if !state.Status.IsNull() {
listReq.Status = state.Status.ValueString()
}
if !state.AccountID.IsNull() {
listReq.AccountID = uint64(state.AccountID.ValueInt64())
}
if !state.SepID.IsNull() {
listReq.SEPID = uint64(state.SepID.ValueInt64())
}
if !state.PoolName.IsNull() {
listReq.Pool = state.PoolName.ValueString()
}
if !state.Type.IsNull() {
listReq.Type = state.Type.ValueString()
}
if !state.SortBy.IsNull() {
listReq.SortBy = state.SortBy.ValueString()
}
if !state.Page.IsNull() {
listReq.Page = uint64(state.Page.ValueInt64())
}
if !state.Size.IsNull() {
listReq.Size = uint64(state.Size.ValueInt64())
}
tflog.Info(ctx, "DataSourceDiskListUnattachedCheckPresence: before call CloudAPI().Disks().ListUnattached", map[string]any{
"req": listReq,
})
diskList, err := c.CloudAPI().Disks().ListUnattached(ctx, listReq)
if err != nil {
diags.AddError("Cannot get info about disk list", err.Error())
return nil, diags
}
tflog.Info(ctx, "DataSourceDiskListUnattachedCheckPresence: got list successfully", map[string]any{
"entry_count": diskList.EntryCount,
})
return diskList, nil
}

View File

@@ -0,0 +1,34 @@
package utilities
import (
"context"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/disks/models"
)
func DataSourceDiskReplicationCheckPresence(ctx context.Context, state *models.RecordDiskModel, c *decort.DecortClient) (*disks.RecordDisk, *string, error) {
status, err := c.CloudAPI().Disks().ReplicationStatus(ctx, disks.ReplicationStatusRequest{DiskID: uint64(state.DiskId.ValueInt64())})
if err != nil {
return nil, nil, err
}
req := disks.GetRequest{}
if !state.DiskId.IsNull() && !state.DiskId.IsUnknown() {
req.DiskID = uint64(state.DiskId.ValueInt64())
} else {
req.DiskID = uint64(state.ID.ValueInt64())
}
tflog.Info(ctx, "DataSourceDiskReplicationCheckPresence: load disk")
disk, err := c.CloudAPI().Disks().Get(ctx, req)
if err != nil {
return nil, nil, err
}
return disk, &status, nil
}

View File

@@ -0,0 +1,43 @@
package utilities
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/disks/models"
)
func DataSourceDiskSnapshotCheckPresence(ctx context.Context, plan *models.DataSourceDiskSnapshotModel, c *decort.DecortClient) (*disks.ItemSnapshot, diag.Diagnostics) {
diags := diag.Diagnostics{}
diskId := uint64(plan.DiskID.ValueInt64())
label := plan.Label.ValueString()
tflog.Info(ctx, "Start DataSourceDiskSnapshotCheckPresence", map[string]any{"disk_id": diskId, "label": label})
tflog.Info(ctx, "DataSourceDiskSnapshotCheckPresence: before call CloudAPI().Disks().Get", map[string]any{"disk_id": diskId})
disk, err := c.CloudAPI().Disks().Get(ctx, disks.GetRequest{DiskID: diskId})
if err != nil {
diags.AddError(
fmt.Sprintf("Cannot get info about disk with disk_id %d", diskId),
err.Error(),
)
return nil, diags
}
tflog.Info(ctx, "DataSourceDiskSnapshotCheckPresence: response from CloudAPI().Disks().Get", map[string]any{"response": disk})
for _, sn := range disk.Snapshots {
if label == sn.Label {
return &sn, nil
}
}
diags.AddError(
"Snapshot not found",
fmt.Sprintf("Snapshot with label %s for disk with disk_id %d not found", label, diskId),
)
return nil, diags
}

View File

@@ -0,0 +1,25 @@
package utilities
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
)
func DiskSnapshotListCheckPresence(ctx context.Context, diskId uint64, c *decort.DecortClient) (*disks.ListSnapshots, error) {
tflog.Info(ctx, fmt.Sprintf("DiskSnapshotListCheckPresence: Get info about disk snapshot list with disk ID - %v", diskId))
recordDisk, err := c.CloudAPI().Disks().Get(ctx, disks.GetRequest{DiskID: diskId})
if err != nil {
return nil, fmt.Errorf("cannot get info about disk with error: %w", err)
}
tflog.Info(ctx, "DiskSnapshotListCheckPresence: response from CloudAPI().Disks().Get", map[string]any{
"disk_id": diskId,
"response": recordDisk})
return &recordDisk.Snapshots, err
}

View File

@@ -0,0 +1,373 @@
package utilities
import (
"context"
"fmt"
"strconv"
"time"
"github.com/hashicorp/terraform-plugin-framework/types"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/status"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/disks/models"
)
// DiskCheckPresence checks if disk with diskId exists
func DiskCheckPresence(ctx context.Context, diskId uint64, c *decort.DecortClient) (*disks.RecordDisk, error) {
tflog.Info(ctx, fmt.Sprintf("Get info about disk with ID - %v", diskId))
diskRecord, err := c.CloudAPI().Disks().Get(ctx, disks.GetRequest{DiskID: diskId})
if err != nil {
return nil, fmt.Errorf("cannot get info about disk with error: %w", err)
}
tflog.Info(ctx, "DiskCheckPresence resourceDisk: response from CloudAPI().Disks().Get", map[string]any{"disk_id": diskId, "response": diskRecord})
return diskRecord, err
}
// CreateRequestResourceDisk generates disk create request from plan
func CreateRequestResourceDisk(ctx context.Context, plan *models.ResourceDiskModel) disks.CreateRequest {
tflog.Info(ctx, "Start CreateRequestResourceDisk", map[string]any{
"account_id": plan.AccountID.ValueInt64(),
"disk_name": plan.DiskName.ValueString(),
"size_max": plan.SizeMax.ValueInt64(),
"gid": plan.GID.ValueInt64(),
})
// set up required parameters in disk create request
createReq := disks.CreateRequest{
AccountID: uint64(plan.AccountID.ValueInt64()),
Name: plan.DiskName.ValueString(),
Size: uint64(plan.SizeMax.ValueInt64()),
GID: uint64(plan.GID.ValueInt64()),
}
if plan.Type.IsUnknown() {
createReq.Type = "D" // default value
} else {
createReq.Type = plan.Type.ValueString()
}
if !plan.SEPID.IsUnknown() {
createReq.SEPID = uint64(plan.SEPID.ValueInt64())
}
if !plan.Pool.IsUnknown() {
createReq.Pool = plan.Pool.ValueString()
}
if !plan.Description.IsUnknown() {
createReq.Description = plan.Description.ValueString()
}
return createReq
}
// LimitIOCreateDisk sets IO limits that user specified in iotune field for created resource.
// In case of failure returns warnings.
func LimitIOCreateDisk(ctx context.Context, diskId uint64, plan *models.ResourceDiskModel, c *decort.DecortClient) diag.Diagnostics {
diags := diag.Diagnostics{}
limitIOReq := disks.LimitIORequest{
DiskID: diskId,
}
var iotunePlan models.IOTuneModel
// plan.IOTune is not null as it was checked before call
tflog.Info(ctx, "LimitIOCreateDisk: new iotune specified", map[string]any{"disk_id": diskId})
diags.Append(plan.IOTune.As(ctx, &iotunePlan, basetypes.ObjectAsOptions{})...)
if diags.HasError() {
tflog.Error(ctx, "LimitIOCreateDisk: cannot populate iotune with plan.IOTune object element")
return diags
}
limitIOReq.IOPS = uint64(iotunePlan.TotalIOPSSec.ValueInt64())
limitIOReq.ReadBytesSec = uint64(iotunePlan.ReadBytesSec.ValueInt64())
limitIOReq.ReadBytesSecMax = uint64(iotunePlan.ReadBytesSecMax.ValueInt64())
limitIOReq.ReadIOPSSec = uint64(iotunePlan.ReadIOPSSec.ValueInt64())
limitIOReq.ReadIOPSSecMax = uint64(iotunePlan.ReadIOPSSecMax.ValueInt64())
limitIOReq.SizeIOPSSec = uint64(iotunePlan.SizeIOPSSec.ValueInt64())
limitIOReq.TotalBytesSec = uint64(iotunePlan.TotalBytesSec.ValueInt64())
limitIOReq.TotalBytesSecMax = uint64(iotunePlan.TotalBytesSecMax.ValueInt64())
limitIOReq.TotalIOPSSecMax = uint64(iotunePlan.TotalIOPSSecMax.ValueInt64())
limitIOReq.TotalIOPSSec = uint64(iotunePlan.TotalIOPSSec.ValueInt64())
limitIOReq.WriteBytesSec = uint64(iotunePlan.WriteBytesSec.ValueInt64())
limitIOReq.WriteBytesSecMax = uint64(iotunePlan.WriteBytesSecMax.ValueInt64())
limitIOReq.WriteIOPSSec = uint64(iotunePlan.WriteIOPSSec.ValueInt64())
limitIOReq.WriteIOPSSecMax = uint64(iotunePlan.WriteIOPSSecMax.ValueInt64())
tflog.Info(ctx, "LimitIOCreateDisk: before calling CloudAPI().Disks().LimitIO", map[string]any{
"disk_id": diskId,
"limitIOReq": limitIOReq})
res, err := c.CloudAPI().Disks().LimitIO(ctx, limitIOReq)
if err != nil {
diags.AddWarning("LimitIOCreateDisk: Unable to limit io for Disk",
err.Error())
}
tflog.Info(ctx, "LimitIOCreateDisk: response from CloudAPI().Disks().LimitIO", map[string]any{
"disk_id": diskId,
"response": res})
return diags
}
// ShareableCreateDisk shares disk.
// In case of failure returns warnings.
func ShareableCreateDisk(ctx context.Context, diskId uint64, c *decort.DecortClient) diag.Diagnostics {
diags := diag.Diagnostics{}
tflog.Info(ctx, "ShareableCreateDisk: before calling CloudAPI().Disks().Share", map[string]any{"disk_id": diskId})
res, err := c.CloudAPI().Disks().Share(ctx, disks.ShareRequest{DiskID: diskId})
if err != nil {
diags.AddWarning("ShareableCreateDisk: Unable to share Disk",
err.Error())
}
tflog.Info(ctx, "ShareableCreateDisk: response from CloudAPI().Disks().Share", map[string]any{
"disk_id": diskId,
"response": res})
return diags
}
// DiskReadStatus loads disk resource by ids id, gets it current status. Performs restore and enable if needed for
// Deleted status.
// In case of failure returns errors.
func DiskReadStatus(ctx context.Context, state *models.ResourceDiskModel, c *decort.DecortClient) diag.Diagnostics {
tflog.Info(ctx, "DiskReadStatus: Read status disk with ID", map[string]any{"disk_id": state.Id.ValueString()})
diags := diag.Diagnostics{}
diskId, err := strconv.ParseUint(state.Id.ValueString(), 10, 64)
if err != nil {
diags.AddError("DiskReadStatus: Cannot parse disk ID from state", err.Error())
return diags
}
recordDisk, err := DiskCheckPresence(ctx, diskId, c)
if err != nil {
diags.AddError("DiskReadStatus: Unable to Read Disk before status check", err.Error())
return diags
}
// check resource status
switch recordDisk.Status {
case status.Modeled:
diags.AddError(
"Disk is in status Modeled",
"please, contact support for more information",
)
return diags
case status.Deleted:
// attempt to restore disk
tflog.Info(ctx, "DiskReadStatus: disk with status.Deleted is being read, attempt to restore it", map[string]any{
"disk_id": recordDisk.ID,
"status": recordDisk.Status})
diags.Append(RestoreDisk(ctx, diskId, c)...)
if diags.HasError() {
tflog.Error(ctx, "DiskReadStatus: cannot restore disk")
return diags
}
tflog.Info(ctx, "DiskReadStatus: disk restored successfully", map[string]any{"disk_id": diskId})
state.LastUpdated = types.StringValue(time.Now().Format(time.RFC850))
case status.Destroyed, status.Purged:
diags.AddError(
"DiskReadStatus: Disk is in status Destroyed or Purged",
fmt.Sprintf("the resource with disk_id %d cannot be read because it has been destroyed or purged", diskId),
)
return diags
}
return nil
}
// RestoreDisk performs disk Restore request.
// Returns error in case of failures.
func RestoreDisk(ctx context.Context, diskId uint64, c *decort.DecortClient) diag.Diagnostics {
diags := diag.Diagnostics{}
restoreReq := disks.RestoreRequest{
DiskID: diskId,
Reason: "Terraform automatic restore",
}
tflog.Info(ctx, "RestoreDisk: before calling CloudAPI().Disks().Restore", map[string]any{"diskId": diskId, "req": restoreReq})
res, err := c.CloudAPI().Disks().Restore(ctx, restoreReq)
if err != nil {
diags.AddError(
"RestoreDisk: cannot restore disk",
err.Error(),
)
return diags
}
tflog.Info(ctx, "RestoreDisk: response from CloudAPI().Disks().Restore", map[string]any{"disk_id": diskId, "response": res})
return nil
}
// SizeMaxUpdateDisk resizes disk.
// Returns error in case of failures.
func SizeMaxUpdateDisk(ctx context.Context, diskId uint64, plan, state *models.ResourceDiskModel, c *decort.DecortClient) diag.Diagnostics {
var diags diag.Diagnostics
resizeReq := disks.ResizeRequest{
DiskID: diskId,
}
// check if resize request is valid
if plan.SizeMax.ValueInt64() < state.SizeMax.ValueInt64() {
diags.AddError(
"SizeMaxUpdateDisk: reducing disk size is not allowed",
fmt.Sprintf("disk with id %s has state size %d, plan size %d",
plan.Id.ValueString(),
state.SizeMax.ValueInt64(),
plan.SizeMax.ValueInt64()))
return diags
}
resizeReq.Size = uint64(plan.SizeMax.ValueInt64())
tflog.Info(ctx, "SizeMaxUpdateDisk: before calling CloudAPI().Disks().Resize2", map[string]any{
"disk_id": plan.Id.ValueString(),
"size_max_state": state.SizeMax.ValueInt64(),
"size_max_plan": plan.SizeMax.ValueInt64(),
"req": resizeReq,
})
res, err := c.CloudAPI().Disks().Resize2(ctx, resizeReq)
if err != nil {
diags.AddError("can not resize disk", err.Error())
return diags
}
tflog.Info(ctx, "SizeMaxUpdateDisk: response from CloudAPI().Disks().Resize2", map[string]any{
"disk_id": plan.Id.ValueString(),
"response": res})
return nil
}
// NameUpdateDisk renames disk.
// Returns error in case of failures.
func NameUpdateDisk(ctx context.Context, diskId uint64, plan *models.ResourceDiskModel, c *decort.DecortClient) diag.Diagnostics {
var diags diag.Diagnostics
renameReq := disks.RenameRequest{
DiskID: diskId,
Name: plan.DiskName.ValueString(),
}
tflog.Info(ctx, "NameUpdateDisk: before calling CloudAPI().Disks().Rename", map[string]any{
"disk_id": plan.Id.ValueString(),
"disk_name_plan": plan.DiskName.ValueString(),
"req": renameReq,
})
res, err := c.CloudAPI().Disks().Rename(ctx, renameReq)
if err != nil {
diags.AddError("NameUpdateDisk: can not rename disk", err.Error())
return diags
}
tflog.Info(ctx, "NameUpdateDisk: response from CloudAPI().Disks().Rename", map[string]any{
"disk_id": plan.Id.ValueString(),
"response": res})
return nil
}
// LimitIOUpdateDisk changes IO limits that user specified in iotune field for updated resource.
// In case of failure returns errors.
func LimitIOUpdateDisk(ctx context.Context, diskId uint64, plan *models.ResourceDiskModel, c *decort.DecortClient) diag.Diagnostics {
diags := diag.Diagnostics{}
limitIOReq := disks.LimitIORequest{
DiskID: diskId,
}
var iotunePlan models.IOTuneModel
// plan.IOTune is not null as it was checked before call
tflog.Info(ctx, "LimitIOUpdateDisk: new iotune specified", map[string]any{"disk_id": diskId})
diags.Append(plan.IOTune.As(ctx, &iotunePlan, basetypes.ObjectAsOptions{})...)
if diags.HasError() {
tflog.Error(ctx, "LimitIOUpdateDisk: cannot populate iotune with plan.IOTune object element")
return diags
}
limitIOReq.IOPS = uint64(iotunePlan.TotalIOPSSec.ValueInt64())
limitIOReq.ReadBytesSec = uint64(iotunePlan.ReadBytesSec.ValueInt64())
limitIOReq.ReadBytesSecMax = uint64(iotunePlan.ReadBytesSecMax.ValueInt64())
limitIOReq.ReadIOPSSec = uint64(iotunePlan.ReadIOPSSec.ValueInt64())
limitIOReq.ReadIOPSSecMax = uint64(iotunePlan.ReadIOPSSecMax.ValueInt64())
limitIOReq.SizeIOPSSec = uint64(iotunePlan.SizeIOPSSec.ValueInt64())
limitIOReq.TotalBytesSec = uint64(iotunePlan.TotalBytesSec.ValueInt64())
limitIOReq.TotalBytesSecMax = uint64(iotunePlan.TotalBytesSecMax.ValueInt64())
limitIOReq.TotalIOPSSecMax = uint64(iotunePlan.TotalIOPSSecMax.ValueInt64())
limitIOReq.TotalIOPSSec = uint64(iotunePlan.TotalIOPSSec.ValueInt64())
limitIOReq.WriteBytesSec = uint64(iotunePlan.WriteBytesSec.ValueInt64())
limitIOReq.WriteBytesSecMax = uint64(iotunePlan.WriteBytesSecMax.ValueInt64())
limitIOReq.WriteIOPSSec = uint64(iotunePlan.WriteIOPSSec.ValueInt64())
limitIOReq.WriteIOPSSecMax = uint64(iotunePlan.WriteIOPSSecMax.ValueInt64())
tflog.Info(ctx, "LimitIOUpdateDisk: before calling CloudAPI().Disks().LimitIO", map[string]any{
"disk_id": diskId,
"limitIOReq": limitIOReq})
res, err := c.CloudAPI().Disks().LimitIO(ctx, limitIOReq)
if err != nil {
diags.AddError("LimitIOUpdateDisk: Unable to limit io for Disk",
err.Error())
return diags
}
tflog.Info(ctx, "LimitIOUpdateDisk: response from CloudAPI().Disks().LimitIO", map[string]any{
"disk_id": diskId,
"response": res})
return nil
}
// ShareableUpdateDisk shares or unshares disk.
// In case of failure returns errors.
func ShareableUpdateDisk(ctx context.Context, diskId uint64, share bool, c *decort.DecortClient) diag.Diagnostics {
diags := diag.Diagnostics{}
// share
if share {
tflog.Info(ctx, "ShareableUpdateDisk: before calling CloudAPI().Disks().Share", map[string]any{"disk_id": diskId})
res, err := c.CloudAPI().Disks().Share(ctx, disks.ShareRequest{DiskID: diskId})
if err != nil {
diags.AddError("ShareableUpdateDisk: Unable to share Disk",
err.Error())
return diags
}
tflog.Info(ctx, "ShareableUpdateDisk: response from CloudAPI().Disks().Share", map[string]any{
"disk_id": diskId,
"response": res})
}
// unshare
if !share {
tflog.Info(ctx, "ShareableUpdateDisk: before calling CloudAPI().Disks().Unshare", map[string]any{"disk_id": diskId})
res, err := c.CloudAPI().Disks().Unshare(ctx, disks.UnshareRequest{DiskID: diskId})
if err != nil {
diags.AddError("ShareableUpdateDisk: Unable to unshare Disk",
err.Error())
return diags
}
tflog.Info(ctx, "ShareableUpdateDisk: response from CloudAPI().Disks().Unshare", map[string]any{
"disk_id": diskId,
"response": res})
}
return nil
}

View File

@@ -0,0 +1,172 @@
package utilities
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/disks/models"
)
func UtilityDiskReplicationUpdateStartStop(ctx context.Context, state *models.ResourceRecordDiskReplicationModel, c *decort.DecortClient) diag.Diagnostics {
diags := diag.Diagnostics{}
diskId := uint64(state.DiskId.ValueInt64())
targetDiskId := uint64(state.ReplicationId.ValueInt64())
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdateStartStop: start update for disk replica with ID: %d", diskId))
ok := !(state.Start.IsNull() || state.Start.IsUnknown())
start := state.Start.ValueBool()
if ok && start {
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdateStartStop: start disk replication from Disk with ID: %d to Disk with ID: %d", diskId, targetDiskId))
req := disks.ReplicationStartRequest{
DiskID: diskId,
TargetDiskID: targetDiskId,
}
_, err := c.CloudAPI().Disks().ReplicationStart(ctx, req)
if err != nil {
diags.AddError("UtilityDiskReplicationUpdateStartStop: Unable to start replicate disk", err.Error())
return diags
}
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdateStartStop: start disk replication from Disk with ID: %d to Disk with ID: %d, complete", diskId, targetDiskId))
}
if ok && !start {
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdateStartStop: stop disk replication from Disk with ID: %d to Disk with ID: %d", targetDiskId, diskId))
req := disks.ReplicationStopRequest{
DiskID: targetDiskId,
}
_, err := c.CloudAPI().Disks().ReplicationStop(ctx, req)
if err != nil {
diags.AddError("UtilityDiskReplicationUpdateStartStop: Unable to stop replicate disk", err.Error())
return diags
}
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdateStartStop: stop disk replication from Disk with ID: %d to Disk with ID: %d, complete", targetDiskId, diskId))
}
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdateStartStop: complete update for disk replica with ID: %d", diskId))
return nil
}
func UtilityDiskReplicationUpdatePause(ctx context.Context, state *models.ResourceRecordDiskReplicationModel, c *decort.DecortClient) diag.Diagnostics {
diags := diag.Diagnostics{}
diskId := uint64(state.DiskId.ValueInt64())
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdatePause: start update for disk replica with ID: %d", diskId))
pause := state.Pause.ValueBool()
ok := !(state.Pause.IsNull() || state.Pause.IsUnknown())
if ok && pause {
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdatePause: pause disk replication with ID: %d", diskId))
req := disks.ReplicationSuspendRequest{
DiskID: diskId,
}
_, err := c.CloudAPI().Disks().ReplicationSuspend(ctx, req)
if err != nil {
diags.AddError("utilityDiskReplicationUpdatePause: Unable to pause disk", err.Error())
return diags
}
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdatePause: pause disk replication with ID: %d, complete", diskId))
}
if ok && !pause {
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdatePause: resume disk replication with ID: %d", diskId))
req := disks.ReplicationResumeRequest{
DiskID: diskId,
}
_, err := c.CloudAPI().Disks().ReplicationResume(ctx, req)
if err != nil {
diags.AddError("utilityDiskReplicationUpdatePause: Unable to resume disk", err.Error())
return diags
}
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdatePause: resume disk replication with ID: %d, complete", diskId))
}
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicationUpdatePause: complete update for disk replica with ID: %d", diskId))
return nil
}
func UtilityDiskReplicationUpdateReverse(ctx context.Context, state *models.ResourceRecordDiskReplicationModel, c *decort.DecortClient) diag.Diagnostics {
diags := diag.Diagnostics{}
diskId := uint64(state.DiskId.ValueInt64())
targetDiskId := uint64(state.ReplicationId.ValueInt64())
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicaUpdateReverse: start update for disk replica with ID: %d", diskId))
reverse := state.Reverse.ValueBool()
ok := !(state.Reverse.IsNull() || state.Reverse.IsUnknown())
if ok && reverse {
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicaUpdateReverse: reverse disk replication from Disk with ID: %d to Disk with ID: %d", diskId, targetDiskId))
req := disks.ReplicationReverseRequest{
DiskID: diskId,
}
_, err := c.CloudAPI().Disks().ReplicationReverse(ctx, req)
if err != nil {
diags.AddError("utilityDiskReplicationUpdateReverse: Unable to reverse disk", err.Error())
return diags
}
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicaUpdateReverse: reverse disk replication from Disk with ID: %d to Disk with ID: %d, complete", diskId, targetDiskId))
}
if ok && !reverse {
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicaUpdateReverse: reverse disk replication from Disk with ID: %d to Disk with ID: %d", targetDiskId, diskId))
req := disks.ReplicationReverseRequest{
DiskID: targetDiskId,
}
_, err := c.CloudAPI().Disks().ReplicationReverse(ctx, req)
if err != nil {
diags.AddError("utilityDiskReplicationUpdateReverse: Unable to reverse disk", err.Error())
return diags
}
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicaUpdateReverse: reverse disk replication from Disk with ID: %d to Disk with ID: %d, complete", targetDiskId, diskId))
}
tflog.Info(ctx, fmt.Sprintf("utilityDiskReplicaUpdateReverse: complete update for disk replica with ID: %d", diskId))
return nil
}
func ResourceDiskReplicationCheckPresence(ctx context.Context, state *models.ResourceRecordDiskReplicationModel, c *decort.DecortClient) (*disks.RecordDisk, *string, error) {
status, err := c.CloudAPI().Disks().ReplicationStatus(ctx, disks.ReplicationStatusRequest{DiskID: uint64(state.DiskId.ValueInt64())})
if err != nil {
return nil, nil, err
}
req := disks.GetRequest{}
if !state.DiskId.IsNull() && !state.DiskId.IsUnknown() {
req.DiskID = uint64(state.DiskId.ValueInt64())
} else {
req.DiskID = uint64(state.ReplicationId.ValueInt64())
}
tflog.Info(ctx, "ResourceDiskReplicationCheckPresence: load disk")
disk, err := c.CloudAPI().Disks().Get(ctx, req)
if err != nil {
return nil, nil, err
}
return disk, &status, nil
}
// DiskReadStatus loads disk resource by ids id, gets it current status.
// In case of failure returns errors.
func ReplicationDiskReadStatus(ctx context.Context, state *models.ResourceRecordDiskReplicationModel, c *decort.DecortClient) diag.Diagnostics {
tflog.Info(ctx, "ReplicationDiskReadStatus: Read status disk with ID", map[string]any{"disk_id": state.DiskId.ValueInt64()})
diags := diag.Diagnostics{}
_, _, err := ResourceDiskReplicationCheckPresence(ctx, state, c)
if err != nil {
diags.AddError("ReplicationDiskReadStatus: Unable to Read Disk before status check", err.Error())
return diags
}
return nil
}

View File

@@ -0,0 +1,94 @@
package utilities
import (
"context"
"fmt"
"strconv"
"strings"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-log/tflog"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/disks/models"
)
// DiskSnapshotCheckPresence checks if disk snapshot exists
func DiskSnapshotCheckPresence(ctx context.Context, plan *models.ResourceDiskSnapshotModel, c *decort.DecortClient) (*disks.ItemSnapshot, diag.Diagnostics) {
diags := diag.Diagnostics{}
// take diskId and label from plan
diskId := uint64(plan.DiskID.ValueInt64())
label := plan.Label.ValueString()
// take diskId and label from Id for imported resource
if strings.Contains(plan.Id.ValueString(), "#") {
diskIdInt, err := strconv.Atoi(strings.Split(plan.Id.ValueString(), "#")[0])
if err != nil {
diags.AddError("Cannot parse disk ID from state", err.Error())
return nil, diags
}
diskId = uint64(diskIdInt)
label = strings.Split(plan.Id.ValueString(), "#")[1]
}
tflog.Info(ctx, "Start DiskSnapshotCheckPresence", map[string]any{
"disk_id": diskId,
"label": label,
"id": plan.Id.ValueString(),
})
tflog.Info(ctx, "DiskSnapshotCheckPresence: before call CloudAPI().Disks().Get", map[string]any{"disk_id": diskId})
disk, err := c.CloudAPI().Disks().Get(ctx, disks.GetRequest{DiskID: diskId})
if err != nil {
diags.AddError(
fmt.Sprintf("Cannot get info about disk with disk_id %d", diskId),
err.Error(),
)
return nil, diags
}
tflog.Info(ctx, "DiskSnapshotCheckPresence: response from CloudAPI().Disks().Get", map[string]any{"response": disk})
for _, sn := range disk.Snapshots {
if label == sn.Label {
return &sn, nil
}
}
diags.AddError(
"Snapshot not found",
fmt.Sprintf("Snapshot with label %s for disk with disk_id %d not found", label, diskId),
)
return nil, diags
}
// RollbackDiskSnapshot rollbacks disk snapshot.
// Returns error in case of failures.
func RollbackDiskSnapshot(ctx context.Context, plan *models.ResourceDiskSnapshotModel, c *decort.DecortClient) diag.Diagnostics {
diags := diag.Diagnostics{}
rollbackReq := disks.SnapshotRollbackRequest{
DiskID: uint64(plan.DiskID.ValueInt64()),
Label: plan.Label.ValueString(),
}
if !plan.TimeStamp.IsUnknown() {
rollbackReq.TimeStamp = uint64(plan.TimeStamp.ValueInt64())
}
tflog.Info(ctx, "RollbackDiskSnapshot: before calling CloudAPI().Disks().SnapshotRollback", map[string]any{"req": rollbackReq})
res, err := c.CloudAPI().Disks().SnapshotRollback(ctx, rollbackReq)
if err != nil {
diags.AddError(
"RollbackDiskSnapshot: Cannot rollback snapshot",
err.Error(),
)
return diags
}
tflog.Info(ctx, "RollbackDiskSnapshot: response from CloudAPI().Disks().SnapshotRollback", map[string]any{
"disk_id": plan.DiskID.ValueInt64(),
"label": plan.Label.ValueString(),
"response": res})
return nil
}