Implement disk management, phase 1

rc-1.0
Sergey Shubin svs1370 4 years ago
parent 32947819f6
commit 30742c30e9

@ -61,11 +61,11 @@ func flattenDisk(d *schema.ResourceData, disk_facts string) error {
d.Set("sep_id", model.SepID)
d.Set("sep_type", model.SepType)
d.Set("pool", model.Pool)
d.Set("compute_id", model.ComputeID)
// d.Set("compute_id", model.ComputeID)
d.Set("description", model.Desc)
d.Set("status", model.Status)
d.Set("tech_status", model.TechStatus)
// d.Set("status", model.Status)
// d.Set("tech_status", model.TechStatus)
/* we do not manage snapshots via Terraform yet, so keep this commented out for a while
if len(model.Snapshots) > 0 {
@ -96,37 +96,32 @@ func dataSourceDiskSchemaMake() map[string]*schema.Schema {
"name": {
Type: schema.TypeString,
Optional: true,
Description: "Name of this disk. NOTE: disk names are NOT unique within an account.",
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 name, account and account ID are ignored.",
Description: "ID of the disk to get. If disk ID is specified, then disk name and account ID are ignored.",
},
"account_id": {
Type: schema.TypeInt,
Optional: true,
Description: "ID of the account this disk belongs to.",
Description: "ID of the account this disk belongs to. If disk ID is specified, then account ID is ignored.",
},
"account_name": {
Type: schema.TypeString,
Optional: true,
Description: "Name of the account this disk belongs to. If account ID is specified, account name is ignored.",
},
"description": {
Type: schema.TypeString,
// The rest of the data source Disk schema are all computed
"sep_id": {
Type: schema.TypeInt,
Computed: true,
Description: "User-defined text description of this disk.",
Description: "Storage end-point provider serving this disk.",
},
"image_id": {
Type: schema.TypeInt,
"pool": {
Type: schema.TypeString,
Computed: true,
Description: "ID of the image, which this disk was cloned from.",
Description: "Pool where this disk is located.",
},
"size": {
@ -141,21 +136,22 @@ func dataSourceDiskSchemaMake() map[string]*schema.Schema {
Description: "Type of this disk.",
},
/*
"snapshots": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource {
Schema: snapshotSubresourceSchemaMake(),
},
Description: "List of user-created snapshots for this disk."
},
*/
"description": {
Type: schema.TypeString,
Computed: true,
Description: "User-defined text description of this disk.",
},
"sep_id": {
"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.",
},
"image_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Storage end-point provider serving this disk.",
Description: "ID of the image, which this disk was cloned from (valid for disk clones only).",
},
"sep_type": {
@ -164,11 +160,15 @@ func dataSourceDiskSchemaMake() map[string]*schema.Schema {
Description: "Type of the storage end-point provider serving this disk.",
},
"pool": {
Type: schema.TypeString,
Computed: true,
Description: "Pool where this disk is located.",
},
/*
"snapshots": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource {
Schema: snapshotSubresourceSchemaMake(),
},
Description: "List of user-created snapshots for this disk."
},
"status": {
Type: schema.TypeString,
@ -187,6 +187,7 @@ func dataSourceDiskSchemaMake() map[string]*schema.Schema {
Computed: true,
Description: "ID of the compute instance where this disk is attached to, or 0 for unattached disk.",
},
*/
}
return rets

@ -476,17 +476,6 @@ const ComputeDiskDetachAPI = "/restmachine/cloudapi/compute/diskDetach"
//
// structures related to /cloudapi/disks/create
//
type DiskCreateParam struct {
AccountID int `json:"accountId`
GridID int `json:"gid"`
Name string `json:"string"`
Description string `json:"description"`
Size int `json:"size"`
Type string `json:"type"`
SepID int `json:"sep_id"`
Pool string `json:"pool"`
}
const DiskCreateAPI = "/restmachine/cloudapi/disks/create"
//
@ -499,6 +488,20 @@ const DisksGetAPI = "/restmachine/cloudapi/disks/get" // Returns single DiskReco
const DisksListAPI = "/restmachine/cloudapi/disks/list" // Returns list of DiskRecord on success
type DisksListResp []DiskRecord
//
// Grid ID structures
//
type LocationRecord struct {
GridID int `json:"gid"`
Id int `json:"id"`
LocationCode string `json:"locationCode"`
Name string `json:"name"`
Flag string `json:"flag"`
}
const LocationsListAPI = "/restmachine/cloudapi/locations/list" // Returns list of GridRecord on success
type LocationsListResp []LocationRecord
//
// Auxiliary structures
//

@ -18,6 +18,7 @@ limitations under the License.
package decort
import (
"fmt"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
@ -110,7 +111,7 @@ func Provider() *schema.Provider {
"decort_resgroup": dataSourceResgroup(),
"decort_kvmvm": dataSourceCompute(),
"decort_image": dataSourceImage(),
// "decort_disk": dataSourceDisk(),
"decort_disk": dataSourceDisk(),
// "decort_vins": dataSourceVins(),
// "decort_pfw": dataSourcePfw(),
},
@ -128,5 +129,15 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
if err != nil {
return nil, err
}
// initialize global default Grid ID - it will be needed to create some resource types, e.g. disks
gridId, err := decsController.utilityLocationGetDefaultGridID()
if err != nil {
return nil, err
}
if gridId == 0 {
return nil, fmt.Errorf("providerConfigure: invalid default Grid ID = 0")
}
return decsController, nil
}

@ -37,7 +37,7 @@ import (
)
func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
// we assume all mandatiry parameters it takes to create a comptue instance are properly
// we assume all mandatory parameters it takes to create a comptue instance are properly
// specified - we rely on schema "Required" attributes to let Terraform validate them for us
log.Debugf("resourceComputeCreate: called for Compute name %q, RG ID %d", d.Get("name").(string), d.Get("rg_id").(int))

@ -0,0 +1,243 @@
/*
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
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.
*/
/*
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
Technology platfom.
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
*/
package decort
import (
// "encoding/json"
"fmt"
"net/url"
"strconv"
log "github.com/sirupsen/logrus"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
// "github.com/hashicorp/terraform-plugin-sdk/helper/validation"
)
func resourceDiskCreate(d *schema.ResourceData, m interface{}) error {
log.Debugf("resourceDiskCreate: called for Disk name %q, Account ID %d", d.Get("name").(string), d.Get("account_id").(int))
controller := m.(*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", DefaultGridID)) // we use default Grid ID, which was obtained along with DECORT Controller init
urlValues.Add("name", d.Get("name").(string))
urlValues.Add("size", d.Get("size").(string))
urlValues.Add("type", d.Get("type").(string))
urlValues.Add("sep_id", fmt.Sprintf("%d", d.Get("sep_id").(int)))
urlValues.Add("pool", d.Get("pool").(string))
argVal, argSet := d.GetOk("description")
if argSet {
urlValues.Add("decs", argVal.(string))
}
apiResp, err := controller.decortAPICall("POST", DiskCreateAPI, urlValues)
if err != nil {
return err
}
d.SetId(apiResp) // update ID of the resource to tell Terraform that the disk resource exists
diskId, _ := strconv.Atoi(apiResp)
log.Debugf("resourceDiskCreate: new Disk ID %d, name %q creation sequence complete", diskId, d.Get("name").(string))
// 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(d, m)
}
func resourceDiskRead(d *schema.ResourceData, m interface{}) error {
disk_facts, err := utilityDiskCheckPresence(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 err
}
return flattenDisk(d, disk_facts)
}
func resourceDiskUpdate(d *schema.ResourceData, m interface{}) error {
log.Debugf("resourceDiskUpdate: called for disk name %q, Account ID %d",
d.Get("name").(string), d.Get("account_id").(int))
log.Warn("resourceDiskUpdate: NOT IMPLEMENTED YET!")
// we may reuse dataSourceDiskRead here as we maintain similarity
// between Compute resource and Compute data source schemas
return dataSourceDiskRead(d, m)
}
func resourceDiskDelete(d *schema.ResourceData, m interface{}) error {
log.Warn("resourceDiskDelete: NOT IMPLEMENTED YET!")
return nil
}
func resourceDiskExists(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 name %q, Account ID %d",
d.Get("name").(string), d.Get("account_id").(int))
diskFacts, err := utilityDiskCheckPresence(d, m)
if diskFacts == "" {
if err != nil {
return false, err
}
return false, nil
}
return true, nil
}
func resourceDiskSchemaMake() 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.",
},
"account_id": {
Type: schema.TypeInt,
Optional: true,
Description: "ID of the account this disk belongs to.",
},
"sep_id": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
Description: "Storage end-point provider serving this disk. Cannot be changed for existing disk.",
},
"pool": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Pool where this disk is located. Cannot be changed for existing disk.",
},
"size": {
Type: schema.TypeInt,
Required: true,
Description: "Size of the disk in GB. Note, that existing disks can only be grown in size.",
},
"type": {
Type: schema.TypeString,
Optional: true,
Default: "D",
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,
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.",
},
"image_id": {
Type: schema.TypeInt,
Computed: true,
Description: "ID of the image, which this disk was cloned from (if ever cloned).",
},
"sep_type": {
Type: schema.TypeString,
Computed: true,
Description: "Type of the storage end-point provider serving this disk.",
},
/*
"snapshots": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource {
Schema: snapshotSubresourceSchemaMake(),
},
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.",
},
"compute_id": {
Type: schema.TypeInt,
Computed: true,
Description: "ID of the compute instance where this disk is attached to, or 0 for unattached disk.",
},
*/
}
return rets
}
func resourceDisk() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
Create: resourceDiskCreate,
Read: resourceDiskRead,
Update: resourceDiskUpdate,
Delete: resourceDiskDelete,
Exists: resourceDiskExists,
Timeouts: &schema.ResourceTimeout{
Create: &Timeout180s,
Read: &Timeout30s,
Update: &Timeout180s,
Delete: &Timeout60s,
Default: &Timeout60s,
},
Schema: resourceDiskSchemaMake(),
}
}

@ -122,7 +122,7 @@ func utilityGetAccountIdBySchema(d *schema.ResourceData, m interface{}) (int, er
accName, argSet := d.GetOk("account_name")
if !argSet {
return 0, fmt.Errorf("Either non-empty account name or positive account ID must be specified")
return 0, fmt.Errorf("Either non-empty account name or valid account ID must be specified")
}
controller := m.(*ControllerCfg)

@ -0,0 +1,65 @@
/*
Copyright (c) 2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
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.
*/
/*
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
Technology platfom.
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
*/
package decort
import (
"encoding/json"
"fmt"
"net/url"
log "github.com/sirupsen/logrus"
// "github.com/hashicorp/terraform-plugin-sdk/helper/schema"
// "github.com/hashicorp/terraform-plugin-sdk/helper/validation"
)
var DefaultGridID int
func (controller *ControllerCfg) utilityLocationGetDefaultGridID() (int, error) {
urlValues := &url.Values{}
log.Debug("utilityLocationGetDefaultGridID: retrieving locations list")
apiResp, err := controller.decortAPICall("POST", LocationsListAPI, urlValues)
if err != nil {
return 0, err
}
locList := LocationsListResp{}
err = json.Unmarshal([]byte(apiResp), &locList)
if err != nil {
return 0, err
}
if len(locList) == 0 {
DefaultGridID = 0
return 0, fmt.Errorf("utilityLocationGetDefaultGridID: retrieved 0 length locations list")
}
DefaultGridID = locList[0].GridID
log.Debugf("utilityLocationGetDefaultGridID: default location GridID %d, name %s", DefaultGridID, locList[0].Name)
return DefaultGridID, nil
}
Loading…
Cancel
Save