This commit is contained in:
KasimBaybikov
2023-05-04 10:08:25 +03:00
parent 9bad8a6947
commit 8ca233dd32
288 changed files with 6645 additions and 11464 deletions

View File

@@ -33,58 +33,42 @@ package rg
import (
"context"
"encoding/json"
"fmt"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
log "github.com/sirupsen/logrus"
// "net/url"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/rg"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func flattenResgroup(d *schema.ResourceData, rg_facts string) error {
// NOTE: this function modifies ResourceData argument - as such it should never be called
// from resourceRsgroupExists(...) method
// log.Debugf("%s", rg_facts)
log.Debugf("flattenResgroup: ready to decode response body from API")
details := ResgroupGetResp{}
err := json.Unmarshal([]byte(rg_facts), &details)
if err != nil {
return err
}
func flattenResgroup(d *schema.ResourceData, rgData *rg.RecordRG) error {
log.Debugf("flattenResgroup: decoded RG name %q / ID %d, account ID %d",
details.Name, details.ID, details.AccountID)
rgData.Name, rgData.ID, rgData.AccountID)
d.SetId(fmt.Sprintf("%d", details.ID))
d.Set("rg_id", details.ID)
d.Set("name", details.Name)
d.Set("account_name", details.AccountName)
d.Set("account_id", details.AccountID)
// d.Set("grid_id", details.GridID)
d.Set("description", details.Desc)
d.Set("status", details.Status)
d.Set("def_net_type", details.DefaultNetType)
d.Set("def_net_id", details.DefaultNetID)
/*
d.Set("vins", details.Vins)
d.Set("computes", details.Computes)
*/
d.SetId(fmt.Sprintf("%d", rgData.ID))
d.Set("rg_id", rgData.ID)
d.Set("name", rgData.Name)
d.Set("account_name", rgData.AccountName)
d.Set("account_id", rgData.AccountID)
// d.Set("grid_id", rgData.GridID)
d.Set("description", rgData.Description)
d.Set("status", rgData.Status)
d.Set("def_net_type", rgData.DefNetType)
d.Set("def_net_id", rgData.DefNetID)
log.Debugf("flattenResgroup: calling flattenQuota()")
if err = d.Set("quota", parseQuota(details.Quota)); err != nil {
return err
}
// log.Debugf("flattenResgroup: calling flattenQuota()")
// if err := d.Set("quota", parseQuota(rgData.Resources)); err != nil {
// return err
// }
return nil
}
func dataSourceResgroupRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
rg_facts, err := utilityResgroupCheckPresence(ctx, d, m)
if rg_facts == "" {
if rg_facts == nil {
// if empty string is returned from utilityResgroupCheckPresence then there is no
// such resource group and err tells so - just return it to the calling party
d.SetId("") // ensure ID is empty in this case

View File

@@ -37,24 +37,25 @@ import (
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/rg"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
)
func flattenRgList(rgl ResgroupListResp) []map[string]interface{} {
func flattenRgList(rgl rg.ListRG) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, rg := range rgl {
temp := map[string]interface{}{
"account_id": rg.AccountID,
"account_name": rg.AccountName,
"acl": flattenRgAcl(rg.ACLs),
"acl": flattenRgAcl(rg.ACL),
"created_by": rg.CreatedBy,
"created_time": rg.CreatedTime,
"def_net_id": rg.DefaultNetID,
"def_net_type": rg.DefaultNetType,
"def_net_id": rg.DefNetID,
"def_net_type": rg.DefNetType,
"deleted_by": rg.DeletedBy,
"deleted_time": rg.DeletedTime,
"desc": rg.Decsription,
"gid": rg.GridID,
"desc": rg.Description,
"gid": rg.GID,
"guid": rg.GUID,
"rg_id": rg.ID,
"lock_status": rg.LockStatus,
@@ -66,8 +67,8 @@ func flattenRgList(rgl ResgroupListResp) []map[string]interface{} {
"status": rg.Status,
"updated_by": rg.UpdatedBy,
"updated_time": rg.UpdatedTime,
"vins": rg.Vins,
"vms": rg.Computes,
"vins": rg.VINS,
"vms": rg.VMs,
}
res = append(res, temp)
}
@@ -75,31 +76,31 @@ func flattenRgList(rgl ResgroupListResp) []map[string]interface{} {
}
func flattenRgAcl(rgAcls []AccountAclRecord) []map[string]interface{} {
func flattenRgAcl(rgAcls rg.ListACL) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, rgAcl := range rgAcls {
temp := map[string]interface{}{
"explicit": rgAcl.IsExplicit,
"guid": rgAcl.Guid,
"right": rgAcl.Rights,
"explicit": rgAcl.Explicit,
"guid": rgAcl.GUID,
"right": rgAcl.Right,
"status": rgAcl.Status,
"type": rgAcl.Type,
"user_group_id": rgAcl.UgroupID,
"user_group_id": rgAcl.UserGroupID,
}
res = append(res, temp)
}
return res
}
func flattenRgResourceLimits(rl ResourceLimits) []map[string]interface{} {
func flattenRgResourceLimits(rl rg.ResourceLimits) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"cu_c": rl.CUC,
"cu_d": rl.CUD,
"cu_d": rl.CuD,
"cu_i": rl.CUI,
"cu_m": rl.CUM,
"cu_np": rl.CUNP,
"gpu_units": rl.GpuUnits,
"gpu_units": rl.GPUUnits,
}
res = append(res, temp)

View File

@@ -126,12 +126,12 @@ type UserAclRecord struct {
}
type QuotaRecord struct { // this is how quota is reported by /api/.../rg/get
Cpu int `json:"CU_C"` // CPU count in pcs
Cpu float64 `json:"CU_C"` // CPU count in pcs
Ram float64 `json:"CU_M"` // RAM volume in MB, it is STILL reported as FLOAT
Disk int `json:"CU_D"` // Disk capacity in GB
ExtIPs int `json:"CU_I"` // Ext IPs count
ExtTraffic int `json:"CU_NP"` // Ext network traffic
GpuUnits int `json:"gpu_units"` // GPU count
Disk float64 `json:"CU_D"` // Disk capacity in GB
ExtIPs float64 `json:"CU_I"` // Ext IPs count
ExtTraffic float64 `json:"CU_NP"` // Ext network traffic
GpuUnits float64 `json:"gpu_units"` // GPU count
}
type ResourceRecord struct { // this is how actual usage is reported by /api/.../rg/get

View File

@@ -33,6 +33,7 @@ package rg
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/rg"
)
func makeQuotaRecord(arg_list []interface{}) QuotaRecord {
@@ -47,41 +48,41 @@ func makeQuotaRecord(arg_list []interface{}) QuotaRecord {
subres_data := arg_list[0].(map[string]interface{})
if subres_data["cpu"].(int) > 0 {
quota.Cpu = subres_data["cpu"].(int)
quota.Cpu = subres_data["cpu"].(float64)
}
if subres_data["disk"].(int) > 0 {
quota.Disk = subres_data["disk"].(int) // Disk capacity ib GB
quota.Disk = subres_data["disk"].(float64)
}
if subres_data["ram"].(float64) > 0 {
quota.Ram = subres_data["ram"].(float64) // RAM volume in MB, as float64!
quota.Ram = subres_data["ram"].(float64)
}
if subres_data["ext_traffic"].(int) > 0 {
quota.ExtTraffic = subres_data["ext_traffic"].(int)
quota.ExtTraffic = subres_data["ext_traffic"].(float64)
}
if subres_data["ext_ips"].(int) > 0 {
quota.ExtIPs = subres_data["ext_ips"].(int)
quota.ExtIPs = subres_data["ext_ips"].(float64)
}
if subres_data["gpu_units"].(int) > 0 {
quota.GpuUnits = subres_data["gpu_units"].(int)
quota.GpuUnits = subres_data["gpu_units"].(float64)
}
return quota
}
func parseQuota(quota QuotaRecord) []interface{} {
func parseQuota(quota rg.ResourceLimits) []interface{} {
quota_map := make(map[string]interface{})
quota_map["cpu"] = quota.Cpu
quota_map["ram"] = quota.Ram // NB: this is float64, unlike the rest of values
quota_map["disk"] = quota.Disk
quota_map["ext_traffic"] = quota.ExtTraffic
quota_map["ext_ips"] = quota.ExtIPs
quota_map["gpu_units"] = quota.GpuUnits
quota_map["cpu"] = quota.CUC
quota_map["ram"] = quota.CUM
quota_map["disk"] = quota.CuD
quota_map["ext_traffic"] = quota.CUNP
quota_map["ext_ips"] = quota.CUI
quota_map["gpu_units"] = quota.GPUUnits
result := make([]interface{}, 1)
result[0] = quota_map
@@ -92,7 +93,7 @@ func parseQuota(quota QuotaRecord) []interface{} {
func quotaRgSubresourceSchemaMake() map[string]*schema.Schema {
rets := map[string]*schema.Schema{
"cpu": {
Type: schema.TypeInt,
Type: schema.TypeFloat,
Optional: true,
Default: -1,
Description: "Limit on the total number of CPUs in this resource group.",
@@ -106,28 +107,28 @@ func quotaRgSubresourceSchemaMake() map[string]*schema.Schema {
},
"disk": {
Type: schema.TypeInt,
Type: schema.TypeFloat,
Optional: true,
Default: -1,
Description: "Limit on the total volume of storage resources in this resource group, specified in GB.",
},
"ext_traffic": {
Type: schema.TypeInt,
Type: schema.TypeFloat,
Optional: true,
Default: -1,
Description: "Limit on the total ingress network traffic for this resource group, specified in GB.",
},
"ext_ips": {
Type: schema.TypeInt,
Type: schema.TypeFloat,
Optional: true,
Default: -1,
Description: "Limit on the total number of external IP addresses this resource group can use.",
},
"gpu_units": {
Type: schema.TypeInt,
Type: schema.TypeFloat,
Optional: true,
Default: -1,
Description: "Limit on the total number of virtual GPUs this resource group can use.",

View File

@@ -33,14 +33,14 @@ package rg
import (
"context"
"encoding/json"
"fmt"
"net/url"
"strconv"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/rg"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/location"
log "github.com/sirupsen/logrus"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -48,32 +48,13 @@ import (
)
func resourceResgroupCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
// First validate that we have all parameters required to create the new Resource Group
// Valid account ID is required to create new resource group
// obtain Account ID by account name - it should not be zero on success
rg_name, arg_set := d.GetOk("name")
if !arg_set {
return diag.FromErr(fmt.Errorf("Cannot create new RG: missing name."))
}
/* Current version of provider works with default grid id (same is true for disk resources)
grid_id, arg_set := d.GetOk("grid_id")
if !arg_set {
return fmt.Errorf("Cannot create new RG %q in account ID %d: missing Grid ID.",
rg_name.(string), validated_account_id)
}
if grid_id.(int) < 1 {
grid_id = DefaultGridID
}
*/
// all required parameters are set in the schema - we can continue with RG creation
log.Debugf("resourceResgroupCreate: called for RG name %s, account ID %d",
rg_name.(string), d.Get("account_id").(int))
// quota settings are optional
set_quota := false
var quota_record QuotaRecord
arg_value, arg_set := d.GetOk("quota")
@@ -88,62 +69,57 @@ func resourceResgroupCreate(ctx context.Context, d *schema.ResourceData, m inter
c.GetDecortUsername(),
rg_name.(string), d.Get("account_id").(int))
url_values := &url.Values{}
url_values.Add("accountId", fmt.Sprintf("%d", d.Get("account_id").(int)))
url_values.Add("name", rg_name.(string))
url_values.Add("gid", fmt.Sprintf("%d", location.DefaultGridID)) // use default Grid ID, similar to disk resource mgmt convention
url_values.Add("owner", c.GetDecortUsername())
req := rg.CreateRequest{
AccountID: uint64(d.Get("account_id").(int)),
Name: rg_name.(string),
GID: uint64(location.DefaultGridID),
Owner: c.GetDecortUsername(),
}
// pass quota values as set
if set_quota {
url_values.Add("maxCPUCapacity", fmt.Sprintf("%d", quota_record.Cpu))
url_values.Add("maxVDiskCapacity", fmt.Sprintf("%d", quota_record.Disk))
url_values.Add("maxMemoryCapacity", fmt.Sprintf("%f", quota_record.Ram)) // RAM quota is float; this may change in the future
url_values.Add("maxNetworkPeerTransfer", fmt.Sprintf("%d", quota_record.ExtTraffic))
url_values.Add("maxNumPublicIP", fmt.Sprintf("%d", quota_record.ExtIPs))
req.MaxCPUCapacity = int64(quota_record.Cpu)
req.MaxVDiskCapacity = int64(quota_record.Disk)
req.MaxMemoryCapacity = int64(quota_record.Ram)
req.MaxNetworkPeerTransfer = int64(quota_record.ExtTraffic)
req.MaxNumPublicIP = int64(quota_record.ExtIPs)
// url_values.Add("???", fmt.Sprintf("%d", quota_record.GpuUnits))
}
// parse and handle network settings
def_net_type, arg_set := d.GetOk("def_net_type")
if arg_set {
url_values.Add("def_net", def_net_type.(string)) // NOTE: in API default network type is set by "def_net" parameter
req.DefNet = def_net_type.(string)
}
ipcidr, arg_set := d.GetOk("ipcidr")
if arg_set {
url_values.Add("ipcidr", ipcidr.(string))
req.IPCIDR = ipcidr.(string)
}
ext_net_id, arg_set := d.GetOk("ext_net_id")
if arg_set {
url_values.Add("extNetId", fmt.Sprintf("%d", ext_net_id.(int)))
req.ExtNetID = uint64(ext_net_id.(int))
}
ext_ip, arg_set := d.GetOk("ext_ip")
if arg_set {
url_values.Add("extIp", ext_ip.(string))
req.ExtIP = ext_ip.(string)
}
api_resp, err := c.DecortAPICall(ctx, "POST", ResgroupCreateAPI, url_values)
rgId, err := c.CloudBroker().RG().Create(ctx, req)
if err != nil {
return diag.FromErr(err)
}
d.SetId(api_resp) // rg/create API returns ID of the newly creted resource group on success
// rg.ID, _ = strconv.Atoi(api_resp)
d.SetId(strconv.FormatUint(rgId, 10))
if !set_quota {
resp, err := utilityResgroupCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
rg := ResgroupGetResp{}
if err := json.Unmarshal([]byte(resp), &rg); err != nil {
return diag.FromErr(err)
}
d.Set("quota", parseQuota(rg.Quota))
d.Set("quota", parseQuota(resp.ResourceLimits))
}
// re-read newly created RG to make sure schema contains complete and up to date set of specifications
@@ -155,9 +131,7 @@ func resourceResgroupRead(ctx context.Context, d *schema.ResourceData, m interfa
d.Get("name").(string), d.Get("account_id").(int))
rg_facts, err := utilityResgroupCheckPresence(ctx, d, m)
if rg_facts == "" {
// if empty string is returned from utilityResgroupCheckPresence then there is no
// such resource group and err tells so - just return it to the calling party
if rg_facts == nil {
d.SetId("") // ensure ID is empty
return diag.FromErr(err)
}
@@ -192,8 +166,10 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
do_general_update := false // will be true if general RG update is necessary (API rg/update)
c := m.(*controller.ControllerCfg)
url_values := &url.Values{}
url_values.Add("rgId", d.Id())
rgId, _ := strconv.ParseUint(d.Id(), 10, 64)
req := rg.UpdateRequest{
RGID: rgId,
}
name_new, name_set := d.GetOk("name")
if name_set {
@@ -201,7 +177,7 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
name_old, _ := d.GetChange("name")
if name_old.(string) != name_new.(string) {
do_general_update = true
url_values.Add("name", name_new.(string))
req.Name = name_new.(string)
}
}
@@ -215,31 +191,31 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
if quotarecord_new.Cpu != quotarecord_old.Cpu {
do_general_update = true
log.Debugf("resourceResgroupUpdate: Cpu diff %d <- %d", quotarecord_new.Cpu, quotarecord_old.Cpu)
url_values.Add("maxCPUCapacity", fmt.Sprintf("%d", quotarecord_new.Cpu))
req.MaxCPUCapacity = int64(quotarecord_new.Cpu)
}
if quotarecord_new.Disk != quotarecord_old.Disk {
do_general_update = true
log.Debugf("resourceResgroupUpdate: Disk diff %d <- %d", quotarecord_new.Disk, quotarecord_old.Disk)
url_values.Add("maxVDiskCapacity", fmt.Sprintf("%d", quotarecord_new.Disk))
req.MaxVDiskCapacity = int64(quotarecord_new.Disk)
}
if quotarecord_new.Ram != quotarecord_old.Ram { // NB: quota on RAM is stored as float32, in units of MB
do_general_update = true
log.Debugf("resourceResgroupUpdate: Ram diff %f <- %f", quotarecord_new.Ram, quotarecord_old.Ram)
url_values.Add("maxMemoryCapacity", fmt.Sprintf("%f", quotarecord_new.Ram))
req.MaxMemoryCapacity = int64(quotarecord_new.Ram)
}
if quotarecord_new.ExtTraffic != quotarecord_old.ExtTraffic {
do_general_update = true
log.Debugf("resourceResgroupUpdate: ExtTraffic diff %d <- %d", quotarecord_new.ExtTraffic, quotarecord_old.ExtTraffic)
url_values.Add("maxNetworkPeerTransfer", fmt.Sprintf("%d", quotarecord_new.ExtTraffic))
req.MaxNetworkPeerTransfer = int64(quotarecord_new.ExtTraffic)
}
if quotarecord_new.ExtIPs != quotarecord_old.ExtIPs {
do_general_update = true
log.Debugf("resourceResgroupUpdate: ExtIPs diff %d <- %d", quotarecord_new.ExtIPs, quotarecord_old.ExtIPs)
url_values.Add("maxNumPublicIP", fmt.Sprintf("%d", quotarecord_new.ExtIPs))
req.MaxNumPublicIP = int64(quotarecord_new.ExtIPs)
}
}
@@ -249,13 +225,13 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
desc_old, _ := d.GetChange("description")
if desc_old.(string) != desc_new.(string) {
do_general_update = true
url_values.Add("desc", desc_new.(string))
req.Description = desc_new.(string)
}
}
if do_general_update {
log.Debugf("resourceResgroupUpdate: detected delta between new and old RG specs - updating the RG")
_, err := c.DecortAPICall(ctx, "POST", ResgroupUpdateAPI, url_values)
_, err := c.CloudBroker().RG().Update(ctx, req)
if err != nil {
return diag.FromErr(err)
}
@@ -267,29 +243,26 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
}
func resourceResgroupDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
// NOTE: this method forcibly destroys target resource group with flag "permanently", so there is no way to
// restore the destroyed resource group as well all Computes & VINSes that existed in it
log.Debugf("resourceResgroupDelete: called for RG name %s, account ID %d",
d.Get("name").(string), d.Get("account_id").(int))
rg_facts, err := utilityResgroupCheckPresence(ctx, d, m)
if rg_facts == "" {
if rg_facts == nil {
if err != nil {
return diag.FromErr(err)
}
// the target RG does not exist - in this case according to Terraform best practice
// we exit from Destroy method without error
return nil
}
url_values := &url.Values{}
url_values.Add("rgId", d.Id())
url_values.Add("force", "1")
url_values.Add("permanently", "1")
url_values.Add("reason", "Destroyed by DECORT Terraform provider")
req := rg.DeleteRequest{
RGID: rg_facts.ID,
Force: true,
Permanently: true,
Reason: "Destroyed by DECORT Terraform provider",
}
c := m.(*controller.ControllerCfg)
_, err = c.DecortAPICall(ctx, "POST", ResgroupDeleteAPI, url_values)
_, err = c.CloudBroker().RG().Delete(ctx, req)
if err != nil {
return diag.FromErr(err)
}

View File

@@ -33,48 +33,25 @@ package rg
import (
"context"
"encoding/json"
"fmt"
"net/url"
"strconv"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/rg"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
// On success this function returns a string, as returned by API rg/get, which could be unmarshalled
// into ResgroupGetResp structure
func utilityResgroupCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (string, error) {
// This function tries to locate resource group by one of the following algorithms depending
// on the parameters passed:
// - if resource group ID is specified -> by RG ID
// - if resource group name is specifeid -> by RG name and either account ID or account name
//
// If succeeded, it returns non empty string that contains JSON formatted facts about the
// resource group as returned by rg/get API call.
// Otherwise it returns empty string and a meaningful error.
//
// NOTE: As our provider always deletes RGs permanently, there is no "restore" method and
// consequently we are not interested in matching RGs in DELETED state. Hence, we call
// .../rg/list API with includedeleted=false
//
// This function does not modify its ResourceData argument, so it is safe to use it as core
// method for the Terraform resource Exists method.
//
func utilityResgroupCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (*rg.RecordRG, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
// make it possible to use "read" & "check presence" functions with RG ID set so
// that Import of RG resource is possible
idSet := false
theId, err := strconv.Atoi(d.Id())
theId, err := strconv.ParseUint(d.Id(), 10, 64)
if err != nil || theId <= 0 {
rgId, argSet := d.GetOk("rg_id")
if argSet {
theId = rgId.(int)
theId = uint64(rgId.(int))
idSet = true
}
} else {
@@ -82,58 +59,50 @@ func utilityResgroupCheckPresence(ctx context.Context, d *schema.ResourceData, m
}
if idSet {
// go straight for the RG by its ID
log.Debugf("utilityResgroupCheckPresence: locating RG by its ID %d", theId)
urlValues.Add("rgId", fmt.Sprintf("%d", theId))
rgFacts, err := c.DecortAPICall(ctx, "POST", ResgroupGetAPI, urlValues)
req := rg.GetRequest{
RGID: theId,
}
rgFacts, err := c.CloudBroker().RG().Get(ctx, req)
if err != nil {
return "", err
return nil, err
}
return rgFacts, nil
}
rgName, argSet := d.GetOk("name")
if !argSet {
// no RG ID and no RG name - we cannot locate resource group in this case
return "", fmt.Errorf("Cannot check resource group presence if name is empty and no resource group ID specified")
return nil, fmt.Errorf("Cannot check resource group presence if name is empty and no resource group ID specified")
}
// Valid account ID is required to locate a resource group
// obtain Account ID by account name - it should not be zero on success
urlValues.Add("includedeleted", "false")
apiResp, err := c.DecortAPICall(ctx, "POST", ResgroupListAPI, urlValues)
if err != nil {
return "", err
listReq := rg.ListRequest{
IncludeDeleted: false,
}
// log.Debugf("%s", apiResp)
log.Debugf("utilityResgroupCheckPresence: ready to decode response body from %s", ResgroupListAPI)
model := ResgroupListResp{}
err = json.Unmarshal([]byte(apiResp), &model)
model, err := c.CloudBroker().RG().List(ctx, listReq)
if err != nil {
return "", err
return nil, err
}
log.Debugf("utilityResgroupCheckPresence: traversing decoded Json of length %d", len(model))
for index, item := range model {
// match by RG name & account ID
if item.Name == rgName.(string) && item.AccountID == d.Get("account_id").(int) {
if item.Name == rgName.(string) && item.AccountID == uint64(d.Get("account_id").(int)) {
log.Debugf("utilityResgroupCheckPresence: match RG name %s / ID %d, account ID %d at index %d",
item.Name, item.ID, item.AccountID, index)
// not all required information is returned by rg/list API, so we need to initiate one more
// call to rg/get to obtain extra data to complete Resource population.
// Namely, we need resource quota settings
reqValues := &url.Values{}
reqValues.Add("rgId", fmt.Sprintf("%d", item.ID))
apiResp, err := c.DecortAPICall(ctx, "POST", ResgroupGetAPI, reqValues)
req := rg.GetRequest{
RGID: item.ID,
}
apiResp, err := c.CloudBroker().RG().Get(ctx, req)
if err != nil {
return "", err
return nil, err
}
return apiResp, nil
}
}
return "", fmt.Errorf("Cannot find RG name %s owned by account ID %d", rgName, d.Get("account_id").(int))
return nil, fmt.Errorf("Cannot find RG name %s owned by account ID %d", rgName, d.Get("account_id").(int))
}

View File

@@ -33,39 +33,30 @@ package rg
import (
"context"
"encoding/json"
"net/url"
"strconv"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/rg"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func utilityRgListCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (ResgroupListResp, error) {
func utilityRgListCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (rg.ListRG, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
rgList := ResgroupListResp{}
req := rg.ListRequest{}
if size, ok := d.GetOk("size"); ok {
urlValues.Add("size", strconv.Itoa(size.(int)))
req.Size = uint64(size.(int))
}
if page, ok := d.GetOk("page"); ok {
urlValues.Add("page", strconv.Itoa(page.(int)))
req.Page = uint64(page.(int))
}
if includedeleted, ok := d.GetOk("includedeleted"); ok {
urlValues.Add("includedeleted", strconv.FormatBool(includedeleted.(bool)))
req.IncludeDeleted = includedeleted.(bool)
}
log.Debugf("utilityRgListCheckPresence: load rg list")
rgListRaw, err := c.DecortAPICall(ctx, "POST", ResgroupListAPI, urlValues)
if err != nil {
return nil, err
}
err = json.Unmarshal([]byte(rgListRaw), &rgList)
rgList, err := c.CloudBroker().RG().List(ctx, req)
if err != nil {
return nil, err
}