Add files

This commit is contained in:
stSolo
2022-07-20 17:14:00 +03:00
parent 2b7f3d45f3
commit 28ceebecf8
125 changed files with 15225 additions and 735 deletions

View File

@@ -73,51 +73,6 @@ func flattenRgAcl(rgAcls []AccountAclRecord) []map[string]interface{} {
return res
}
/*uncomment for cloudbroker
func flattenAccountList(al AccountList) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, acc := range al {
temp := map[string]interface{}{
"dc_location": acc.DCLocation,
"ckey": acc.CKey,
"meta": flattenMeta(acc.Meta),
"acl": flattenRgAcl(acc.Acl),
"company": acc.Company,
"companyurl": acc.CompanyUrl,
"created_by": acc.CreatedBy,
"created_time": acc.CreatedTime,
"deactivation_time": acc.DeactiovationTime,
"deleted_by": acc.DeletedBy,
"deleted_time": acc.DeletedTime,
"displayname": acc.DisplayName,
"guid": acc.GUID,
"account_id": acc.ID,
"account_name": acc.Name,
"resource_limits": flattenRgResourceLimits(acc.ResourceLimits),
"send_access_emails": acc.SendAccessEmails,
"service_account": acc.ServiceAccount,
"status": acc.Status,
"updated_time": acc.UpdatedTime,
"version": acc.Version,
"vins": acc.Vins,
}
res = append(res, temp)
}
return res
}
*/
func dataSourceAccountListRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
accountList, err := utilityAccountListCheckPresence(ctx, d, m)
if err != nil {
@@ -148,22 +103,6 @@ func dataSourceAccountListSchemaMake() map[string]*schema.Schema {
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
/*uncomment for cloudbroker
"dc_location": {
Type: schema.TypeString,
Computed: true,
},
"ckey": {
Type: schema.TypeString,
Computed: true,
},
"meta": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},*/
"acl": {
Type: schema.TypeList,
Computed: true,
@@ -196,48 +135,14 @@ func dataSourceAccountListSchemaMake() map[string]*schema.Schema {
},
},
},
/*uncomment for cloudbroker
"company": {
Type: schema.TypeString,
Computed: true,
},
"companyurl": {
Type: schema.TypeString,
Computed: true,
},
"created_by": {
Type: schema.TypeString,
Computed: true,
},
*/
"created_time": {
Type: schema.TypeInt,
Computed: true,
},
/*uncomment for cloudbroker
"deactivation_time": {
Type: schema.TypeFloat,
Computed: true,
},
"deleted_by": {
Type: schema.TypeString,
Computed: true,
},
*/
"deleted_time": {
Type: schema.TypeInt,
Computed: true,
},
/*uncomment for cloudbroker
"displayname": {
Type: schema.TypeString,
Computed: true,
},
"guid": {
Type: schema.TypeInt,
Computed: true,
},
*/
"account_id": {
Type: schema.TypeInt,
Computed: true,
@@ -246,49 +151,6 @@ func dataSourceAccountListSchemaMake() map[string]*schema.Schema {
Type: schema.TypeString,
Computed: true,
},
/*uncomment for cloudbroker
"resource_limits": {
Type: schema.TypeList,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cu_c": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_d": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_i": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_m": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_np": {
Type: schema.TypeFloat,
Computed: true,
},
"gpu_units": {
Type: schema.TypeFloat,
Computed: true,
},
},
},
},
"send_access_emails": {
Type: schema.TypeBool,
Computed: true,
},
"service_account": {
Type: schema.TypeBool,
Computed: true,
},
*/
"status": {
Type: schema.TypeString,
Computed: true,
@@ -297,19 +159,6 @@ func dataSourceAccountListSchemaMake() map[string]*schema.Schema {
Type: schema.TypeInt,
Computed: true,
},
/*uncomment for cloudbroker
"version": {
Type: schema.TypeInt,
Computed: true,
},
"vins": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
},
*/
},
},
},

View File

@@ -37,7 +37,6 @@ import (
"strconv"
"strings"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/rudecs/terraform-provider-decort/internal/constants"
@@ -49,22 +48,6 @@ import (
func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceAccountCreate")
if accountId, ok := d.GetOk("account_id"); ok {
if exists, err := resourceAccountExists(ctx, d, m); exists {
if err != nil {
return diag.FromErr(err)
}
d.SetId(strconv.Itoa(accountId.(int)))
diagnostics := resourceAccountRead(ctx, d, m)
if diagnostics != nil {
return diagnostics
}
return nil
}
return diag.Errorf("provided account id does not exist")
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
@@ -138,7 +121,6 @@ func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, m interf
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(accountId)
d.Set("account_id", accountId)
@@ -147,7 +129,42 @@ func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, m interf
return diagnostics
}
d.SetId(id.String())
urlValues = &url.Values{}
if enable, ok := d.GetOk("enable"); ok {
api := accountDisableAPI
enable := enable.(bool)
if enable {
api = accountEnableAPI
}
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
_, err := c.DecortAPICall(ctx, "POST", api, urlValues)
if err != nil {
return diag.FromErr(err)
}
urlValues = &url.Values{}
}
if users, ok := d.GetOk("users"); ok {
addedUsers := users.([]interface{})
if len(addedUsers) > 0 {
for _, user := range addedUsers {
userConv := user.(map[string]interface{})
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
urlValues.Add("userId", userConv["user_id"].(string))
urlValues.Add("accesstype", strings.ToUpper(userConv["access_type"].(string)))
_, err := c.DecortAPICall(ctx, "POST", accountAddUserAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
urlValues = &url.Values{}
}
}
}
return nil
}

View File

@@ -36,7 +36,6 @@ import (
"net/url"
"strconv"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/rudecs/terraform-provider-decort/internal/constants"
@@ -47,24 +46,6 @@ import (
func resourceBasicServiceCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceBasicServiceCreate")
if serviceId, ok := d.GetOk("service_id"); ok {
if exists, err := resourceBasicServiceExists(ctx, d, m); exists {
if err != nil {
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(strconv.Itoa(serviceId.(int)))
d.Set("service_id", strconv.Itoa(serviceId.(int)))
diagnostics := resourceBasicServiceRead(ctx, d, m)
if diagnostics != nil {
return diagnostics
}
d.SetId(id.String())
return nil
}
return diag.Errorf("provided service id does not exist")
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
@@ -83,7 +64,6 @@ func resourceBasicServiceCreate(ctx context.Context, d *schema.ResourceData, m i
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(serviceId)
d.Set("service_id", serviceId)
@@ -92,8 +72,6 @@ func resourceBasicServiceCreate(ctx context.Context, d *schema.ResourceData, m i
return diagnostics
}
d.SetId(id.String())
return nil
}

View File

@@ -37,7 +37,6 @@ import (
"strconv"
"strings"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
@@ -49,26 +48,6 @@ import (
func resourceBasicServiceGroupCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceBasicServiceGroupCreate")
if compgroupId, ok := d.GetOk("compgroup_id"); ok {
if _, ok := d.GetOk("service_id"); ok {
if exists, err := resourceBasicServiceGroupExists(ctx, d, m); exists {
if err != nil {
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(strconv.Itoa(compgroupId.(int)))
d.Set("compgroup_id", strconv.Itoa(compgroupId.(int)))
diagnostics := resourceBasicServiceGroupRead(ctx, d, m)
if diagnostics != nil {
return diagnostics
}
d.SetId(id.String())
return nil
}
return diag.Errorf("provided compgroup id does not exist")
}
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
@@ -124,7 +103,6 @@ func resourceBasicServiceGroupCreate(ctx context.Context, d *schema.ResourceData
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(compgroupId)
d.Set("compgroup_id", compgroupId)
@@ -133,8 +111,6 @@ func resourceBasicServiceGroupCreate(ctx context.Context, d *schema.ResourceData
return diagnostics
}
d.SetId(id.String())
return nil
}

View File

@@ -31,9 +31,11 @@ Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
package disks
const DisksCreateAPI = "/restmachine/cloudapi/disks/create"
const DisksGetAPI = "/restmachine/cloudapi/disks/get" // Returns single DiskRecord on success
const DisksListAPI = "/restmachine/cloudapi/disks/list" // Returns list of DiskRecord on success
const DisksResizeAPI = "/restmachine/cloudapi/disks/resize2"
const DisksRenameAPI = "/restmachine/cloudapi/disks/rename"
const DisksDeleteAPI = "/restmachine/cloudapi/disks/delete"
const disksCreateAPI = "/restmachine/cloudapi/disks/create"
const disksGetAPI = "/restmachine/cloudapi/disks/get"
const disksListAPI = "/restmachine/cloudapi/disks/list"
const disksResizeAPI = "/restmachine/cloudapi/disks/resize2"
const disksRenameAPI = "/restmachine/cloudapi/disks/rename"
const disksDeleteAPI = "/restmachine/cloudapi/disks/delete"
const disksIOLimitAPI = "/restmachine/cloudapi/disks/limitIO"
const disksRestoreAPI = "/restmachine/cloudapi/disks/restore"

View File

@@ -34,162 +34,340 @@ package disks
import (
"context"
"encoding/json"
"fmt"
// "net/url"
"github.com/google/uuid"
"github.com/rudecs/terraform-provider-decort/internal/constants"
log "github.com/sirupsen/logrus"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func flattenDisk(d *schema.ResourceData, disk_facts string) error {
// This function expects disk_facts string to contain a response from disks/get API
//
// NOTE: this function modifies ResourceData argument - as such it should never be called
// from resourceDiskExists(...) method. Use utilityDiskCheckPresence instead.
log.Debugf("flattenDisk: ready to unmarshal string %s", disk_facts)
model := DiskRecord{}
err := json.Unmarshal([]byte(disk_facts), &model)
func dataSourceDiskRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
disk, err := utilityDiskCheckPresence(ctx, d, m)
if err != nil {
return err
return diag.FromErr(err)
}
log.Debugf("flattenDisk: disk ID %d, disk AccountID %d", model.ID, model.AccountID)
id := uuid.New()
d.SetId(id.String())
d.SetId(fmt.Sprintf("%d", model.ID))
// d.Set("disk_id", model.ID) - we should NOT update disk_id in the schema. If it was set - it is already set, if it wasn't - we shouldn't
d.Set("name", model.Name)
d.Set("account_id", model.AccountID)
d.Set("account_name", model.AccountName)
d.Set("size", model.SizeMax)
// d.Set("sizeUsed", model.SizeUsed)
d.Set("type", model.Type)
d.Set("image_id", model.ImageID)
d.Set("sep_id", model.SepID)
d.Set("sep_type", model.SepType)
d.Set("pool", model.Pool)
// d.Set("compute_id", model.ComputeID)
diskAcl, _ := json.Marshal(disk.Acl)
d.Set("description", model.Desc)
d.Set("account_id", disk.AccountID)
d.Set("account_name", disk.AccountName)
d.Set("acl", string(diskAcl))
d.Set("boot_partition", disk.BootPartition)
d.Set("compute_id", disk.ComputeID)
d.Set("compute_name", disk.ComputeName)
d.Set("created_time", disk.CreatedTime)
d.Set("deleted_time", disk.DeletedTime)
d.Set("desc", disk.Desc)
d.Set("destruction_time", disk.DestructionTime)
d.Set("devicename", disk.DeviceName)
d.Set("disk_path", disk.DiskPath)
d.Set("gid", disk.GridID)
d.Set("guid", disk.GUID)
d.Set("disk_id", disk.ID)
d.Set("image_id", disk.ImageID)
d.Set("images", disk.Images)
d.Set("iotune", flattenIOTune(disk.IOTune))
d.Set("iqn", disk.IQN)
d.Set("login", disk.Login)
d.Set("milestones", disk.Milestones)
d.Set("disk_name", disk.Name)
d.Set("order", disk.Order)
d.Set("params", disk.Params)
d.Set("parent_id", disk.ParentId)
d.Set("passwd", disk.Passwd)
d.Set("pci_slot", disk.PciSlot)
d.Set("pool", disk.Pool)
d.Set("purge_attempts", disk.PurgeAttempts)
d.Set("purge_time", disk.PurgeTime)
d.Set("reality_device_number", disk.RealityDeviceNumber)
d.Set("reference_id", disk.ReferenceId)
d.Set("res_id", disk.ResID)
d.Set("res_name", disk.ResName)
d.Set("role", disk.Role)
d.Set("sep_id", disk.SepID)
d.Set("sep_type", disk.SepType)
d.Set("size_max", disk.SizeMax)
d.Set("size_used", disk.SizeUsed)
d.Set("snapshots", flattendDiskSnapshotList(disk.Snapshots))
d.Set("status", disk.Status)
d.Set("tech_status", disk.TechStatus)
d.Set("type", disk.Type)
d.Set("vmid", disk.VMID)
return nil
}
func dataSourceDiskRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
disk_facts, err := utilityDiskCheckPresence(ctx, d, m)
if disk_facts == "" {
// if empty string is returned from utilityDiskCheckPresence then there is no
// such Disk and err tells so - just return it to the calling party
d.SetId("") // ensure ID is empty
return diag.FromErr(err)
}
return diag.FromErr(flattenDisk(d, disk_facts))
}
func dataSourceDiskSchemaMake() map[string]*schema.Schema {
rets := map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Optional: true,
Description: "Name of this disk. NOTE: disk names are NOT unique within an account. If disk ID is specified, disk name is ignored.",
},
"disk_id": {
Type: schema.TypeInt,
Optional: true,
Description: "ID of the disk to get. If disk ID is specified, then disk name and account ID are ignored.",
Type: schema.TypeInt,
Required: true,
},
"account_id": {
Type: schema.TypeInt,
Optional: true,
Description: "ID of the account this disk belongs to. If disk ID is specified, then account ID is ignored.",
Type: schema.TypeInt,
Computed: true,
},
// The rest of the data source Disk schema are all computed
"sep_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Storage end-point provider serving this disk.",
},
"pool": {
Type: schema.TypeString,
Computed: true,
Description: "Pool where this disk is located.",
},
"size": {
Type: schema.TypeInt,
Computed: true,
Description: "Size of the disk in GB.",
},
"type": {
Type: schema.TypeString,
Computed: true,
Description: "Type of this disk. E.g. D for data disks, B for boot.",
},
"description": {
Type: schema.TypeString,
Computed: true,
Description: "User-defined text description of this disk.",
},
"account_name": {
Type: schema.TypeString,
Computed: true,
Description: "Name of the account this disk belongs to. If account ID is specified, account name is ignored.",
Type: schema.TypeString,
Computed: true,
},
"acl": {
Type: schema.TypeString,
Computed: true,
},
"boot_partition": {
Type: schema.TypeInt,
Computed: true,
},
"compute_id": {
Type: schema.TypeInt,
Computed: true,
},
"compute_name": {
Type: schema.TypeString,
Computed: true,
},
"created_time": {
Type: schema.TypeInt,
Computed: true,
},
"deleted_time": {
Type: schema.TypeInt,
Computed: true,
},
"desc": {
Type: schema.TypeString,
Computed: true,
},
"destruction_time": {
Type: schema.TypeInt,
Computed: true,
},
"devicename": {
Type: schema.TypeString,
Computed: true,
},
"disk_path": {
Type: schema.TypeString,
Computed: true,
},
"gid": {
Type: schema.TypeInt,
Computed: true,
},
"guid": {
Type: schema.TypeInt,
Computed: true,
},
"image_id": {
Type: schema.TypeInt,
Computed: true,
Description: "ID of the image, which this disk was cloned from (valid for disk clones only).",
Type: schema.TypeInt,
Computed: true,
},
"sep_type": {
Type: schema.TypeString,
Computed: true,
Description: "Type of the storage end-point provider serving this disk.",
"images": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
/*
"snapshots": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource {
Schema: snapshotSubresourceSchemaMake(),
"iotune": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"read_bytes_sec": {
Type: schema.TypeInt,
Computed: true,
},
"read_bytes_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
"read_iops_sec": {
Type: schema.TypeInt,
Computed: true,
},
"read_iops_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
"size_iops_sec": {
Type: schema.TypeInt,
Computed: true,
},
"total_bytes_sec": {
Type: schema.TypeInt,
Computed: true,
},
"total_bytes_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
"total_iops_sec": {
Type: schema.TypeInt,
Computed: true,
},
"total_iops_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
"write_bytes_sec": {
Type: schema.TypeInt,
Computed: true,
},
"write_bytes_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
"write_iops_sec": {
Type: schema.TypeInt,
Computed: true,
},
"write_iops_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
Description: "List of user-created snapshots for this disk."
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: "Current model status of this disk.",
},
"tech_status": {
Type: schema.TypeString,
Computed: true,
Description: "Current technical status of this disk.",
},
"iqn": {
Type: schema.TypeString,
Computed: true,
},
"login": {
Type: schema.TypeString,
Computed: true,
},
"milestones": {
Type: schema.TypeInt,
Computed: true,
},
"disk_name": {
Type: schema.TypeString,
Computed: true,
},
"order": {
Type: schema.TypeInt,
Computed: true,
},
"params": {
Type: schema.TypeString,
Computed: true,
},
"parent_id": {
Type: schema.TypeInt,
Computed: true,
},
"passwd": {
Type: schema.TypeString,
Computed: true,
},
"pci_slot": {
Type: schema.TypeInt,
Computed: true,
},
"pool": {
Type: schema.TypeString,
Computed: true,
},
"purge_attempts": {
Type: schema.TypeInt,
Computed: true,
},
"purge_time": {
Type: schema.TypeInt,
Computed: true,
},
"reality_device_number": {
Type: schema.TypeInt,
Computed: true,
},
"reference_id": {
Type: schema.TypeString,
Computed: true,
},
"res_id": {
Type: schema.TypeString,
Computed: true,
},
"res_name": {
Type: schema.TypeString,
Computed: true,
},
"role": {
Type: schema.TypeString,
Computed: true,
},
"sep_id": {
Type: schema.TypeInt,
Computed: true,
},
"sep_type": {
Type: schema.TypeString,
Computed: true,
},
"size_max": {
Type: schema.TypeInt,
Computed: true,
},
"size_used": {
Type: schema.TypeInt,
Computed: true,
},
"snapshots": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"guid": {
Type: schema.TypeString,
Computed: true,
},
"label": {
Type: schema.TypeString,
Computed: true,
},
"res_id": {
Type: schema.TypeString,
Computed: true,
},
"snap_set_guid": {
Type: schema.TypeString,
Computed: true,
},
"snap_set_time": {
Type: schema.TypeInt,
Computed: true,
},
"timestamp": {
Type: schema.TypeInt,
Computed: true,
},
},
},
"compute_id": {
Type: schema.TypeInt,
Computed: true,
Description: "ID of the compute instance where this disk is attached to, or 0 for unattached disk.",
},
*/
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"tech_status": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
"vmid": {
Type: schema.TypeInt,
Computed: true,
},
}
return rets

View File

@@ -41,11 +41,32 @@ import (
"github.com/rudecs/terraform-provider-decort/internal/constants"
)
func flattenDiskList(dl DisksListResp) []map[string]interface{} {
func flattenIOTune(iot IOTune) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"read_bytes_sec": iot.ReadBytesSec,
"read_bytes_sec_max": iot.ReadBytesSecMax,
"read_iops_sec": iot.ReadIopsSec,
"read_iops_sec_max": iot.ReadIopsSecMax,
"size_iops_sec": iot.SizeIopsSec,
"total_bytes_sec": iot.TotalBytesSec,
"total_bytes_sec_max": iot.TotalBytesSecMax,
"total_iops_sec": iot.TotalIopsSec,
"total_iops_sec_max": iot.TotalIopsSecMax,
"write_bytes_sec": iot.WriteBytesSec,
"write_bytes_sec_max": iot.WriteBytesSecMax,
"write_iops_sec": iot.WriteIopsSec,
"write_iops_sec_max": iot.WriteIopsSecMax,
}
res = append(res, temp)
return res
}
func flattenDiskList(dl DisksList) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, disk := range dl {
diskAcl, _ := json.Marshal(disk.Acl)
diskIotune, _ := json.Marshal(disk.IOTune)
temp := map[string]interface{}{
"account_id": disk.AccountID,
"account_name": disk.AccountName,
@@ -64,13 +85,13 @@ func flattenDiskList(dl DisksListResp) []map[string]interface{} {
"disk_id": disk.ID,
"image_id": disk.ImageID,
"images": disk.Images,
"iotune": string(diskIotune),
"iotune": flattenIOTune(disk.IOTune),
"iqn": disk.IQN,
"login": disk.Login,
"machine_id": disk.MachineId,
"machine_name": disk.MachineName,
"milestones": disk.Milestones,
"name": disk.Name,
"disk_name": disk.Name,
"order": disk.Order,
"params": disk.Params,
"parent_id": disk.ParentId,
@@ -93,7 +114,6 @@ func flattenDiskList(dl DisksListResp) []map[string]interface{} {
"tech_status": disk.TechStatus,
"type": disk.Type,
"vmid": disk.VMID,
"update_by": disk.UpdateBy,
}
res = append(res, temp)
}
@@ -101,7 +121,7 @@ func flattenDiskList(dl DisksListResp) []map[string]interface{} {
}
func flattendDiskSnapshotList(sl SnapshotRecordList) []interface{} {
func flattendDiskSnapshotList(sl SnapshotList) []interface{} {
res := make([]interface{}, 0)
for _, snapshot := range sl {
temp := map[string]interface{}{
@@ -231,8 +251,64 @@ func dataSourceDiskListSchemaMake() map[string]*schema.Schema {
},
},
"iotune": {
Type: schema.TypeString,
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"read_bytes_sec": {
Type: schema.TypeInt,
Computed: true,
},
"read_bytes_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
"read_iops_sec": {
Type: schema.TypeInt,
Computed: true,
},
"read_iops_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
"size_iops_sec": {
Type: schema.TypeInt,
Computed: true,
},
"total_bytes_sec": {
Type: schema.TypeInt,
Computed: true,
},
"total_bytes_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
"total_iops_sec": {
Type: schema.TypeInt,
Computed: true,
},
"total_iops_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
"write_bytes_sec": {
Type: schema.TypeInt,
Computed: true,
},
"write_bytes_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
"write_iops_sec": {
Type: schema.TypeInt,
Computed: true,
},
"write_iops_sec_max": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
"iqn": {
Type: schema.TypeString,
@@ -254,7 +330,7 @@ func dataSourceDiskListSchemaMake() map[string]*schema.Schema {
Type: schema.TypeInt,
Computed: true,
},
"name": {
"disk_name": {
Type: schema.TypeString,
Computed: true,
},
@@ -374,10 +450,6 @@ func dataSourceDiskListSchemaMake() map[string]*schema.Schema {
Type: schema.TypeInt,
Computed: true,
},
"update_by": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},

View File

@@ -31,7 +31,7 @@ Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
package disks
type DiskRecord struct {
type Disk struct {
Acl map[string]interface{} `json:"acl"`
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
@@ -49,7 +49,7 @@ type DiskRecord struct {
ID uint `json:"id"`
ImageID int `json:"imageId"`
Images []int `json:"images"`
IOTune map[string]interface{} `json:"iotune"`
IOTune IOTune `json:"iotune"`
IQN string `json:"iqn"`
Login string `json:"login"`
Name string `json:"name"`
@@ -73,7 +73,7 @@ type DiskRecord struct {
SepID int `json:"sepId"` // NOTE: absent from compute/get output
SizeMax int `json:"sizeMax"`
SizeUsed int `json:"sizeUsed"` // sum over all snapshots of this disk to report total consumed space
Snapshots []SnapshotRecord `json:"snapshots"`
Snapshots []Snapshot `json:"snapshots"`
Status string `json:"status"`
TechStatus string `json:"techStatus"`
Type string `json:"type"`
@@ -81,7 +81,7 @@ type DiskRecord struct {
VMID int `json:"vmid"`
}
type SnapshotRecord struct {
type Snapshot struct {
Guid string `json:"guid"`
Label string `json:"label"`
ResId string `json:"resId"`
@@ -90,6 +90,22 @@ type SnapshotRecord struct {
TimeStamp uint64 `json:"timestamp"`
}
type SnapshotRecordList []SnapshotRecord
type SnapshotList []Snapshot
type DisksListResp []DiskRecord
type DisksList []Disk
type IOTune struct {
ReadBytesSec int `json:"read_bytes_sec"`
ReadBytesSecMax int `json:"read_bytes_sec_max"`
ReadIopsSec int `json:"read_iops_sec"`
ReadIopsSecMax int `json:"read_iops_sec_max"`
SizeIopsSec int `json:"size_iops_sec"`
TotalBytesSec int `json:"total_bytes_sec"`
TotalBytesSecMax int `json:"total_bytes_sec_max"`
TotalIopsSec int `json:"total_iops_sec"`
TotalIopsSecMax int `json:"total_iops_sec_max"`
WriteBytesSec int `json:"write_bytes_sec"`
WriteBytesSecMax int `json:"write_bytes_sec_max"`
WriteIopsSec int `json:"write_iops_sec"`
WriteIopsSecMax int `json:"write_iops_sec_max"`
}

View File

@@ -32,15 +32,15 @@ Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
package disks
import (
// "encoding/json"
"context"
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
"github.com/rudecs/terraform-provider-decort/internal/constants"
"github.com/rudecs/terraform-provider-decort/internal/controller"
"github.com/rudecs/terraform-provider-decort/internal/location"
log "github.com/sirupsen/logrus"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -49,16 +49,18 @@ import (
)
func resourceDiskCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceDiskCreate: called for Disk name %q, Account ID %d", d.Get("name").(string), d.Get("account_id").(int))
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
// accountId, gid, name, description, size, type, sep_id, pool
urlValues.Add("accountId", fmt.Sprintf("%d", d.Get("account_id").(int)))
urlValues.Add("gid", fmt.Sprintf("%d", location.DefaultGridID)) // we use default Grid ID, which was obtained along with DECORT Controller init
urlValues.Add("name", d.Get("name").(string))
urlValues.Add("size", fmt.Sprintf("%d", d.Get("size").(int)))
urlValues.Add("type", "D") // NOTE: only disks of Data type are managed via plugin
urlValues.Add("gid", fmt.Sprintf("%d", d.Get("gid").(int)))
urlValues.Add("name", d.Get("disk_name").(string))
urlValues.Add("size", fmt.Sprintf("%d", d.Get("size_max").(int)))
if typeRaw, ok := d.GetOk("type"); ok {
urlValues.Add("type", strings.ToUpper(typeRaw.(string)))
} else {
urlValues.Add("type", "D")
}
if sepId, ok := d.GetOk("sep_id"); ok {
urlValues.Add("sep_id", strconv.Itoa(sepId.(int)))
@@ -68,126 +70,210 @@ func resourceDiskCreate(ctx context.Context, d *schema.ResourceData, m interface
urlValues.Add("pool", poolName.(string))
}
argVal, argSet := d.GetOk("description")
argVal, argSet := d.GetOk("desc")
if argSet {
urlValues.Add("description", argVal.(string))
}
apiResp, err := c.DecortAPICall(ctx, "POST", DisksCreateAPI, urlValues)
diskId, err := c.DecortAPICall(ctx, "POST", disksCreateAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
d.SetId(apiResp) // update ID of the resource to tell Terraform that the disk resource exists
diskId, _ := strconv.Atoi(apiResp)
urlValues = &url.Values{}
log.Debugf("resourceDiskCreate: new Disk ID / name %d / %s creation sequence complete", diskId, d.Get("name").(string))
d.SetId(diskId) // update ID of the resource to tell Terraform that the disk resource exists
// We may reuse dataSourceDiskRead here as we maintain similarity
// between Disk resource and Disk data source schemas
// Disk resource read function will also update resource ID on success, so that Terraform
// will know the resource exists (however, we already did it a few lines before)
return dataSourceDiskRead(ctx, d, m)
if iotuneRaw, ok := d.GetOk("iotune"); ok {
iot := iotuneRaw.([]interface{})[0]
iotune := iot.(map[string]interface{})
urlValues.Add("diskId", diskId)
urlValues.Add("iops", strconv.Itoa(iotune["total_iops_sec"].(int)))
urlValues.Add("read_bytes_sec", strconv.Itoa(iotune["read_bytes_sec"].(int)))
urlValues.Add("read_bytes_sec_max", strconv.Itoa(iotune["read_bytes_sec_max"].(int)))
urlValues.Add("read_iops_sec", strconv.Itoa(iotune["read_iops_sec"].(int)))
urlValues.Add("read_iops_sec_max", strconv.Itoa(iotune["read_iops_sec_max"].(int)))
urlValues.Add("size_iops_sec", strconv.Itoa(iotune["size_iops_sec"].(int)))
urlValues.Add("total_bytes_sec", strconv.Itoa(iotune["total_bytes_sec"].(int)))
urlValues.Add("total_bytes_sec_max", strconv.Itoa(iotune["total_bytes_sec_max"].(int)))
urlValues.Add("total_iops_sec_max", strconv.Itoa(iotune["total_iops_sec_max"].(int)))
urlValues.Add("write_bytes_sec", strconv.Itoa(iotune["write_bytes_sec"].(int)))
urlValues.Add("write_bytes_sec_max", strconv.Itoa(iotune["write_bytes_sec_max"].(int)))
urlValues.Add("write_iops_sec", strconv.Itoa(iotune["write_iops_sec"].(int)))
urlValues.Add("write_iops_sec_max", strconv.Itoa(iotune["write_iops_sec_max"].(int)))
_, err := c.DecortAPICall(ctx, "POST", disksIOLimitAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
urlValues = &url.Values{}
}
dgn := resourceDiskRead(ctx, d, m)
if dgn != nil {
return dgn
}
return nil
}
func resourceDiskRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
diskFacts, err := utilityDiskCheckPresence(ctx, d, m)
if diskFacts == "" {
// if empty string is returned from utilityDiskCheckPresence then there is no
// such Disk and err tells so - just return it to the calling party
d.SetId("") // ensure ID is empty
return diag.FromErr(err)
disk, err := utilityDiskCheckPresence(ctx, d, m)
if disk == nil {
d.SetId("")
if err != nil {
return diag.FromErr(err)
}
return nil
}
return diag.FromErr(flattenDisk(d, diskFacts))
diskAcl, _ := json.Marshal(disk.Acl)
d.Set("account_id", disk.AccountID)
d.Set("account_name", disk.AccountName)
d.Set("acl", string(diskAcl))
d.Set("boot_partition", disk.BootPartition)
d.Set("compute_id", disk.ComputeID)
d.Set("compute_name", disk.ComputeName)
d.Set("created_time", disk.CreatedTime)
d.Set("deleted_time", disk.DeletedTime)
d.Set("desc", disk.Desc)
d.Set("destruction_time", disk.DestructionTime)
d.Set("devicename", disk.DeviceName)
d.Set("disk_path", disk.DiskPath)
d.Set("gid", disk.GridID)
d.Set("guid", disk.GUID)
d.Set("disk_id", disk.ID)
d.Set("image_id", disk.ImageID)
d.Set("images", disk.Images)
d.Set("iotune", flattenIOTune(disk.IOTune))
d.Set("iqn", disk.IQN)
d.Set("login", disk.Login)
d.Set("milestones", disk.Milestones)
d.Set("disk_name", disk.Name)
d.Set("order", disk.Order)
d.Set("params", disk.Params)
d.Set("parent_id", disk.ParentId)
d.Set("passwd", disk.Passwd)
d.Set("pci_slot", disk.PciSlot)
d.Set("pool", disk.Pool)
d.Set("purge_attempts", disk.PurgeAttempts)
d.Set("purge_time", disk.PurgeTime)
d.Set("reality_device_number", disk.RealityDeviceNumber)
d.Set("reference_id", disk.ReferenceId)
d.Set("res_id", disk.ResID)
d.Set("res_name", disk.ResName)
d.Set("role", disk.Role)
d.Set("sep_id", disk.SepID)
d.Set("sep_type", disk.SepType)
d.Set("size_max", disk.SizeMax)
d.Set("size_used", disk.SizeUsed)
d.Set("snapshots", flattendDiskSnapshotList(disk.Snapshots))
d.Set("status", disk.Status)
d.Set("tech_status", disk.TechStatus)
d.Set("type", disk.Type)
d.Set("vmid", disk.VMID)
return nil
}
func resourceDiskUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
// Update will only change the following attributes of the disk:
// - Size; to keep data safe, shrinking disk is not allowed.
// - Name
//
// Attempt to change disk type will throw an error and mark disk
// resource as partially updated
log.Debugf("resourceDiskUpdate: called for Disk ID / name %s / %s, Account ID %d",
d.Id(), d.Get("name").(string), d.Get("account_id").(int))
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
oldSize, newSize := d.GetChange("size")
if oldSize.(int) < newSize.(int) {
log.Debugf("resourceDiskUpdate: resizing disk ID %s - %d GB -> %d GB",
d.Id(), oldSize.(int), newSize.(int))
sizeParams := &url.Values{}
sizeParams.Add("diskId", d.Id())
sizeParams.Add("size", fmt.Sprintf("%d", newSize.(int)))
_, err := c.DecortAPICall(ctx, "POST", DisksResizeAPI, sizeParams)
if d.HasChange("size_max") {
oldSize, newSize := d.GetChange("size_max")
if oldSize.(int) < newSize.(int) {
log.Debugf("resourceDiskUpdate: resizing disk ID %s - %d GB -> %d GB",
d.Id(), oldSize.(int), newSize.(int))
urlValues.Add("diskId", d.Id())
urlValues.Add("size", fmt.Sprintf("%d", newSize.(int)))
_, err := c.DecortAPICall(ctx, "POST", disksResizeAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
d.Set("size_max", newSize)
} else if oldSize.(int) > newSize.(int) {
return diag.FromErr(fmt.Errorf("resourceDiskUpdate: Disk ID %s - reducing disk size is not allowed", d.Id()))
}
urlValues = &url.Values{}
}
if d.HasChange("disk_name") {
urlValues.Add("diskId", d.Id())
urlValues.Add("name", d.Get("disk_name").(string))
_, err := c.DecortAPICall(ctx, "POST", disksRenameAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
d.Set("size", newSize)
} else if oldSize.(int) > newSize.(int) {
return diag.FromErr(fmt.Errorf("resourceDiskUpdate: Disk ID %s - reducing disk size is not allowed", d.Id()))
urlValues = &url.Values{}
}
oldName, newName := d.GetChange("name")
if oldName.(string) != newName.(string) {
log.Debugf("resourceDiskUpdate: renaming disk ID %d - %s -> %s",
d.Get("disk_id").(int), oldName.(string), newName.(string))
renameParams := &url.Values{}
renameParams.Add("diskId", d.Id())
renameParams.Add("name", newName.(string))
_, err := c.DecortAPICall(ctx, "POST", DisksRenameAPI, renameParams)
if d.HasChange("iotune") {
iot := d.Get("iotune").([]interface{})[0]
iotune := iot.(map[string]interface{})
urlValues.Add("diskId", d.Id())
urlValues.Add("iops", strconv.Itoa(iotune["total_iops_sec"].(int)))
urlValues.Add("read_bytes_sec", strconv.Itoa(iotune["read_bytes_sec"].(int)))
urlValues.Add("read_bytes_sec_max", strconv.Itoa(iotune["read_bytes_sec_max"].(int)))
urlValues.Add("read_iops_sec", strconv.Itoa(iotune["read_iops_sec"].(int)))
urlValues.Add("read_iops_sec_max", strconv.Itoa(iotune["read_iops_sec_max"].(int)))
urlValues.Add("size_iops_sec", strconv.Itoa(iotune["size_iops_sec"].(int)))
urlValues.Add("total_bytes_sec", strconv.Itoa(iotune["total_bytes_sec"].(int)))
urlValues.Add("total_bytes_sec_max", strconv.Itoa(iotune["total_bytes_sec_max"].(int)))
urlValues.Add("total_iops_sec_max", strconv.Itoa(iotune["total_iops_sec_max"].(int)))
urlValues.Add("write_bytes_sec", strconv.Itoa(iotune["write_bytes_sec"].(int)))
urlValues.Add("write_bytes_sec_max", strconv.Itoa(iotune["write_bytes_sec_max"].(int)))
urlValues.Add("write_iops_sec", strconv.Itoa(iotune["write_iops_sec"].(int)))
urlValues.Add("write_iops_sec_max", strconv.Itoa(iotune["write_iops_sec_max"].(int)))
_, err := c.DecortAPICall(ctx, "POST", disksIOLimitAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
urlValues = &url.Values{}
}
/*
NOTE: plugin will manage disks of type "Data" only, and type cannot be changed once disk is created
if d.HasChange("restore") {
if d.Get("restore").(bool) {
urlValues.Add("diskId", d.Id())
urlValues.Add("reason", d.Get("reason").(string))
oldType, newType := d.GetChange("type")
if oldType.(string) != newType.(string) {
return fmt.Errorf("resourceDiskUpdate: Disk ID %s - changing type of existing disk not allowed", d.Id())
_, err := c.DecortAPICall(ctx, "POST", disksRestoreAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
urlValues = &url.Values{}
}
*/
// we may reuse dataSourceDiskRead here as we maintain similarity
// between Compute resource and Compute data source schemas
return dataSourceDiskRead(ctx, d, m)
}
return resourceDiskRead(ctx, d, m)
}
func resourceDiskDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
// NOTE: this function tries to detach and destroy target Disk "permanently", so
// there is no way to restore it.
// If, however, the disk is attached to a compute, the method will
// fail (by failing the underpinning DECORt API call, which is issued with detach=false)
log.Debugf("resourceDiskDelete: called for Disk ID / name %d / %s, Account ID %d",
d.Get("disk_id").(int), d.Get("name").(string), d.Get("account_id").(int))
diskFacts, err := utilityDiskCheckPresence(ctx, d, m)
if diskFacts == "" {
disk, err := utilityDiskCheckPresence(ctx, d, m)
if disk == nil {
if err != nil {
return diag.FromErr(err)
}
// the specified Disk does not exist - in this case according to Terraform best practice
// we exit from Destroy method without error
return nil
}
params := &url.Values{}
params.Add("diskId", d.Id())
// NOTE: we are not force-detaching disk from a compute (if attached) thus protecting
// data that may be on that disk from destruction.
// However, this may change in the future, as TF state management logic may want
// to delete disk resource BEFORE it is detached from compute instance, and, while
// perfectly OK from data preservation viewpoint, this is breaking expected TF workflow
// in the eyes of an experienced TF user
params.Add("detach", "0")
params.Add("permanently", "1")
params.Add("detach", strconv.FormatBool(d.Get("detach").(bool)))
params.Add("permanently", strconv.FormatBool(d.Get("permanently").(bool)))
params.Add("reason", d.Get("reason").(string))
c := m.(*controller.ControllerCfg)
_, err = c.DecortAPICall(ctx, "POST", DisksDeleteAPI, params)
_, err = c.DecortAPICall(ctx, "POST", disksDeleteAPI, params)
if err != nil {
return diag.FromErr(err)
}
@@ -196,12 +282,9 @@ func resourceDiskDelete(ctx context.Context, d *schema.ResourceData, m interface
}
func resourceDiskExists(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
// Reminder: according to Terraform rules, this function should not modify its ResourceData argument
log.Debugf("resourceDiskExists: called for Disk ID / name %d / %s, Account ID %d",
d.Get("disk_id").(int), d.Get("name").(string), d.Get("account_id").(int))
diskFacts, err := utilityDiskCheckPresence(ctx, d, m)
if diskFacts == "" {
if diskFacts == nil {
if err != nil {
return false, err
}
@@ -212,101 +295,318 @@ func resourceDiskExists(ctx context.Context, d *schema.ResourceData, m interface
func resourceDiskSchemaMake() map[string]*schema.Schema {
rets := map[string]*schema.Schema{
"name": {
"account_id": {
Type: schema.TypeInt,
Required: true,
},
"disk_name": {
Type: schema.TypeString,
Required: true,
},
"size_max": {
Type: schema.TypeInt,
Required: true,
},
"gid": {
Type: schema.TypeInt,
Required: true,
},
"pool": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"sep_id": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"desc": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice([]string{"D", "B", "T"}, false),
},
"detach": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "detach disk from machine first",
},
"permanently": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "whether to completely delete the disk, works only with non attached disks",
},
"reason": {
Type: schema.TypeString,
Required: true,
Description: "Name of this disk. NOTE: disk names are NOT unique within an account. If disk ID is specified, disk name is ignored.",
Optional: true,
Default: "",
Description: "reason for an action",
},
"restore": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "restore deleting disk",
},
"disk_id": {
Type: schema.TypeInt,
Optional: true,
Description: "ID of the disk to get. If disk ID is specified, then disk name and account ID are ignored.",
Type: schema.TypeInt,
Computed: true,
},
"account_id": {
Type: schema.TypeInt,
Required: true,
Description: "ID of the account this disk belongs to.",
},
"sep_id": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ForceNew: true,
Description: "Storage end-point provider serving this disk. Cannot be changed for existing disk.",
},
"pool": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
Description: "Pool where this disk is located. Cannot be changed for existing disk.",
},
"size": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntAtLeast(1),
Description: "Size of the disk in GB. Note, that existing disks can only be grown in size.",
},
/* We moved "type" attribute to computed attributes section, as plugin manages disks of only
one type - "D", e.g. data disks.
"type": {
Type: schema.TypeString,
Optional: true,
Default: "D",
StateFunc: stateFuncToUpper,
ValidateFunc: validation.StringInSlice([]string{"B", "D"}, false),
Description: "Optional type of this disk. Defaults to D, i.e. data disk. Cannot be changed for existing disks.",
},
*/
"description": {
Type: schema.TypeString,
Optional: true,
Default: "Disk resource managed by Terraform",
Description: "Optional user-defined text description of this disk.",
},
// The rest of the attributes are all computed
"account_name": {
Type: schema.TypeString,
Computed: true,
Description: "Name of the account this disk belongs to.",
Type: schema.TypeString,
Computed: true,
},
"acl": {
Type: schema.TypeString,
Computed: true,
},
"boot_partition": {
Type: schema.TypeInt,
Computed: true,
},
"compute_id": {
Type: schema.TypeInt,
Computed: true,
},
"compute_name": {
Type: schema.TypeString,
Computed: true,
},
"created_time": {
Type: schema.TypeInt,
Computed: true,
},
"deleted_time": {
Type: schema.TypeInt,
Computed: true,
},
"destruction_time": {
Type: schema.TypeInt,
Computed: true,
},
"devicename": {
Type: schema.TypeString,
Computed: true,
},
"disk_path": {
Type: schema.TypeString,
Computed: true,
},
"guid": {
Type: schema.TypeInt,
Computed: true,
},
"image_id": {
Type: schema.TypeInt,
Computed: true,
Description: "ID of the image, which this disk was cloned from (if ever cloned).",
Type: schema.TypeInt,
Computed: true,
},
"images": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"iotune": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"read_bytes_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"read_bytes_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"read_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"read_iops_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"size_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_bytes_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_bytes_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_iops_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_bytes_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_bytes_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_iops_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
},
},
},
"iqn": {
Type: schema.TypeString,
Computed: true,
},
"login": {
Type: schema.TypeString,
Computed: true,
},
"milestones": {
Type: schema.TypeInt,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
Description: "Type of this disk.",
"order": {
Type: schema.TypeInt,
Computed: true,
},
"params": {
Type: schema.TypeString,
Computed: true,
},
"parent_id": {
Type: schema.TypeInt,
Computed: true,
},
"passwd": {
Type: schema.TypeString,
Computed: true,
},
"pci_slot": {
Type: schema.TypeInt,
Computed: true,
},
"purge_attempts": {
Type: schema.TypeInt,
Computed: true,
},
"purge_time": {
Type: schema.TypeInt,
Computed: true,
},
"reality_device_number": {
Type: schema.TypeInt,
Computed: true,
},
"reference_id": {
Type: schema.TypeString,
Computed: true,
},
"res_id": {
Type: schema.TypeString,
Computed: true,
},
"res_name": {
Type: schema.TypeString,
Computed: true,
},
"role": {
Type: schema.TypeString,
Computed: true,
},
"sep_type": {
Type: schema.TypeString,
Computed: true,
Description: "Type of the storage end-point provider serving this disk.",
Type: schema.TypeString,
Computed: true,
},
/*
"snapshots": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource {
Schema: snapshotSubresourceSchemaMake(),
"size_used": {
Type: schema.TypeInt,
Computed: true,
},
"snapshots": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"guid": {
Type: schema.TypeString,
Computed: true,
},
"label": {
Type: schema.TypeString,
Computed: true,
},
"res_id": {
Type: schema.TypeString,
Computed: true,
},
"snap_set_guid": {
Type: schema.TypeString,
Computed: true,
},
"snap_set_time": {
Type: schema.TypeInt,
Computed: true,
},
"timestamp": {
Type: schema.TypeInt,
Computed: true,
},
},
Description: "List of user-created snapshots for this disk."
},
*/
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"tech_status": {
Type: schema.TypeString,
Computed: true,
},
"vmid": {
Type: schema.TypeInt,
Computed: true,
},
}
return rets

View File

@@ -34,7 +34,6 @@ package disks
import (
"context"
"encoding/json"
"fmt"
"net/url"
"strconv"
@@ -44,103 +43,28 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func utilityDiskCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (string, error) {
// This function tries to locate Disk by one of the following algorithms depending on
// the parameters passed:
// - if disk ID is specified -> by disk ID
// - if disk name is specifeid -> by disk name and either account ID or account name
//
// NOTE: disk names are not unique, so the first occurence of this name in the account will
// be returned. There is no such ambiguity when locating disk by its ID.
//
// If succeeded, it returns non empty string that contains JSON formatted facts about the disk
// as returned by disks/get API call.
// Otherwise it returns empty string and meaningful error.
//
// This function does not modify its ResourceData argument, so it is safe to use it as core
// method for resource's Exists method.
//
func utilityDiskCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (*Disk, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
// make it possible to use "read" & "check presence" functions with disk ID set so
// that Import of preexisting Disk resource is possible
idSet := false
theId, err := strconv.Atoi(d.Id())
if err != nil || theId <= 0 {
diskId, argSet := d.GetOk("disk_id")
if argSet {
theId = diskId.(int)
idSet = true
}
disk := &Disk{}
if d.Get("disk_id").(int) == 0 {
urlValues.Add("diskId", d.Id())
} else {
idSet = true
urlValues.Add("diskId", strconv.Itoa(d.Get("disk_id").(int)))
}
if idSet {
// disk ID is specified, try to get disk instance straight by this ID
log.Debugf("utilityDiskCheckPresence: locating disk by its ID %d", theId)
urlValues.Add("diskId", fmt.Sprintf("%d", theId))
diskFacts, err := c.DecortAPICall(ctx, "POST", DisksGetAPI, urlValues)
if err != nil {
return "", err
}
return diskFacts, nil
}
// ID or disk_di was not set in the schema upon entering this function - rely on Disk name
// and Account ID to find the disk
diskName, argSet := d.GetOk("name")
if !argSet {
// no disk ID and no disk name - we cannot locate disk in this case
return "", fmt.Errorf("Cannot locate disk if name is empty and no disk ID specified")
}
// Valid account ID is required to locate disks
// obtain Account ID by account name - it should not be zero on success
urlValues.Add("accountId", fmt.Sprintf("%d", d.Get("account_id").(int)))
diskFacts, err := c.DecortAPICall(ctx, "POST", DisksListAPI, urlValues)
log.Debugf("utilityDiskCheckPresence: load disk")
diskRaw, err := c.DecortAPICall(ctx, "POST", disksGetAPI, urlValues)
if err != nil {
return "", err
return nil, err
}
log.Debugf("utilityDiskCheckPresence: ready to unmarshal string %s", diskFacts)
disksList := DisksListResp{}
err = json.Unmarshal([]byte(diskFacts), &disksList)
err = json.Unmarshal([]byte(diskRaw), disk)
if err != nil {
return "", err
return nil, err
}
// log.Printf("%#v", vm_list)
log.Debugf("utilityDiskCheckPresence: traversing decoded JSON of length %d", len(disksList))
for index, item := range disksList {
// need to match disk by name, return the first match
if item.Name == diskName.(string) && item.Status != "DESTROYED" {
log.Debugf("utilityDiskCheckPresence: index %d, matched disk name %q", index, item.Name)
// we found the disk we need - not get detailed information via API call to disks/get
/*
// TODO: this may not be optimal as it initiates one extra call to the DECORT controller
// in spite of the fact that we already have all required information about the disk in
// item variable
//
get_urlValues := &url.Values{}
get_urlValues.Add("diskId", fmt.Sprintf("%d", item.ID))
diskFacts, err = controller.decortAPICall("POST", DisksGetAPI, get_urlValues)
if err != nil {
return "", err
}
return diskFacts, nil
*/
reencodedItem, err := json.Marshal(item)
if err != nil {
return "", err
}
return string(reencodedItem[:]), nil
}
}
return "", nil // there should be no error if disk does not exist
return disk, nil
}

View File

@@ -44,8 +44,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func utilityDiskListCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (DisksListResp, error) {
diskList := DisksListResp{}
func utilityDiskListCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (DisksList, error) {
diskList := DisksList{}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
@@ -62,8 +62,8 @@ func utilityDiskListCheckPresence(ctx context.Context, d *schema.ResourceData, m
urlValues.Add("accountId", strconv.Itoa(accountId.(int)))
}
log.Debugf("utilityDiskListCheckPresence: load grid list")
diskListRaw, err := c.DecortAPICall(ctx, "POST", DisksListAPI, urlValues)
log.Debugf("utilityDiskListCheckPresence: load disk list")
diskListRaw, err := c.DecortAPICall(ctx, "POST", disksListAPI, urlValues)
if err != nil {
return nil, err
}

View File

@@ -0,0 +1,40 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
const imageCreateAPI = "/restmachine/cloudapi/image/createImage"
const imageCreateVirtualAPI = "/restmachine/cloudapi/image/createVirtual"
const imageGetAPI = "/restmachine/cloudapi/image/get"
const imageListGetAPI = "/restmachine/cloudapi/image/list"
const imageDeleteAPI = "/restmachine/cloudapi/image/delete"
const imageEditNameAPI = "/restmachine/cloudapi/image/rename"
const imageLinkAPI = "/restmachine/cloudapi/image/link"

View File

@@ -0,0 +1,123 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
import (
"context"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/rudecs/terraform-provider-decort/internal/constants"
)
func flattenHistory(history []History) []map[string]interface{} {
temp := make([]map[string]interface{}, 0)
for _, item := range history {
t := map[string]interface{}{
"id": item.Id,
"guid": item.Guid,
"timestamp": item.Timestamp,
}
temp = append(temp, t)
}
return temp
}
func flattenImage(d *schema.ResourceData, img *ImageExtend) {
d.Set("unc_path", img.UNCPath)
d.Set("ckey", img.CKey)
d.Set("account_id", img.AccountId)
d.Set("acl", img.Acl)
d.Set("architecture", img.Architecture)
d.Set("boot_type", img.BootType)
d.Set("bootable", img.Bootable)
d.Set("compute_ci_id", img.ComputeCiId)
d.Set("deleted_time", img.DeletedTime)
d.Set("desc", img.Description)
d.Set("drivers", img.Drivers)
d.Set("enabled", img.Enabled)
d.Set("gid", img.GridId)
d.Set("guid", img.GUID)
d.Set("history", flattenHistory(img.History))
d.Set("hot_resize", img.HotResize)
d.Set("image_id", img.Id)
d.Set("last_modified", img.LastModified)
d.Set("link_to", img.LinkTo)
d.Set("milestones", img.Milestones)
d.Set("image_name", img.Name)
d.Set("password", img.Password)
d.Set("pool_name", img.Pool)
d.Set("provider_name", img.ProviderName)
d.Set("purge_attempts", img.PurgeAttempts)
d.Set("res_id", img.ResId)
d.Set("rescuecd", img.RescueCD)
d.Set("sep_id", img.SepId)
d.Set("shared_with", img.SharedWith)
d.Set("size", img.Size)
d.Set("status", img.Status)
d.Set("tech_status", img.TechStatus)
d.Set("type", img.Type)
d.Set("username", img.Username)
d.Set("version", img.Version)
}
func dataSourceImageRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
image, err := utilityImageCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(id.String())
flattenImage(d, image)
return nil
}
func DataSourceImage() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
ReadContext: dataSourceImageRead,
Timeouts: &schema.ResourceTimeout{
Read: &constants.Timeout30s,
Default: &constants.Timeout60s,
},
Schema: dataSourceImageExtendSchemaMake(),
}
}

View File

@@ -0,0 +1,126 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
import (
"context"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/rudecs/terraform-provider-decort/internal/constants"
)
func flattenImageList(il ImageList) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, img := range il {
temp := map[string]interface{}{
"account_id": img.AccountId,
"architecture": img.Architecture,
"boot_type": img.BootType,
"bootable": img.Bootable,
"cdrom": img.CDROM,
"desc": img.Description,
"drivers": img.Drivers,
"hot_resize": img.HotResize,
"image_id": img.Id,
"link_to": img.LinkTo,
"image_name": img.Name,
"pool_name": img.Pool,
"sep_id": img.SepId,
"size": img.Size,
"status": img.Status,
"type": img.Type,
"username": img.Username,
"virtual": img.Virtual,
}
res = append(res, temp)
}
return res
}
func dataSourceImageListRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
imageList, err := utilityImageListCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(id.String())
d.Set("items", flattenImageList(imageList))
return nil
}
func dataSourceImageListSchemaMake() map[string]*schema.Schema {
rets := map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Optional: true,
Description: "optional account ID to include account images",
},
"page": {
Type: schema.TypeInt,
Optional: true,
Description: "page number",
},
"size": {
Type: schema.TypeInt,
Optional: true,
Description: "page size",
},
"items": {
Type: schema.TypeList,
Computed: true,
Description: "image list",
Elem: &schema.Resource{
Schema: dataSourceImageSchemaMake(),
},
},
}
return rets
}
func DataSourceImageList() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
ReadContext: dataSourceImageListRead,
Timeouts: &schema.ResourceTimeout{
Read: &constants.Timeout30s,
Default: &constants.Timeout60s,
},
Schema: dataSourceImageListSchemaMake(),
}
}

View File

@@ -0,0 +1,208 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
func dataSourceImageExtendSchemaMake() map[string]*schema.Schema {
return map[string]*schema.Schema{
"image_id": {
Type: schema.TypeInt,
Required: true,
},
"show_all": {
Type: schema.TypeBool,
Default: false,
Optional: true,
},
"unc_path": {
Type: schema.TypeString,
Computed: true,
},
"ckey": {
Type: schema.TypeString,
Computed: true,
},
"account_id": {
Type: schema.TypeInt,
Computed: true,
},
"acl": {
Type: schema.TypeString,
Computed: true,
},
"architecture": {
Type: schema.TypeString,
Computed: true,
},
"boot_type": {
Type: schema.TypeString,
Computed: true,
},
"bootable": {
Type: schema.TypeBool,
Computed: true,
},
"compute_ci_id": {
Type: schema.TypeInt,
Computed: true,
},
"deleted_time": {
Type: schema.TypeString,
Computed: true,
},
"desc": {
Type: schema.TypeString,
Computed: true,
},
"drivers": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"enabled": {
Type: schema.TypeBool,
Computed: true,
},
"gid": {
Type: schema.TypeInt,
Computed: true,
},
"guid": {
Type: schema.TypeInt,
Computed: true,
},
"history": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"guid": {
Type: schema.TypeString,
Computed: true,
},
"id": {
Type: schema.TypeInt,
Computed: true,
},
"timestamp": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
"hot_resize": {
Type: schema.TypeBool,
Computed: true,
},
"last_modified": {
Type: schema.TypeInt,
Computed: true,
},
"link_to": {
Type: schema.TypeInt,
Computed: true,
},
"milestones": {
Type: schema.TypeInt,
Computed: true,
},
"image_name": {
Type: schema.TypeString,
Computed: true,
},
"password": {
Type: schema.TypeString,
Computed: true,
},
"pool_name": {
Type: schema.TypeString,
Computed: true,
},
"provider_name": {
Type: schema.TypeString,
Computed: true,
},
"purge_attempts": {
Type: schema.TypeInt,
Computed: true,
},
"res_id": {
Type: schema.TypeString,
Computed: true,
},
"rescuecd": {
Type: schema.TypeBool,
Computed: true,
},
"sep_id": {
Type: schema.TypeInt,
Computed: true,
},
"shared_with": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
},
"size": {
Type: schema.TypeInt,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"tech_status": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
"username": {
Type: schema.TypeString,
Computed: true,
},
"version": {
Type: schema.TypeString,
Computed: true,
},
}
}

View File

@@ -0,0 +1,132 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
func dataSourceImageSchemaMake() map[string]*schema.Schema {
return map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Owner account id",
},
"architecture": {
Type: schema.TypeString,
Computed: true,
Description: "Image architecture",
},
"boot_type": {
Type: schema.TypeString,
Computed: true,
Description: "Boot image type",
},
"bootable": {
Type: schema.TypeBool,
Computed: true,
Description: "Flag, true if image is bootable, otherwise - false",
},
"cdrom": {
Type: schema.TypeBool,
Computed: true,
Description: "Flag, true if image is cdrom image, otherwise - false",
},
"desc": {
Type: schema.TypeString,
Computed: true,
Description: "Image description",
},
"drivers": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Description: "Image drivers",
},
"hot_resize": {
Type: schema.TypeBool,
Computed: true,
Description: "Flag, true if image supports hot resize, else if not",
},
"image_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Image id",
},
"link_to": {
Type: schema.TypeInt,
Computed: true,
Description: "For virtual images, id image, which current image linked",
},
"image_name": {
Type: schema.TypeString,
Computed: true,
Description: "Image name",
},
"pool_name": {
Type: schema.TypeString,
Computed: true,
Description: "Image pool",
},
"sep_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Image storage endpoint id",
},
"size": {
Type: schema.TypeInt,
Computed: true,
Description: "Image size",
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: "Image status",
},
"type": {
Type: schema.TypeString,
Computed: true,
Description: "Image type",
},
"username": {
Type: schema.TypeString,
Computed: true,
Description: "username",
},
"virtual": {
Type: schema.TypeBool,
Computed: true,
Description: "True if image is virtula, otherwise - else",
},
}
}

View File

@@ -0,0 +1,158 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
func resourceImageSchemaMake(sch map[string]*schema.Schema) map[string]*schema.Schema {
delete(sch, "show_all")
sch["name"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "Name of the rescue disk",
}
sch["url"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "URL where to download media from",
}
sch["gid"] = &schema.Schema{
Type: schema.TypeInt,
Required: true,
Description: "grid (platform) ID where this template should be create in",
}
sch["image_id"] = &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Computed: true,
Description: "image id",
}
sch["boot_type"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"bios", "uefi"}, true),
Description: "Boot type of image bios or uefi",
}
sch["type"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"linux", "windows", "other"}, true),
Description: "Image type linux, windows or other",
}
sch["hot_resize"] = &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Computed: true,
Description: "Does this machine supports hot resize",
}
sch["username"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "Optional username for the image",
}
sch["password"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "Optional password for the image",
}
sch["account_id"] = &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Computed: true,
Description: "AccountId to make the image exclusive",
}
sch["username_dl"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "username for upload binary media",
}
sch["password_dl"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "password for upload binary media",
}
sch["pool_name"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "pool for image create",
}
sch["sep_id"] = &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Computed: true,
Description: "storage endpoint provider ID",
}
sch["architecture"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice([]string{"X86_64", "PPC64_LE"}, true),
Description: "binary architecture of this image, one of X86_64 of PPC64_LE",
}
sch["drivers"] = &schema.Schema{
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
}
sch["permanently"] = &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "whether to completely delete the image",
}
return sch
}

View File

@@ -0,0 +1,66 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func resourceImageVirtualSchemaMake(sch map[string]*schema.Schema) map[string]*schema.Schema {
delete(sch, "show_all")
sch["name"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "Name of the rescue disk",
}
sch["link_to"] = &schema.Schema{
Type: schema.TypeInt,
Required: true,
Description: "ID of real image to link this virtual image to upon creation",
}
sch["permanently"] = &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "whether to completely delete the image",
}
sch["image_id"] = &schema.Schema{
Type: schema.TypeInt,
Computed: true,
Description: "Image id",
}
return sch
}

View File

@@ -0,0 +1,148 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
/*
type History struct {
Guid string `json:"guid"`
Id int `json:"id"`
Timestamp int64 `json:"timestamp"`
}
type Image struct {
ImageId int `json:"id"`
Name string `json:"name"`
Url string `json:"url"`
Gid int `json:"gid"`
Guid int `json:"guid"`
Boottype string `json:"bootType"`
Imagetype string `json:"type"`
Drivers []string `json:"drivers"`
Hotresize bool `json:"hotResize"`
Bootable bool `json:"bootable"`
Username string `json:"username"`
Password string `json:"password"`
AccountId int `json:"accountId"`
UsernameDL string `json:"usernameDL"`
PasswordDL string `json:"passwordDL"`
SepId int `json:"sepId"`
PoolName string `json:"pool"`
Architecture string `json:"architecture"`
UNCPath string `json:"UNCPath"`
LinkTo int `json:"linkTo"`
Status string `json:"status"`
TechStatus string `json:"techStatus"`
Size int `json:"size"`
Version string `json:"version"`
Enabled bool `json:"enabled"`
ComputeciId int `json:"computeciId"`
Milestones int `json:"milestones"`
ProviderName string `json:"provider_name"`
PurgeAttempts int `json:"purgeAttempts"`
ReferenceId string `json:"referenceId"`
ResId string `json:"resId"`
ResName string `json:"resName"`
Rescuecd bool `json:"rescuecd"`
Meta []interface{} `json:"_meta"`
History []History `json:"history"`
LastModified int64 `json:"lastModified"`
Desc string `json:"desc"`
SharedWith []int `json:"sharedWith"`
}
*/
type Image struct {
AccountId int `json:"accountId"`
Architecture string `json:"architecture"`
BootType string `json:"bootType"`
Bootable bool `json:"bootable"`
CDROM bool `json:"cdrom"`
Description string `json:"desc"`
Drivers []string `json:"drivers"`
HotResize bool `json:"hotResize"`
Id int `json:"id"`
LinkTo int `json:"linkTo"`
Name string `json:"name"`
Pool string `json:"pool"`
SepId int `json:"sepId"`
Size int `json:"size"`
Status string `json:"status"`
Type string `json:"type"`
Username string `json:"username"`
Virtual bool `json:"virtual"`
}
type ImageList []Image
type History struct {
Guid string `json:"guid"`
Id int `json:"id"`
Timestamp int64 `json:"timestamp"`
}
type ImageExtend struct {
UNCPath string `json:"UNCPath"`
CKey string `json:"_ckey"`
AccountId int `json:"accountId"`
Acl interface{} `json:"acl"`
Architecture string `json:"architecture"`
BootType string `json:"bootType"`
Bootable bool `json:"bootable"`
ComputeCiId int `json:"computeciId"`
DeletedTime int `json:"deletedTime"`
Description string `json:"desc"`
Drivers []string `json:"drivers"`
Enabled bool `json:"enabled"`
GridId int `json:"gid"`
GUID int `json:"guid"`
History []History `json:"history"`
HotResize bool `json:"hotResize"`
Id int `json:"id"`
LastModified int `json:"lastModified"`
LinkTo int `json:"linkTo"`
Milestones int `json:"milestones"`
Name string `json:"name"`
Password string `json:"password"`
Pool string `json:"pool"`
ProviderName string `json:"provider_name"`
PurgeAttempts int `json:"purgeAttempts"`
ResId string `json:"resId"`
RescueCD bool `json:"rescuecd"`
SepId int `json:"sepId"`
SharedWith []int `json:"sharedWith"`
Size int `json:"size"`
Status string `json:"status"`
TechStatus string `json:"techStatus"`
Type string `json:"type"`
Username string `json:"username"`
Version string `json:"version"`
}

View File

@@ -0,0 +1,259 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
import (
"context"
"net/url"
"strconv"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/rudecs/terraform-provider-decort/internal/constants"
"github.com/rudecs/terraform-provider-decort/internal/controller"
log "github.com/sirupsen/logrus"
)
func resourceImageCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceImageCreate: called for image %s", d.Get("name").(string))
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("name", d.Get("name").(string))
urlValues.Add("url", d.Get("url").(string))
urlValues.Add("gid", strconv.Itoa(d.Get("gid").(int)))
urlValues.Add("boottype", d.Get("boot_type").(string))
urlValues.Add("imagetype", d.Get("image_type").(string))
tstr := d.Get("drivers").([]interface{})
temp := ""
l := len(tstr)
for i, str := range tstr {
s := "\"" + str.(string) + "\""
if i != (l - 1) {
s += ","
}
temp = temp + s
}
temp = "[" + temp + "]"
urlValues.Add("drivers", temp)
if hotresize, ok := d.GetOk("hot_resize"); ok {
urlValues.Add("hotresize", strconv.FormatBool(hotresize.(bool)))
}
if username, ok := d.GetOk("username"); ok {
urlValues.Add("username", username.(string))
}
if password, ok := d.GetOk("password"); ok {
urlValues.Add("password", password.(string))
}
if accountId, ok := d.GetOk("account_id"); ok {
urlValues.Add("accountId", strconv.Itoa(accountId.(int)))
}
if usernameDL, ok := d.GetOk("username_dl"); ok {
urlValues.Add("usernameDL", usernameDL.(string))
}
if passwordDL, ok := d.GetOk("password_dl"); ok {
urlValues.Add("passwordDL", passwordDL.(string))
}
if sepId, ok := d.GetOk("sep_id"); ok {
urlValues.Add("sepId", strconv.Itoa(sepId.(int)))
}
if poolName, ok := d.GetOk("pool_name"); ok {
urlValues.Add("poolName", poolName.(string))
}
if architecture, ok := d.GetOk("architecture"); ok {
urlValues.Add("architecture", architecture.(string))
}
imageId, err := c.DecortAPICall(ctx, "POST", imageCreateAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
d.SetId(imageId)
d.Set("image_id", imageId)
_, err = utilityImageCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
diagnostics := resourceImageRead(ctx, d, m)
if diagnostics != nil {
return diagnostics
}
return nil
}
func resourceImageRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceImageRead: called for %s id: %s", d.Get("name").(string), d.Id())
img, err := utilityImageCheckPresence(ctx, d, m)
if img == nil {
d.SetId("")
return diag.FromErr(err)
}
d.Set("unc_path", img.UNCPath)
d.Set("ckey", img.CKey)
d.Set("account_id", img.AccountId)
d.Set("acl", img.Acl)
d.Set("architecture", img.Architecture)
d.Set("boot_type", img.BootType)
d.Set("bootable", img.Bootable)
d.Set("compute_ci_id", img.ComputeCiId)
d.Set("deleted_time", img.DeletedTime)
d.Set("desc", img.Description)
d.Set("drivers", img.Drivers)
d.Set("enabled", img.Enabled)
d.Set("gid", img.GridId)
d.Set("guid", img.GUID)
d.Set("history", flattenHistory(img.History))
d.Set("hot_resize", img.HotResize)
d.Set("image_id", img.Id)
d.Set("last_modified", img.LastModified)
d.Set("link_to", img.LinkTo)
d.Set("milestones", img.Milestones)
d.Set("image_name", img.Name)
d.Set("password", img.Password)
d.Set("pool_name", img.Pool)
d.Set("provider_name", img.ProviderName)
d.Set("purge_attempts", img.PurgeAttempts)
d.Set("res_id", img.ResId)
d.Set("rescuecd", img.RescueCD)
d.Set("sep_id", img.SepId)
d.Set("shared_with", img.SharedWith)
d.Set("size", img.Size)
d.Set("status", img.Status)
d.Set("tech_status", img.TechStatus)
d.Set("type", img.Type)
d.Set("username", img.Username)
d.Set("version", img.Version)
return nil
}
func resourceImageDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceImageDelete: called for %s, id: %s", d.Get("name").(string), d.Id())
image, err := utilityImageCheckPresence(ctx, d, m)
if image == nil {
if err != nil {
return diag.FromErr(err)
}
return nil
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
if permanently, ok := d.GetOk("permanently"); ok {
urlValues.Add("permanently", strconv.FormatBool(permanently.(bool)))
}
_, err = c.DecortAPICall(ctx, "POST", imageDeleteAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
d.SetId("")
return nil
}
func resourceImageExists(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
log.Debugf("resourceImageExists: called for %s, id: %s", d.Get("name").(string), d.Id())
image, err := utilityImageCheckPresence(ctx, d, m)
if image == nil {
if err != nil {
return false, err
}
return false, nil
}
return true, nil
}
func resourceImageEditName(ctx context.Context, d *schema.ResourceData, m interface{}) error {
log.Debugf("resourceImageEditName: called for %s, id: %s", d.Get("name").(string), d.Id())
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
urlValues.Add("name", d.Get("name").(string))
_, err := c.DecortAPICall(ctx, "POST", imageEditNameAPI, urlValues)
if err != nil {
return err
}
return nil
}
func resourceImageEdit(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceImageEdit: called for %s, id: %s", d.Get("name").(string), d.Id())
if d.HasChange("name") {
err := resourceImageEditName(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
}
return resourceImageRead(ctx, d, m)
}
func ResourceImage() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
CreateContext: resourceImageCreate,
ReadContext: resourceImageRead,
UpdateContext: resourceImageEdit,
DeleteContext: resourceImageDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Timeouts: &schema.ResourceTimeout{
Create: &constants.Timeout60s,
Read: &constants.Timeout30s,
Update: &constants.Timeout60s,
Delete: &constants.Timeout60s,
Default: &constants.Timeout60s,
},
Schema: resourceImageSchemaMake(dataSourceImageExtendSchemaMake()),
}
}

View File

@@ -0,0 +1,132 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
import (
"context"
"net/url"
"strconv"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/rudecs/terraform-provider-decort/internal/constants"
"github.com/rudecs/terraform-provider-decort/internal/controller"
log "github.com/sirupsen/logrus"
)
func resourceImageVirtualCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceImageVirtualCreate: called for image %s", d.Get("name").(string))
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("name", d.Get("name").(string))
urlValues.Add("targetId", strconv.Itoa(d.Get("target_id").(int)))
imageId, err := c.DecortAPICall(ctx, "POST", imageCreateVirtualAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
d.SetId(imageId)
d.Set("image_id", imageId)
_, err = utilityImageCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
diagnostics := resourceImageRead(ctx, d, m)
if diagnostics != nil {
return diagnostics
}
return nil
}
func resourceImageVirtualEdit(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceImageEdit: called for %s, id: %s", d.Get("name").(string), d.Id())
if d.HasChange("name") {
err := resourceImageEditName(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
}
if d.HasChange("link_to") {
err := resourceImageVirtualLink(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
}
return resourceImageRead(ctx, d, m)
}
func resourceImageVirtualLink(ctx context.Context, d *schema.ResourceData, m interface{}) error {
log.Debugf("resourceVirtualImageLink: called for %s, id: %s", d.Get("name").(string), d.Id())
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
urlValues.Add("targetId", strconv.Itoa(d.Get("link_to").(int)))
_, err := c.DecortAPICall(ctx, "POST", imageLinkAPI, urlValues)
if err != nil {
return err
}
return nil
}
func ResourceImageVirtual() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
CreateContext: resourceImageVirtualCreate,
ReadContext: resourceImageRead,
UpdateContext: resourceImageVirtualEdit,
DeleteContext: resourceImageDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Timeouts: &schema.ResourceTimeout{
Create: &constants.Timeout60s,
Read: &constants.Timeout30s,
Update: &constants.Timeout60s,
Delete: &constants.Timeout60s,
Default: &constants.Timeout60s,
},
Schema: resourceImageVirtualSchemaMake(dataSourceImageExtendSchemaMake()),
}
}

View File

@@ -0,0 +1,75 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/url"
"strconv"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/rudecs/terraform-provider-decort/internal/controller"
)
func utilityImageCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (*ImageExtend, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
if (strconv.Itoa(d.Get("image_id").(int))) != "0" {
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
} else {
urlValues.Add("imageId", d.Id())
}
if showAll, ok := d.GetOk("show_all"); ok {
urlValues.Add("page", strconv.FormatBool(showAll.(bool)))
}
resp, err := c.DecortAPICall(ctx, "POST", imageGetAPI, urlValues)
if err != nil {
return nil, err
}
if resp == "" {
return nil, nil
}
image := &ImageExtend{}
if err := json.Unmarshal([]byte(resp), image); err != nil {
return nil, errors.New(fmt.Sprint("Can not unmarshall data to image: ", resp, " ", image))
}
return image, nil
}

View File

@@ -0,0 +1,74 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://github.com/rudecs/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://github.com/rudecs/terraform-provider-decort/wiki
*/
package image
import (
"context"
"encoding/json"
"net/url"
"strconv"
"github.com/rudecs/terraform-provider-decort/internal/controller"
log "github.com/sirupsen/logrus"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func utilityImageListCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (ImageList, error) {
imageList := ImageList{}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
if accountId, ok := d.GetOk("account_id"); ok {
urlValues.Add("accountId", strconv.Itoa(accountId.(int)))
}
if page, ok := d.GetOk("page"); ok {
urlValues.Add("page", strconv.Itoa(page.(int)))
}
if size, ok := d.GetOk("size"); ok {
urlValues.Add("size", strconv.Itoa(size.(int)))
}
log.Debugf("utilityImageListCheckPresence: load image list")
imageListRaw, err := c.DecortAPICall(ctx, "POST", imageListGetAPI, urlValues)
if err != nil {
return nil, err
}
err = json.Unmarshal([]byte(imageListRaw), &imageList)
if err != nil {
return nil, err
}
return imageList, nil
}