diff --git a/decort/controller.go b/decort/controller.go index 6beb01a..d4902ab 100644 --- a/decort/controller.go +++ b/decort/controller.go @@ -63,8 +63,8 @@ type ControllerCfg struct { app_id string // required for oauth2 mode app_secret string // required for oauth2 mode oauth2_url string // always required - decort_username string // assigned to either legacy_user (legacy mode) or Oauth2 user (oauth2 mode) upon successful verification - cc_client *http.Client // assigned when all initial check successfully passed + decort_username string // assigned to either legacy_user (legacy mode) or Oauth2 user (oauth2 mode) upon successful verification + cc_client *http.Client // assigned when all initial checks successfully passed } func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) { diff --git a/decort/data_source_rg.go b/decort/data_source_rg.go index 5e69a09..45ef3df 100644 --- a/decort/data_source_rg.go +++ b/decort/data_source_rg.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2019-2020 Digital Energy Cloud Solutions LLC. All Rights Reserved. +Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved. Author: Sergey Shubin, , Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,24 +39,23 @@ import ( 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.Printf("%s", rg_facts) - log.Printf("flattenResgroup: ready to decode response body from %q", CloudspacesGetAPI) - details := CloudspacesGetResp{} + log.Debugf("%s", rg_facts) + log.Debugf("flattenResgroup: ready to decode response body from %q", CloudspacesGetAPI) + details := ResgroupGetResp{} err := json.Unmarshal([]byte(rg_facts), &details) if err != nil { return err } - log.Printf("flattenResgroup: decoded ResGroup name %q / ID %d, tenant ID %d, public IP %q", - details.Name, details.ID, details.TenantID, details.PublicIP) + log.Debugf("flattenResgroup: decoded ResGroup name %q / ID %d, account ID %d, public IP %q", + details.Name, details.ID, details.AccountID, details.PublicIP) d.SetId(fmt.Sprintf("%d", details.ID)) d.Set("name", details.Name) - d.Set("tenant_id", details.TenantID) + d.Set("account_id", details.AccountID) d.Set("grid_id", details.GridID) - d.Set("public_ip", details.PublicIP) // legacy field - this may be obsoleted when new network segments are implemented - log.Printf("flattenResgroup: calling flattenQuota()") + log.Debugf("flattenResgroup: calling flattenQuota()") if err = d.Set("quotas", flattenQuota(details.Quotas)); err != nil { return err } @@ -69,7 +68,7 @@ func dataSourceResgroupRead(d *schema.ResourceData, m interface{}) error { 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 - d.SetId("") // ensure ID is empty + d.SetId("") // ensure ID is empty in this case return err } @@ -95,13 +94,13 @@ func dataSourceResgroup() *schema.Resource { Description: "Name of this resource group. Names are case sensitive and unique within the context of a tenant.", }, - "tenant": &schema.Schema { + "account": &schema.Schema { Type: schema.TypeString, Required: true, Description: "Name of the tenant, which this resource group belongs to.", }, - "tenant_id": &schema.Schema { + "account_id": &schema.Schema { Type: schema.TypeInt, Computed: true, Description: "Unique ID of the tenant, which this resource group belongs to.", @@ -113,12 +112,6 @@ func dataSourceResgroup() *schema.Resource { Description: "Unique ID of the grid, where this resource group is deployed.", }, - "location": { - Type: schema.TypeString, - Computed: true, - Description: "Location of this resource group.", - }, - "public_ip": { // this may be obsoleted as new network segments and true resource groups are implemented Type: schema.TypeString, Computed: true, diff --git a/decort/models_api.go b/decort/models_api.go index 9a67972..8ee4968 100644 --- a/decort/models_api.go +++ b/decort/models_api.go @@ -60,8 +60,8 @@ type AccountAclRecord struct { type ResgroupRecord struct { ACLs []UserAclRecord `json:"ACLs"` Owner AccountAclRecord `json:"accountAcl"` - TenantID int `json:"accountId"` - TenantName string `json:"accountName"` + AccountID int `json:"accountId"` + AccountName string `json:"accountName"` CreatedBy string `json:"createdBy"` CreatedTime uint64 `json:"createdTime"` DefaultNetID int `json:"def_net_id"` @@ -85,23 +85,6 @@ type ResgroupListResp []ResgroupRecord // structures related to /cloudapi/rg/create API call // const ResgroupCreateAPI= "/restmachine/cloudapi/rg/create" -type ResgroupCreateParam struct { - TenantID int `json:"accountId"` - GridId int `json:"gid"` - Name string `json:"name"` - Ram int `json:"maxMemoryCapacity"` - Disk int `json:"maxVDiskCapacity"` - Cpu int `json:"maxCPUCapacity"` - NetTraffic int `json:"maxNetworkPeerTransfer"` - ExtIPs int `json:"maxNumPublicIP"` - Owner string `json:"owner"` - DefNet string `json:"def_net"` - IPCidr string `json:"ipcidr"` - Desc string `json:"decs"` - Reason string `json:"reason"` - ExtNetID int `json:"extNetId"` - ExtIP string `json:"extIp"` -} // // structures related to /cloudapi/rg/update API call @@ -139,8 +122,8 @@ const ResgroupGetAPI= "/restmachine/cloudapi/rg/get" type ResgroupGetResp struct { ACLs []UserAclRecord `json:"ACLs"` Usage UsageRecord `json:"Resources"` - TenantID int `json:"accountId"` - TenantName string `json:"accountName"` + AccountID int `json:"accountId"` + AccountName string `json:"accountName"` CreatedBy string `json:"createdBy"` CreatedTime uint64 `json:"createdTime"` @@ -182,11 +165,6 @@ type ResgroupUpdateParam struct { // structures related to /cloudapi/rg/delete API // const ResgroupDeleteAPI = "/restmachine/cloudapi/rg/delete" -type ResgroupDeleteParam struct { - ID uint `json:"rgId"` - Force bool `json:"force"` - Reason string `json:"reason"` -} // // structures related to /cloudapi/kvmXXX/create APIs @@ -245,8 +223,8 @@ type SnapSetRecord struct { } type ComputeRecord struct { - TenantID int `json:"accountId"` - TenantName string `json:"accountName"` + AccountID int `json:"accountId"` + AccountName string `json:"accountName"` ACLs []UserAclRecord `json:"acl"` Arch string `json:"arch"` BootDiskSize int `json:"bootdiskSize"` @@ -302,7 +280,7 @@ type SnapshotRecord struct { type DiskRecord struct { // ACLs `json:"ACL"` - it is a dictionary, special parsing required // was - Acl map[string]string `json:"acl"` - TenantID int `json:"accountId"` + AccountID int `json:"accountId"` BootPartition int `json:"bootPartition"` CreatedTime uint64 `json:"creationTime"` DeletedTime uint64 `json:"deletionTime"` @@ -347,8 +325,8 @@ type ComputeGetParam struct { } type ComputeGetResp struct { // ACLs `json:"ACL"` - it is a dictionary, special parsing required - TenantID int `json:"accountId"` - TenantName string `json:"accountName"` + AccountID int `json:"accountId"` + AccountName string `json:"accountName"` Arch string `json:"arch"` BootDiskSize int `json:"bootdiskSize"` CloneReference int `json:"cloneReference"` @@ -391,7 +369,7 @@ type ComputeGetResp struct { // structures related to /restmachine/cloudapi/images/list API // type ImageRecord struct { - TenantID uint `json:"accountId"` + AccountID uint `json:"accountId"` Arch string `json:"architecture` BootType string `json:"bootType"` IsBootable boo `json:"bootable"` @@ -411,7 +389,7 @@ type ImageRecord struct { const ImagesListAPI = "/restmachine/cloudapi/images/list" type ImagesListParam struct { - TenantID int `json:"accountId"` + AccountID int `json:"accountId"` } type ImagesListResp []ImageRecord @@ -426,7 +404,7 @@ type ExtNetRecord struct { const ExtNetListAPI = "/restmachine/cloudapi/extnet/list" type ExtNetListParam struct { - TenantID int `json:"accountId"` + AccountID int `json:"accountId"` } type ExtNetListResp []ExtNetRecord @@ -434,7 +412,7 @@ type ExtNetListResp []ExtNetRecord // // structures related to /cloudapi/accounts/list API // -type TenantRecord struct { +type AccountRecord struct { ACLs []UserAclRecord `json:"acl"` CreatedTime uint64 `json:"creationTime"` DeletedTime uint64 `json:"deletionTime"` @@ -444,8 +422,8 @@ type TenantRecord struct { UpdatedTime uint64 `json:"updateTime"` } -const TenantsListAPI = "/restmachine/cloudapi/accounts/list" -type TenantsListResp []TenantRecord +const AccountsListAPI = "/restmachine/cloudapi/accounts/list" +type AccountsListResp []AccountRecord // // structures related to /cloudapi/portforwarding/list API @@ -516,7 +494,7 @@ const ComputeDiskDetachAPI = "/restmachine/cloudapi/compute/diskDetach" // structures related to /cloudapi/disks/create // type DiskCreateParam struct { - TenantID int `json:"accountId` + AccountID int `json:"accountId` GridID int `json:"gid"` Name string `json:"string"` Description string `json:"description"` diff --git a/decort/models_objects.go b/decort/models_objects.go index 33f8ae9..19247ce 100644 --- a/decort/models_objects.go +++ b/decort/models_objects.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2019-2020 Digital Energy Cloud Solutions LLC. All Rights Reserved. +Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved. Author: Sergey Shubin, , Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,8 @@ Visit https://github.com/rudecs/terraform-provider-decort for full source code p package decort +/* + type DiskConfig struct { Label string Size int @@ -65,7 +67,7 @@ type ComputeConfig struct { Description string // The following two parameters are required to create data disks by // a separate disks/create API call - TenantID int + AccountID int GridID int // The following one paratmeter is required to create port forwards // it will be obsoleted when we implement true Resource Groups @@ -81,8 +83,8 @@ type ResgroupQuotaConfig struct { } type ResgroupConfig struct { - TenantID int - TenantName string + AccountID int + AccountName string Location string Name string ID int @@ -90,4 +92,6 @@ type ResgroupConfig struct { ExtIP string // legacy field for VDC - this will eventually become obsoleted by true Resource Groups Quota ResgroupQuotaConfig Network NetworkConfig -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/decort/provider.go b/decort/provider.go index 25aaaef..15d9185 100644 --- a/decort/provider.go +++ b/decort/provider.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 Digital Energy Cloud Solutions LLC. All Rights Reserved. +Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved. Author: Sergey Shubin, , Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package decs +package decort import ( @@ -100,14 +100,18 @@ func Provider() *schema.Provider { }, ResourcesMap: map[string]*schema.Resource { - "decs_resgroup": resourceResgroup(), - "decs_vm": resourceVm(), + "decort_resgroup": resourceResgroup(), + "decort_kvmx86": resourceKvmX86(), + "decort_disk": resourceDisk(), + "decort_vins": resourceVins(), }, DataSourcesMap: map[string]*schema.Resource { - "decs_resgroup": dataSourceResgroup(), - "decs_vm": dataSourceVm(), - "decs_image": dataSourceImage(), + "decort_resgroup": dataSourceResgroup(), + "decs_kvmx86": dataSourceCompute(), + "decort_image": dataSourceImage(), + "decort_disk": dataSourceDisk(), + "decort_vins": dataSourceVins(), }, ConfigureFunc: providerConfigure, diff --git a/decort/resource_resgroup.go b/decort/resource_resgroup.go index 908a467..e41751b 100644 --- a/decort/resource_resgroup.go +++ b/decort/resource_resgroup.go @@ -35,12 +35,12 @@ import ( ) func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error { - log.Printf("resourceResgroupCreate: called for res group name %q, tenant name %q", - d.Get("name").(string), d.Get("tenant").(string)) + log.Debugf("resourceResgroupCreate: called for res group name %q, account name %q", + d.Get("name").(string), d.Get("account").(string)) rg := &ResgroupConfig{ Name: d.Get("name").(string), - TenantName: d.Get("tenant").(string), + AccountName: d.Get("account").(string), } // validate that we have all parameters required to create the new Resource Group @@ -49,35 +49,55 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error { if arg_set { rg.Location = arg_value.(string) } else { - return fmt.Errorf("Cannot create new resource group %q for tenant %q: missing location parameter.", - rg.Name, rg.TenantName) + return fmt.Errorf("Cannot create new RG %q for account %q: missing location parameter.", + rg.Name, rg.AccountName) } - // tenant ID is required to create new resource group - // obtain Tenant ID by tenant name - it should not be zero on success - tenant_id, err := utilityGetTenantIdByName(rg.TenantName, m) + // account ID is required to create new resource group + // obtain Account ID by account name - it should not be zero on success + account_id, err := utilityGetAccountIdByName(rg.AccountName, m) if err != nil { return err } - rg.TenantID = tenant_id + rg.AccountID = account_id set_quotas := false arg_value, arg_set = d.GetOk("quotas") if arg_set { - log.Printf("resourceResgroupCreate: calling makeQuotaConfig") + log.Debugf("resourceResgroupCreate: calling makeQuotaConfig") rg.Quota, _ = makeQuotaConfig(arg_value.([]interface{})) set_quotas = true } controller := m.(*ControllerCfg) - log.Printf("resourceResgroupCreate: called by user %q for Resource group name %q, for tenant %q / ID %d, location %q", + log.Debugf("resourceResgroupCreate: called by user %q for RG name %q, for account %q / ID %d, location %q", controller.getdecortUsername(), - rg.Name, d.Get("tenant"), rg.TenantID, rg.Location) + rg.Name, d.Get("account").(string), rg.AccountID, rg.Location) + /* + type ResgroupCreateParam struct { + AccountID int `json:"accountId"` + GridId int `json:"gid"` + Name string `json:"name"` + Ram int `json:"maxMemoryCapacity"` + Disk int `json:"maxVDiskCapacity"` + Cpu int `json:"maxCPUCapacity"` + NetTraffic int `json:"maxNetworkPeerTransfer"` + ExtIPs int `json:"maxNumPublicIP"` + Owner string `json:"owner"` + DefNet string `json:"def_net"` + IPCidr string `json:"ipcidr"` + Desc string `json:"decs"` + Reason string `json:"reason"` + ExtNetID int `json:"extNetId"` + ExtIP string `json:"extIp"` +} + */ url_values := &url.Values{} - url_values.Add("accountId", fmt.Sprintf("%d", rg.TenantID)) + url_values.Add("accountId", fmt.Sprintf("%d", rg.AccountID)) url_values.Add("name", rg.Name) - url_values.Add("location", rg.Location) - url_values.Add("access", controller.getdecortUsername()) + url_values.Add("gid", rg.Location) + url_values.Add("owner", controller.getdecortUsername()) + url_values.Add("def_net", "NONE") // pass quota values as set if set_quotas { url_values.Add("maxCPUCapacity", fmt.Sprintf("%d", rg.Quota.Cpu)) @@ -89,7 +109,7 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error { // pass externalnetworkid if set arg_value, arg_set = d.GetOk("extnet_id") if arg_set { - url_values.Add("externalnetworkid", fmt.Sprintf("%d", arg_value)) + url_values.Add("extNetId", fmt.Sprintf("%d", arg_value)) } api_resp, err := controller.decortAPICall("POST", ResgroupCreateAPI, url_values) @@ -97,15 +117,15 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error { return err } - d.SetId(api_resp) // cloudspaces/create API plainly returns ID of the newly creted resource group on success + d.SetId(api_resp) // rg/create API returns ID of the newly creted resource group on success rg.ID, _ = strconv.Atoi(api_resp) return resourceResgroupRead(d, m) } func resourceResgroupRead(d *schema.ResourceData, m interface{}) error { - log.Printf("resourceResgroupRead: called for res group name %q, tenant name %q", - d.Get("name").(string), d.Get("tenant").(string)) + log.Debugf("resourceResgroupRead: called for RG name %q, account name %q", + d.Get("name").(string), d.Get("account").(string)) rg_facts, err := utilityResgroupCheckPresence(d, m) if rg_facts == "" { // if empty string is returned from utilityResgroupCheckPresence then there is no @@ -119,13 +139,13 @@ func resourceResgroupRead(d *schema.ResourceData, m interface{}) error { func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error { // this method will only update quotas, if any are set - log.Printf("resourceResgroupUpdate: called for res group name %q, tenant name %q", - d.Get("name").(string), d.Get("tenant").(string)) + log.Debugf("resourceResgroupUpdate: called for RG name %q, account name %q", + d.Get("name").(string), d.Get("account").(string)) quota_value, arg_set := d.GetOk("quotas") if !arg_set { // if there are no quotas set explicitly in the resource configuration - no change will be done - log.Printf("resourceResgroupUpdate: quotas are not set in the resource config - no update on this resource will be done") + log.Debugf("resourceResgroupUpdate: quotas are not set in the resource config - no update on this resource will be done") return resourceResgroupRead(d, m) } quotaconfig_new, _ := makeQuotaConfig(quota_value.([]interface{})) @@ -142,66 +162,68 @@ func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error { if quotaconfig_new.Cpu != quotaconfig_old.Cpu { do_update = true - log.Printf("resourceResgroupUpdate: Cpu diff %d <- %d", quotaconfig_new.Cpu, quotaconfig_old.Cpu) + log.Debugf("resourceResgroupUpdate: Cpu diff %d <- %d", quotaconfig_new.Cpu, quotaconfig_old.Cpu) url_values.Add("maxCPUCapacity", fmt.Sprintf("%d", quotaconfig_new.Cpu)) } if quotaconfig_new.Disk != quotaconfig_old.Disk { do_update = true - log.Printf("resourceResgroupUpdate: Disk diff %d <- %d", quotaconfig_new.Disk, quotaconfig_old.Disk) + log.Debugf("resourceResgroupUpdate: Disk diff %d <- %d", quotaconfig_new.Disk, quotaconfig_old.Disk) url_values.Add("maxVDiskCapacity", fmt.Sprintf("%d", quotaconfig_new.Disk)) } if quotaconfig_new.Ram != quotaconfig_old.Ram { do_update = true - log.Printf("resourceResgroupUpdate: Ram diff %f <- %f", quotaconfig_new.Ram, quotaconfig_old.Ram) + log.Debugf("resourceResgroupUpdate: Ram diff %f <- %f", quotaconfig_new.Ram, quotaconfig_old.Ram) url_values.Add("maxMemoryCapacity", fmt.Sprintf("%f", quotaconfig_new.Ram)) } if quotaconfig_new.NetTraffic != quotaconfig_old.NetTraffic { do_update = true - log.Printf("resourceResgroupUpdate: NetTraffic diff %d <- %d", quotaconfig_new.NetTraffic, quotaconfig_old.NetTraffic) + log.Debugf("resourceResgroupUpdate: NetTraffic diff %d <- %d", quotaconfig_new.NetTraffic, quotaconfig_old.NetTraffic) url_values.Add("maxNetworkPeerTransfer", fmt.Sprintf("%d", quotaconfig_new.NetTraffic)) } if quotaconfig_new.ExtIPs != quotaconfig_old.ExtIPs { do_update = true - log.Printf("resourceResgroupUpdate: ExtIPs diff %d <- %d", quotaconfig_new.ExtIPs, quotaconfig_old.ExtIPs) + log.Debugf("resourceResgroupUpdate: ExtIPs diff %d <- %d", quotaconfig_new.ExtIPs, quotaconfig_old.ExtIPs) url_values.Add("maxNumPublicIP", fmt.Sprintf("%d", quotaconfig_new.ExtIPs)) } if do_update { - log.Printf("resourceResgroupUpdate: some new quotas are set - updating the resource") + log.Debugf("resourceResgroupUpdate: some new quotas are set - updating the resource") _, err := controller.decortAPICall("POST", ResgroupUpdateAPI, url_values) if err != nil { return err } } else { - log.Printf("resourceResgroupUpdate: no difference in quotas between old and new state - no update on this resource will be done") + log.Debugf("resourceResgroupUpdate: no difference in quotas between old and new state - no update on this resource will be done") } return resourceResgroupRead(d, m) } func resourceResgroupDelete(d *schema.ResourceData, m interface{}) error { - // NOTE: this method destroys target resource group with flag "permanently", so there is no way to - // restore the destroyed resource group as well all VMs that existed in it - log.Printf("resourceResgroupDelete: called for res group name %q, tenant name %q", - d.Get("name").(string), d.Get("tenant").(string)) - - vm_facts, err := utilityResgroupCheckPresence(d, m) - if vm_facts == "" { - // the target VM does not exist - in this case according to Terraform best practice + // 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").(string)) + + rg_facts, err := utilityResgroupCheckPresence(d, m) + if rg_facts == "" { + // the target RG 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("cloudspaceId", d.Id()) + params.Add("rgId", d.Id()) + params.Add("force", "true") params.Add("permanently", "true") + params.Add("reason", "Destroyed by DECORT Terraform provider") controller := m.(*ControllerCfg) - vm_facts, err = controller.decortAPICall("POST", CloudspacesDeleteAPI, params) + vm_facts, err = controller.decortAPICall("POST", ResgroupDeleteAPI, params) if err != nil { return err } @@ -243,13 +265,13 @@ func resourceResgroup() *schema.Resource { "name": &schema.Schema { Type: schema.TypeString, Required: true, - Description: "Name of this resource group. Names are case sensitive and unique within the context of a tenant.", + Description: "Name of this resource group. Names are case sensitive and unique within the context of a account.", }, - "tenant": &schema.Schema { + "account": &schema.Schema { Type: schema.TypeString, Required: true, - Description: "Name of the tenant, which this resource group belongs to.", + Description: "Name of the account, which this resource group belongs to.", }, "extnet_id": &schema.Schema { @@ -258,31 +280,18 @@ func resourceResgroup() *schema.Resource { Description: "ID of the external network, which this resource group will be connected to by default.", }, - "tenant_id": &schema.Schema { + "account_id": &schema.Schema { Type: schema.TypeInt, Computed: true, - Description: "Unique ID of the tenant, which this resource group belongs to.", + Description: "Unique ID of the account, which this resource group belongs to.", }, "grid_id": &schema.Schema { Type: schema.TypeInt, - Computed: true, + Required: true, Description: "Unique ID of the grid, where this resource group is deployed.", }, - "location": &schema.Schema { - Type: schema.TypeString, - Optional: true, // note that it is a REQUIRED parameter when creating new resource group - ForceNew: true, - Description: "Name of the location where this resource group should exist.", - }, - - "public_ip": { // this may be obsoleted as new network segments and true resource groups are implemented - Type: schema.TypeString, - Computed: true, - Description: "Public IP address of this resource group (if any).", - }, - "quotas": { Type: schema.TypeList, Optional: true, diff --git a/decort/utility_resgroup.go b/decort/utility_resgroup.go index ea7c840..c26ddf5 100644 --- a/decort/utility_resgroup.go +++ b/decort/utility_resgroup.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2019-2020 Digital Energy Cloud Solutions LLC. All Rights Reserved. +Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved. Author: Sergey Shubin, , Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,23 +36,24 @@ import ( // "github.com/hashicorp/terraform/helper/validation" ) -func (ctrl *ControllerCfg) utilityResgroupConfigGet(rgid int) (*ResgroupConfig, error) { +func (ctrl *ControllerCfg) utilityResgroupConfigGet(rgid int) (*ResgroupGetResp, error) { url_values := &url.Values{} - url_values.Add("cloudspaceId", fmt.Sprintf("%d", rgid)) - resgroup_facts, err := ctrl.decortAPICall("POST", CloudspacesGetAPI, url_values) + url_values.Add("rgId", fmt.Sprintf("%d", rgid)) + resgroup_facts, err := ctrl.decortAPICall("POST", ResgroupGetAPI, url_values) if err != nil { return nil, err } - log.Printf("utilityResgroupConfigGet: ready to unmarshal string %q", resgroup_facts) - model := CloudspacesGetResp{} - err = json.Unmarshal([]byte(resgroup_facts), &model) + log.Debugf("utilityResgroupConfigGet: ready to unmarshal string %q", resgroup_facts) + model := &ResgroupGetResp{} + err = json.Unmarshal([]byte(resgroup_facts), model) if err != nil { return nil, err } + /* ret := &ResgroupConfig{} - ret.TenantID = model.TenantID + ret.AccountID = model.AccountID ret.Location = model.Location ret.Name = model.Name ret.ID = rgid @@ -60,53 +61,58 @@ func (ctrl *ControllerCfg) utilityResgroupConfigGet(rgid int) (*ResgroupConfig, ret.ExtIP = model.ExtIP // legacy field for VDC - this will eventually become obsoleted by true Resource Groups // Quota ResgroupQuotaConfig // Network NetworkConfig - log.Printf("utilityResgroupConfigGet: tenant ID %d, GridID %d, ExtIP %q", - model.TenantID, model.GridID, model.ExtIP) + */ + log.Debugf("utilityResgroupConfigGet: account ID %d, GridID %d, Name %s", + model.AccountID, model.GridID, model.Name) - return ret, nil + return model, nil } func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string, error) { - // This function tries to locate resource group by its name and tenant name. + // This function tries to locate resource group by its name and account name. // If succeeded, it returns non empty string that contains JSON formatted facts about the // resource group as returned by cloudspaces/get API call. // Otherwise it returns empty string and 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 resource's Exists method. // name := d.Get("name").(string) - tenant_name := d.Get("tenant").(string) + account_name := d.Get("account").(string) controller := m.(*ControllerCfg) url_values := &url.Values{} url_values.Add("includedeleted", "false") - body_string, err := controller.decortAPICall("POST", CloudspacesListAPI, url_values) + body_string, err := controller.decortAPICall("POST", ResgroupListAPI, url_values) if err != nil { return "", err } - log.Printf("%s", body_string) - log.Printf("utilityResgroupCheckPresence: ready to decode response body from %q", CloudspacesListAPI) + log.Debugf("%s", body_string) + log.Debugf("utilityResgroupCheckPresence: ready to decode response body from %q", ResgroupListAPI) model := CloudspacesListResp{} err = json.Unmarshal([]byte(body_string), &model) if err != nil { return "", err } - log.Printf("utilityResgroupCheckPresence: traversing decoded Json of length %d", len(model)) + log.Debugf("utilityResgroupCheckPresence: traversing decoded Json of length %d", len(model)) for index, item := range model { - // need to match VDC by name & tenant name - if item.Name == name && item.TenantName == tenant_name { - log.Printf("utilityResgroupCheckPresence: match ResGroup name %q / ID %d, tenant %q at index %d", - item.Name, item.ID, item.TenantName, index) + // need to match RG by name & account name + if item.Name == name && item.AccountName == account_name { + log.Debugf("utilityResgroupCheckPresence: match RG name %q / ID %d, account %q at index %d", + item.Name, item.ID, item.AccountName, index) - // not all required information is returned by cloudspaces/list API, so we need to initiate one more - // call to cloudspaces/get to obtain extra data to complete Resource population. + // 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 to extract resource quota settings req_values := &url.Values{} - req_values.Add("cloudspaceId", fmt.Sprintf("%d", item.ID)) - body_string, err := controller.decortAPICall("POST", CloudspacesGetAPI, req_values) + req_values.Add("rgId", fmt.Sprintf("%d", item.ID)) + body_string, err := controller.decortAPICall("POST", ResgroupGetAPI, req_values) if err != nil { return "", err } @@ -115,32 +121,32 @@ func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string } } - return "", fmt.Errorf("Cannot find resource group name %q owned by tenant %q", name, tenant_name) + return "", fmt.Errorf("Cannot find RG name %q owned by account %q", name, account_name) } -func utilityGetTenantIdByName(tenant_name string, m interface{}) (int, error) { +func utilityGetAccountIdByName(account_name string, m interface{}) (int, error) { controller := m.(*ControllerCfg) url_values := &url.Values{} - body_string, err := controller.decortAPICall("POST", TenantsListAPI, url_values) + body_string, err := controller.decortAPICall("POST", AccountsListAPI, url_values) if err != nil { return 0, err } - model := TenantsListResp{} + model := AccountsListResp{} err = json.Unmarshal([]byte(body_string), &model) if err != nil { return 0, err } - log.Printf("utilityGetTenantIdByName: traversing decoded Json of length %d", len(model)) + log.Debugf("utilityGetAccountIdByName: traversing decoded Json of length %d", len(model)) for index, item := range model { - // need to match Tenant by name - if item.Name == tenant_name { - log.Printf("utilityGetTenantIdByName: match Tenant name %q / ID %d at index %d", + // need to match Account by name + if item.Name == account_name { + log.Debugf("utilityGetAccountIdByName: match Account name %q / ID %d at index %d", item.Name, item.ID, index) return item.ID, nil } } - return 0, fmt.Errorf("Cannot find tenant %q for the current user. Check tenant value and your access rights", tenant_name) + return 0, fmt.Errorf("Cannot find account %q for the current user. Check account value and your access rights", account_name) } \ No newline at end of file