Fix state mgmt issues for compute and add Import support for RG

rc-1.0
Sergey Shubin svs1370 4 years ago
parent 3aefa580dc
commit 7f6d11dfd5

@ -55,7 +55,7 @@ func flattenResgroup(d *schema.ResourceData, rg_facts string) error {
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("grid_id", details.GridID)
d.Set("description", details.Desc)
d.Set("status", details.Status)
d.Set("def_net_type", details.DefaultNetType)
@ -111,14 +111,14 @@ func dataSourceResgroup() *schema.Resource {
"account_name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "Name of the account, which this resource group belongs to.",
},
"account_id": {
Type: schema.TypeInt,
Optional: true,
Description: "Unique ID of the account, which this resource group belongs to. If account ID is specified, then account name is ignored.",
Required: true,
Description: "Unique ID of the account, which this resource group belongs to.",
},
"description": {
@ -127,11 +127,13 @@ func dataSourceResgroup() *schema.Resource {
Description: "User-defined text description of this resource group.",
},
/* commented out, as in this version of provider we use default Grid ID
"grid_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Unique ID of the grid, where this resource group is deployed.",
},
*/
"quota": {
Type: schema.TypeList,
@ -143,12 +145,6 @@ func dataSourceResgroup() *schema.Resource {
Description: "Quota settings for this resource group.",
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: "Current status of this resource group.",
},
"def_net_type": {
Type: schema.TypeString,
Computed: true,
@ -162,6 +158,12 @@ func dataSourceResgroup() *schema.Resource {
},
/*
"status": {
Type: schema.TypeString,
Computed: true,
Description: "Current status of this resource group.",
},
"vins": {
Type: schema.TypeList, // this is a list of ints
Computed: true,

@ -106,7 +106,7 @@ type ResgroupUpdateParam struct {
//
type QuotaRecord struct { // this is how quota is reported by /api/.../rg/get
Cpu int `json:"CU_C"` // CPU count in pcs
Ram float32 `json:"CU_M"` // RAM volume in MB, it is STILL reported as FLOAT
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

@ -35,6 +35,7 @@ func networkSubresourceSchemaMake() map[string]*schema.Schema {
"net_type": {
Type: schema.TypeString,
Required: true,
StateFunc: stateFuncToUpper,
ValidateFunc: validation.StringInSlice([]string{"EXTNET", "VINS"}, false), // observe case while validating
Description: "Type of the network for this connection, either EXTNET or VINS.",
},
@ -48,6 +49,7 @@ func networkSubresourceSchemaMake() map[string]*schema.Schema {
"ip_address": {
Type: schema.TypeString,
Optional: true,
// DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {}
Description: "Optional IP address to assign to this connection. This IP should belong to the selected network and free for use.",
},

@ -124,6 +124,10 @@ func stateFuncToLower(argval interface{}) string {
return strings.ToLower(argval.(string))
}
func stateFuncToUpper(argval interface{}) string {
return strings.ToUpper(argval.(string))
}
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
decsController, err := ControllerConfigure(d)
if err != nil {

@ -31,7 +31,7 @@ import (
func makeQuotaRecord(arg_list []interface{}) (QuotaRecord, int) {
quota := QuotaRecord{
Cpu: -1,
Ram: -1., // this is float32, but may change in the future
Ram: -1., // this is float64, but may change in the future
Disk: -1,
ExtTraffic: -1,
ExtIPs: -1,
@ -47,8 +47,8 @@ func makeQuotaRecord(arg_list []interface{}) (QuotaRecord, int) {
quota.Disk = subres_data["disk"].(int) // Disk capacity ib GB
}
if subres_data["ram"].(int) > 0 {
quota.Ram = subres_data["ram"].(float32) // RAM volume in MB, as float32!
if subres_data["ram"].(float64) > 0 {
quota.Ram = subres_data["ram"].(float64) // RAM volume in MB, as float64!
}
if subres_data["ext_traffic"].(int) > 0 {
@ -70,7 +70,7 @@ func parseQuota(quota QuotaRecord) []interface{} {
quota_map := make(map[string]interface{})
quota_map["cpu"] = quota.Cpu
quota_map["ram"] = quota.Ram // NB: this is float32, unlike the rest of values
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

@ -323,7 +323,7 @@ func resourceCompute() *schema.Resource {
"name": {
Type: schema.TypeString,
Required: true,
Description: "Name of this compute. This parameter is case sensitive and must be unique in the resource group.",
Description: "Name of this compute. Compute names are case sensitive and must be unique in the resource group.",
},
"rg_id": {
@ -337,6 +337,7 @@ func resourceCompute() *schema.Resource {
Type: schema.TypeString,
Required: true,
ForceNew: true,
StateFunc: stateFuncToUpper,
ValidateFunc: validation.StringInSlice([]string{"KVM_X86", "KVM_PPC"}, false), // observe case while validating
Description: "Hardware architecture of this compute instance.",
},

@ -33,7 +33,7 @@ import (
log "github.com/sirupsen/logrus"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
// "github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
)
func resourceDiskCreate(d *schema.ResourceData, m interface{}) error {
@ -234,6 +234,8 @@ func resourceDiskSchemaMake() map[string]*schema.Schema {
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.",
},

@ -47,14 +47,19 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
return 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 %q, account ID %d",
log.Debugf("resourceResgroupCreate: called for RG name %s, account ID %d",
rg_name.(string), validated_account_id)
// quota settings are optional
@ -68,14 +73,14 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
}
controller := m.(*ControllerCfg)
log.Debugf("resourceResgroupCreate: called by user %q for RG name %q, account ID %d, Grid ID %d",
log.Debugf("resourceResgroupCreate: called by user %q for RG name %s, account ID %d",
controller.getDecortUsername(),
rg_name.(string), validated_account_id, grid_id.(int))
rg_name.(string), validated_account_id)
url_values := &url.Values{}
url_values.Add("accountId", fmt.Sprintf("%d", validated_account_id))
url_values.Add("name", rg_name.(string))
url_values.Add("gid", fmt.Sprintf("%d", grid_id.(int)))
url_values.Add("gid", fmt.Sprintf("%d", DefaultGridID)) // use default Grid ID, similar to disk resource mgmt convention
url_values.Add("owner", controller.getDecortUsername())
// pass quota values as set
@ -122,8 +127,9 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
}
func resourceResgroupRead(d *schema.ResourceData, m interface{}) error {
log.Debugf("resourceResgroupRead: called for RG name %q, account name %q",
d.Get("name").(string), d.Get("account_name").(string))
log.Debugf("resourceResgroupRead: called for RG name %s, account ID %s",
d.Get("name").(string), d.Get("account_id").(int))
rg_facts, err := utilityResgroupCheckPresence(d, m)
if rg_facts == "" {
// if empty string is returned from utilityResgroupCheckPresence then there is no
@ -136,8 +142,8 @@ func resourceResgroupRead(d *schema.ResourceData, m interface{}) error {
}
func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error {
log.Debugf("resourceResgroupUpdate: called for RG name %q, account name %q",
d.Get("name").(string), d.Get("account").(string))
log.Debugf("resourceResgroupUpdate: called for RG name %s, account ID %d",
d.Get("name").(string), d.Get("account_id").(int))
do_update := false
@ -219,8 +225,8 @@ func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error {
func resourceResgroupDelete(d *schema.ResourceData, m interface{}) error {
// 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 %q, account name %q",
d.Get("name").(string), d.Get("account_name").(string))
log.Debugf("resourceResgroupDelete: called for RG name %s, account ID %s",
d.Get("name").(string), d.Get("account_id").(int))
rg_facts, err := utilityResgroupCheckPresence(d, m)
if rg_facts == "" {
@ -266,6 +272,10 @@ func resourceResgroup() *schema.Resource {
Delete: resourceResgroupDelete,
Exists: resourceResgroupExists,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Timeouts: &schema.ResourceTimeout{
Create: &Timeout180s,
Read: &Timeout30s,
@ -283,14 +293,8 @@ func resourceResgroup() *schema.Resource {
"account_id": {
Type: schema.TypeInt,
Optional: true,
Description: "Unique ID of the account, which this resource group belongs to. If account ID is specified, then account name is ignored.",
},
"account_name": {
Type: schema.TypeString,
Optional: true,
Description: "Name of the account, which this resource group belongs to.",
Required: true,
Description: "Unique ID of the account, which this resource group belongs to.",
},
"def_net_type": {
@ -325,11 +329,16 @@ func resourceResgroup() *schema.Resource {
Description: "IP address on the external netowrk to request, if def_net_type=PUBLIC",
},
"grid_id": { // change of Grid ID will require new RG
/* commented out, as in this version of provider we use default Grid ID
"grid_id": {
Type: schema.TypeInt,
Required: true,
Optional: true,
Default: 0, // if 0 is passed, default Grid ID will be used
// DefaultFunc: utilityResgroupGetDefaultGridID,
ForceNew: true, // change of Grid ID will require new RG
Description: "Unique ID of the grid, where this resource group is deployed.",
},
*/
"quota": {
Type: schema.TypeList,
@ -347,13 +356,19 @@ func resourceResgroup() *schema.Resource {
Description: "User-defined text description of this resource group.",
},
"account_name": {
Type: schema.TypeString,
Computed: true,
Description: "Name of the account, which this resource group belongs to.",
},
/*
"status": {
Type: schema.TypeString,
Computed: true,
Description: "Current status of this resource group.",
},
/*
"vins": {
Type: schema.TypeList, // this is a list of ints
Computed: true,

@ -110,6 +110,10 @@ func utilityGetAccountIdBySchema(d *schema.ResourceData, m interface{}) (int, er
initiate API calls to the DECORT cloud controller and try to match relevant account
by the name.
NOTE that for some resources (most notably, Resource Group) "account_name" attribute is
marked as "Computed: true", so the only way to fully identify Resource Group is to specify
"account_id", which is marked as "Required: true"
*/
accId, argSet := d.GetOk("account_id")

@ -317,7 +317,7 @@ func utilityComputeCheckPresence(d *schema.ResourceData, m interface{}) (string,
controller := m.(*ControllerCfg)
urlValues := &url.Values{}
// make it possible to use "read" & "check presence" functions with comptue ID set so
// make it possible to use "read" & "check presence" functions with compute ID set so
// that Import of Compute resource is possible
idSet := false
theId, err := strconv.Atoi(d.Id())

@ -28,6 +28,7 @@ import (
"encoding/json"
"fmt"
"net/url"
"strconv"
log "github.com/sirupsen/logrus"
@ -43,7 +44,7 @@ func (ctrl *ControllerCfg) utilityResgroupConfigGet(rgid int) (*ResgroupGetResp,
return nil, err
}
log.Debugf("utilityResgroupConfigGet: ready to unmarshal string %q", rgFacts)
log.Debugf("utilityResgroupConfigGet: ready to unmarshal string %s", rgFacts)
model := &ResgroupGetResp{}
err = json.Unmarshal([]byte(rgFacts), model)
if err != nil {
@ -90,11 +91,24 @@ func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string
controller := m.(*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())
if err != nil || theId <= 0 {
rgId, argSet := d.GetOk("rg_id")
if argSet {
theId = rgId.(int)
idSet = true
}
} else {
idSet = true
}
if idSet {
// go straight for the RG by its ID
log.Debugf("utilityResgroupCheckPresence: locating RG by its ID %d", rgId.(int))
urlValues.Add("rgId", fmt.Sprintf("%d", rgId.(int)))
log.Debugf("utilityResgroupCheckPresence: locating RG by its ID %d", theId)
urlValues.Add("rgId", fmt.Sprintf("%d", theId))
rgFacts, err := controller.decortAPICall("POST", ResgroupGetAPI, urlValues)
if err != nil {
return "", err
@ -132,7 +146,7 @@ func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string
for index, item := range model {
// match by RG name & account ID
if item.Name == rgName.(string) && item.AccountID == validatedAccountId {
log.Debugf("utilityResgroupCheckPresence: match RG name %q / ID %d, account ID %d at index %d",
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
@ -149,5 +163,13 @@ func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string
}
}
return "", fmt.Errorf("Cannot find RG name %q owned by account ID %d", rgName, validatedAccountId)
return "", fmt.Errorf("Cannot find RG name %s owned by account ID %d", rgName, validatedAccountId)
}
func utilityResgroupGetDefaultGridID() (interface{}, error) {
if DefaultGridID > 0 {
return fmt.Sprintf("%d", DefaultGridID), nil
}
return "", fmt.Errorf("utilityResgroupGetDefaultGridID: invalid default Grid ID %d", DefaultGridID)
}

Loading…
Cancel
Save