driver fix; start/stop compute

rc-1.25
kjubybot 3 years ago
parent 8058b1c08f
commit 5db588e5dc

@ -27,6 +27,7 @@ package decort
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
// "net/url" // "net/url"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -36,20 +37,20 @@ import (
) )
// Parse list of all disks from API compute/get into a list of "extra disks" attached to this compute // Parse list of all disks from API compute/get into a list of "extra disks" attached to this compute
// Extra disks are all compute disks but a boot disk. // Extra disks are all compute disks but a boot disk.
func parseComputeDisksToExtraDisks(disks []DiskRecord) []interface{} { func parseComputeDisksToExtraDisks(disks []DiskRecord) []interface{} {
// this return value will be used to d.Set("extra_disks",) item of dataSourceCompute schema, // this return value will be used to d.Set("extra_disks",) item of dataSourceCompute schema,
// which is a simple list of integer disk IDs excluding boot disk ID // which is a simple list of integer disk IDs excluding boot disk ID
length := len(disks) length := len(disks)
log.Debugf("parseComputeDisksToExtraDisks: called for %d disks", length) log.Debugf("parseComputeDisksToExtraDisks: called for %d disks", length)
if length == 0 || ( length == 1 && disks[0].Type == "B" ) { if length == 0 || (length == 1 && disks[0].Type == "B") {
// the disk list is empty (which is kind of strange - diskless compute?), or // the disk list is empty (which is kind of strange - diskless compute?), or
// there is only one disk in the list and it is a boot disk; // there is only one disk in the list and it is a boot disk;
// as we skip boot disks, the result will be of 0 length anyway // as we skip boot disks, the result will be of 0 length anyway
return make([]interface{}, 0) return make([]interface{}, 0)
} }
result := make([]interface{}, length-1) result := make([]interface{}, length-1)
idx := 0 idx := 0
for _, value := range disks { for _, value := range disks {
@ -62,7 +63,7 @@ func parseComputeDisksToExtraDisks(disks []DiskRecord) []interface{} {
idx++ idx++
} }
return result return result
} }
// NOTE: this is a legacy function, which is not used as of rc-1.10 // NOTE: this is a legacy function, which is not used as of rc-1.10
@ -70,18 +71,18 @@ func parseComputeDisksToExtraDisks(disks []DiskRecord) []interface{} {
func parseComputeDisks(disks []DiskRecord) []interface{} { func parseComputeDisks(disks []DiskRecord) []interface{} {
// Return value was designed to d.Set("disks",) item of dataSourceCompute schema // Return value was designed to d.Set("disks",) item of dataSourceCompute schema
// However, this item was excluded from the schema as it is not directly // However, this item was excluded from the schema as it is not directly
// managed through Terraform // managed through Terraform
length := len(disks) length := len(disks)
log.Debugf("parseComputeDisks: called for %d disks", length) log.Debugf("parseComputeDisks: called for %d disks", length)
/* /*
if length == 1 && disks[0].Type == "B" { if length == 1 && disks[0].Type == "B" {
// there is only one disk in the list and it is a boot disk // there is only one disk in the list and it is a boot disk
// as we skip boot disks, the result will be of 0 lenght // as we skip boot disks, the result will be of 0 lenght
length = 0 length = 0
} }
*/ */
result := []interface{}{} result := []interface{}{}
if length == 0 { if length == 0 {
@ -90,10 +91,10 @@ func parseComputeDisks(disks []DiskRecord) []interface{} {
for _, value := range disks { for _, value := range disks {
/* /*
if value.Type == "B" { if value.Type == "B" {
// skip boot disk when parsing the list of disks // skip boot disk when parsing the list of disks
continue continue
} }
*/ */
elem := make(map[string]interface{}) elem := make(map[string]interface{})
// keys in this map should correspond to the Schema definition // keys in this map should correspond to the Schema definition
@ -112,11 +113,11 @@ func parseComputeDisks(disks []DiskRecord) []interface{} {
// elem["status"] = value.Status // elem["status"] = value.Status
// elem["tech_status"] = value.TechStatus // elem["tech_status"] = value.TechStatus
elem["compute_id"] = value.ComputeID elem["compute_id"] = value.ComputeID
result = append(result, elem) result = append(result, elem)
} }
return result return result
} }
func parseBootDiskSize(disks []DiskRecord) int { func parseBootDiskSize(disks []DiskRecord) int {
@ -131,7 +132,7 @@ func parseBootDiskSize(disks []DiskRecord) int {
} }
} }
return 0 return 0
} }
func parseBootDiskId(disks []DiskRecord) uint { func parseBootDiskId(disks []DiskRecord) uint {
@ -146,10 +147,10 @@ func parseBootDiskId(disks []DiskRecord) uint {
} }
} }
return 0 return 0
} }
// Parse the list of interfaces from compute/get response into a list of networks // Parse the list of interfaces from compute/get response into a list of networks
// attached to this compute // attached to this compute
func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []interface{} { func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []interface{} {
// return value will be used to d.Set("network") item of dataSourceCompute schema // return value will be used to d.Set("network") item of dataSourceCompute schema
@ -172,8 +173,9 @@ func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []interface{} {
result = append(result, elem) result = append(result, elem)
} }
return result return result
} }
/* /*
func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []map[string]interface{} { func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []map[string]interface{} {
// return value will be used to d.Set("network") item of dataSourceCompute schema // return value will be used to d.Set("network") item of dataSourceCompute schema
@ -196,16 +198,15 @@ func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []map[string]int
result[i] = elem result[i] = elem
} }
return result return result
} }
*/ */
// NOTE: this function is retained for historical purposes and actually not used as of rc-1.10 // NOTE: this function is retained for historical purposes and actually not used as of rc-1.10
func parseComputeInterfaces(ifaces []InterfaceRecord) []map[string]interface{} { func parseComputeInterfaces(ifaces []InterfaceRecord) []map[string]interface{} {
// return value was designed to d.Set("interfaces",) item of dataSourceCompute schema // return value was designed to d.Set("interfaces",) item of dataSourceCompute schema
// However, this item was excluded from the schema as it is not directly // However, this item was excluded from the schema as it is not directly
// managed through Terraform // managed through Terraform
length := len(ifaces) length := len(ifaces)
log.Debugf("parseComputeInterfaces: called for %d ifaces", length) log.Debugf("parseComputeInterfaces: called for %d ifaces", length)
@ -237,7 +238,7 @@ func parseComputeInterfaces(ifaces []InterfaceRecord) []map[string]interface{} {
result[i] = elem result[i] = elem
} }
return result return result
} }
func flattenCompute(d *schema.ResourceData, compFacts string) error { func flattenCompute(d *schema.ResourceData, compFacts string) error {
@ -274,6 +275,12 @@ func flattenCompute(d *schema.ResourceData, compFacts string) error {
// d.Set("status", model.Status) // d.Set("status", model.Status)
// d.Set("tech_status", model.TechStatus) // d.Set("tech_status", model.TechStatus)
if model.TechStatus == "STARTED" {
d.Set("started", true)
} else {
d.Set("started", false)
}
if len(model.Disks) > 0 { if len(model.Disks) > 0 {
log.Debugf("flattenCompute: calling parseComputeDisksToExtraDisks for %d disks", len(model.Disks)) log.Debugf("flattenCompute: calling parseComputeDisksToExtraDisks for %d disks", len(model.Disks))
if err = d.Set("extra_disks", parseComputeDisksToExtraDisks(model.Disks)); err != nil { if err = d.Set("extra_disks", parseComputeDisksToExtraDisks(model.Disks)); err != nil {
@ -403,24 +410,24 @@ func dataSourceCompute() *schema.Resource {
}, },
"extra_disks": { "extra_disks": {
Type: schema.TypeSet, Type: schema.TypeSet,
Computed: true, Computed: true,
MaxItems: MaxExtraDisksPerCompute, MaxItems: MaxExtraDisksPerCompute,
Elem: &schema.Schema { Elem: &schema.Schema{
Type: schema.TypeInt, Type: schema.TypeInt,
}, },
Description: "IDs of the extra disk(s) attached to this compute.", Description: "IDs of the extra disk(s) attached to this compute.",
}, },
/* /*
"disks": { "disks": {
Type: schema.TypeList, Type: schema.TypeList,
Computed: true, Computed: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: dataSourceDiskSchemaMake(), // ID, type, name, size, account ID, SEP ID, SEP type, pool, status, tech status, compute ID, image ID Schema: dataSourceDiskSchemaMake(), // ID, type, name, size, account ID, SEP ID, SEP type, pool, status, tech status, compute ID, image ID
},
Description: "Detailed specification for all disks attached to this compute instance (including bood disk).",
}, },
Description: "Detailed specification for all disks attached to this compute instance (including bood disk).",
},
*/ */
"network": { "network": {
@ -434,14 +441,14 @@ func dataSourceCompute() *schema.Resource {
}, },
/* /*
"interfaces": { "interfaces": {
Type: schema.TypeList, Type: schema.TypeList,
Computed: true, Computed: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: interfaceSubresourceSchemaMake(), Schema: interfaceSubresourceSchemaMake(),
},
Description: "Specification for the virtual NICs configured on this compute instance.",
}, },
Description: "Specification for the virtual NICs configured on this compute instance.",
},
*/ */
"os_users": { "os_users": {
@ -465,24 +472,31 @@ func dataSourceCompute() *schema.Resource {
Description: "Placeholder for cloud_init parameters.", Description: "Placeholder for cloud_init parameters.",
}, },
/* "started": {
"status": { Type: schema.TypeBool,
Type: schema.TypeString, Optional: true,
Computed: true, Default: true,
Description: "Current model status of this compute instance.", Description: "Is compute started.",
}, },
"tech_status": { /*
Type: schema.TypeString, "status": {
Computed: true, Type: schema.TypeString,
Description: "Current technical status of this compute instance.", Computed: true,
}, Description: "Current model status of this compute instance.",
},
"internal_ip": { "tech_status": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
Description: "Internal IP address of this Compute.", Description: "Current technical status of this compute instance.",
}, },
"internal_ip": {
Type: schema.TypeString,
Computed: true,
Description: "Internal IP address of this Compute.",
},
*/ */
}, },
} }

@ -105,12 +105,12 @@ type ResgroupUpdateParam struct {
// structures related to /cloudapi/rg/get API call // structures related to /cloudapi/rg/get API call
// //
type QuotaRecord struct { // this is how quota is reported by /api/.../rg/get type QuotaRecord struct { // this is how quota is reported by /api/.../rg/get
Cpu int `json:"CU_C"` // CPU count in pcs Cpu int `json:"CU_C"` // CPU count in pcs
Ram float64 `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 Disk int `json:"CU_D"` // Disk capacity in GB
ExtIPs int `json:"CU_I"` // Ext IPs count ExtIPs int `json:"CU_I"` // Ext IPs count
ExtTraffic int `json:"CU_NP"` // Ext network traffic ExtTraffic int `json:"CU_NP"` // Ext network traffic
GpuUnits int `json:"gpu_units"` // GPU count GpuUnits int `json:"gpu_units"` // GPU count
} }
type ResourceRecord struct { // this is how actual usage is reported by /api/.../rg/get type ResourceRecord struct { // this is how actual usage is reported by /api/.../rg/get
@ -130,27 +130,27 @@ type UsageRecord struct {
const ResgroupGetAPI = "/restmachine/cloudapi/rg/get" const ResgroupGetAPI = "/restmachine/cloudapi/rg/get"
type ResgroupGetResp struct { type ResgroupGetResp struct {
ACLs []UserAclRecord `json:"ACLs"` ACLs []UserAclRecord `json:"ACLs"`
Usage UsageRecord `json:"Resources"` Usage UsageRecord `json:"Resources"`
AccountID int `json:"accountId"` AccountID int `json:"accountId"`
AccountName string `json:"accountName"` AccountName string `json:"accountName"`
GridID int `json:"gid"` GridID int `json:"gid"`
CreatedBy string `json:"createdBy"` CreatedBy string `json:"createdBy"`
CreatedTime uint64 `json:"createdTime"` CreatedTime uint64 `json:"createdTime"`
DefaultNetID int `json:"def_net_id"` DefaultNetID int `json:"def_net_id"`
DefaultNetType string `json:"def_net_type"` DefaultNetType string `json:"def_net_type"`
DeletedBy string `json:"deletedBy"` DeletedBy string `json:"deletedBy"`
DeletedTime uint64 `json:"deletedTime"` DeletedTime uint64 `json:"deletedTime"`
Desc string `json:"desc"` Desc string `json:"desc"`
ID uint `json:"id"` ID uint `json:"id"`
LockStatus string `json:"lockStatus"` LockStatus string `json:"lockStatus"`
Name string `json:"name"` Name string `json:"name"`
Quota QuotaRecord `json:"resourceLimits"` Quota QuotaRecord `json:"resourceLimits"`
Status string `json:"status"` Status string `json:"status"`
UpdatedBy string `json:"updatedBy"` UpdatedBy string `json:"updatedBy"`
UpdatedTime uint64 `json:"updatedTime"` UpdatedTime uint64 `json:"updatedTime"`
Vins []int `json:"vins"` Vins []int `json:"vins"`
Computes []int `json:"vms"` Computes []int `json:"vms"`
Ignored map[string]interface{} `json:"-"` Ignored map[string]interface{} `json:"-"`
} }
@ -187,22 +187,23 @@ const KvmX86CreateAPI = "/restmachine/cloudapi/kvmx86/create"
const KvmPPCCreateAPI = "/restmachine/cloudapi/kvmppc/create" const KvmPPCCreateAPI = "/restmachine/cloudapi/kvmppc/create"
type KvmVmCreateParam struct { // this is unified structure for both x86 and PPC based KVM VMs creation type KvmVmCreateParam struct { // this is unified structure for both x86 and PPC based KVM VMs creation
RgID uint `json:"rgId"` RgID uint `json:"rgId"`
Name string `json:"name"` Name string `json:"name"`
Cpu int `json:"cpu"` Cpu int `json:"cpu"`
Ram int `json:"ram"` Ram int `json:"ram"`
ImageID int `json:"imageId"` ImageID int `json:"imageId"`
BootDisk int `json:"bootDisk"` BootDisk int `json:"bootDisk"`
NetType string `json:"netType"` NetType string `json:"netType"`
NetId int `json:"netId"` NetId int `json:"netId"`
IPAddr string `json:"ipAddr"` IPAddr string `json:"ipAddr"`
UserData string `json:"userdata"` UserData string `json:"userdata"`
Desc string `json:"desc"` Desc string `json:"desc"`
Start bool `json:"start"` Start bool `json:"start"`
} }
// structures related to cloudapi/compute/start API // structures related to cloudapi/compute/start API
const ComputeStartAPI = "/restmachine/cloudapi/compute/start" const ComputeStartAPI = "/restmachine/cloudapi/compute/start"
const ComputeStopAPI = "/restmachine/cloudapi/compute/stop"
// structures related to cloudapi/compute/delete API // structures related to cloudapi/compute/delete API
const ComputeDeleteAPI = "/restmachine/cloudapi/compute/delete" const ComputeDeleteAPI = "/restmachine/cloudapi/compute/delete"
@ -271,14 +272,14 @@ type ComputeRecord struct {
SnapSets []SnapSetRecord `json:"snapSets"` SnapSets []SnapSetRecord `json:"snapSets"`
Status string `json:"status"` Status string `json:"status"`
// Tags []string `json:"tags"` // Tags were reworked since DECORT 3.7.1 // Tags []string `json:"tags"` // Tags were reworked since DECORT 3.7.1
TechStatus string `json:"techStatus"` TechStatus string `json:"techStatus"`
TotalDiskSize int `json:"totalDiskSize"` TotalDiskSize int `json:"totalDiskSize"`
UpdatedBy string `json:"updatedBy"` UpdatedBy string `json:"updatedBy"`
UpdateTime uint64 `json:"updateTime"` UpdateTime uint64 `json:"updateTime"`
UserManaged bool `json:"userManaged"` UserManaged bool `json:"userManaged"`
Vgpus []int `json:"vgpus"` Vgpus []int `json:"vgpus"`
VinsConnected int `json:"vinsConnected"` VinsConnected int `json:"vinsConnected"`
VirtualImageID int `json:"virtualImageId"` VirtualImageID int `json:"virtualImageId"`
} }
const ComputeListAPI = "/restmachine/cloudapi/compute/list" const ComputeListAPI = "/restmachine/cloudapi/compute/list"
@ -302,7 +303,7 @@ type DiskRecord struct {
// ACLs `json:"ACL"` - it is a dictionary, special parsing required // ACLs `json:"ACL"` - it is a dictionary, special parsing required
// was - Acl map[string]string `json:"acl"` // was - Acl map[string]string `json:"acl"`
AccountID int `json:"accountId"` AccountID int `json:"accountId"`
AccountName string `json:"accountName"` // NOTE: absent from compute/get output AccountName string `json:"accountName"` // NOTE: absent from compute/get output
BootPartition int `json:"bootPartition"` BootPartition int `json:"bootPartition"`
CreatedTime uint64 `json:"creationTime"` CreatedTime uint64 `json:"creationTime"`
DeletedTime uint64 `json:"deletionTime"` DeletedTime uint64 `json:"deletionTime"`
@ -325,7 +326,7 @@ type DiskRecord struct {
PurgeTime uint64 `json:"purgeTime"` PurgeTime uint64 `json:"purgeTime"`
// Role string `json:"role"` // Role string `json:"role"`
SepType string `json:"sepType"` SepType string `json:"sepType"`
SepID int `json:"sepId"` // NOTE: absent from compute/get output SepID int `json:"sepId"` // NOTE: absent from compute/get output
SizeMax int `json:"sizeMax"` SizeMax int `json:"sizeMax"`
SizeUsed int `json:"sizeUsed"` // sum over all snapshots of this disk to report total consumed space SizeUsed int `json:"sizeUsed"` // sum over all snapshots of this disk to report total consumed space
Snapshots []SnapshotRecord `json:"snapshots"` Snapshots []SnapshotRecord `json:"snapshots"`
@ -376,14 +377,14 @@ type ComputeGetResp struct {
SnapSets []SnapSetRecord `json:"snapSets"` SnapSets []SnapSetRecord `json:"snapSets"`
Status string `json:"status"` Status string `json:"status"`
// Tags []string `json:"tags"` // Tags were reworked since DECORT 3.7.1 // Tags []string `json:"tags"` // Tags were reworked since DECORT 3.7.1
TechStatus string `json:"techStatus"` TechStatus string `json:"techStatus"`
TotalDiskSize int `json:"totalDiskSize"` TotalDiskSize int `json:"totalDiskSize"`
UpdatedBy string `json:"updatedBy"` UpdatedBy string `json:"updatedBy"`
UpdateTime uint64 `json:"updateTime"` UpdateTime uint64 `json:"updateTime"`
UserManaged bool `json:"userManaged"` UserManaged bool `json:"userManaged"`
Vgpus []int `json:"vgpus"` Vgpus []int `json:"vgpus"`
VinsConnected int `json:"vinsConnected"` VinsConnected int `json:"vinsConnected"`
VirtualImageID int `json:"virtualImageId"` VirtualImageID int `json:"virtualImageId"`
} }
// //
@ -468,11 +469,12 @@ const ComputePfwDelAPI = "/restmachine/cloudapi/compute/pfwDel"
// structures related to /cloudapi/compute/net Attach/Detach API // structures related to /cloudapi/compute/net Attach/Detach API
// //
type ComputeNetMgmtRecord struct { // used to "cache" network specs when preparing to manage compute networks type ComputeNetMgmtRecord struct { // used to "cache" network specs when preparing to manage compute networks
ID int ID int
Type string Type string
IPAddress string IPAddress string
MAC string MAC string
} }
const ComputeNetAttachAPI = "/restmachine/cloudapi/compute/netAttach" const ComputeNetAttachAPI = "/restmachine/cloudapi/compute/netAttach"
const ComputeNetDetachAPI = "/restmachine/cloudapi/compute/netDetach" const ComputeNetDetachAPI = "/restmachine/cloudapi/compute/netDetach"
@ -512,52 +514,52 @@ const DisksRenameAPI = "/restmachine/cloudapi/disks/rename"
// //
const DisksDeleteAPI = "/restmachine/cloudapi/disks/delete" const DisksDeleteAPI = "/restmachine/cloudapi/disks/delete"
// //
// ViNS structures // ViNS structures
// //
// this is the structure of the element in the list returned by vins/search API // this is the structure of the element in the list returned by vins/search API
type VinsSearchRecord struct { type VinsSearchRecord struct {
ID int `json:"id"` ID int `json:"id"`
Name string `json:"name"` Name string `json:"name"`
IPCidr string `json:"network"` IPCidr string `json:"network"`
VxLanID int `json:"vxlanId"` VxLanID int `json:"vxlanId"`
ExternalIP string `json:"externalIP"` ExternalIP string `json:"externalIP"`
AccountID int `json:"accountId"` AccountID int `json:"accountId"`
AccountName string `json:"accountName"` AccountName string `json:"accountName"`
RgID int `json:"rgId"` RgID int `json:"rgId"`
RgName string `json:"rgName"` RgName string `json:"rgName"`
} }
const VinsSearchAPI = "/restmachine/cloudapi/vins/search" const VinsSearchAPI = "/restmachine/cloudapi/vins/search"
type VinsSearchResp []VinsSearchRecord type VinsSearchResp []VinsSearchRecord
type VnfRecord struct { type VnfRecord struct {
ID int `json:"id"` ID int `json:"id"`
AccountID int `json:"accountId"` AccountID int `json:"accountId"`
Type string `json:"type"` // "DHCP", "NAT", "GW" etc Type string `json:"type"` // "DHCP", "NAT", "GW" etc
Config map[string]interface{} `json:"config"` // NOTE: VNF specs vary by VNF type Config map[string]interface{} `json:"config"` // NOTE: VNF specs vary by VNF type
} }
type VnfGwConfigRecord struct { // describes GW VNF config structure inside ViNS, as returned by API vins/get type VnfGwConfigRecord struct { // describes GW VNF config structure inside ViNS, as returned by API vins/get
ExtNetID int `json:"ext_net_id"` ExtNetID int `json:"ext_net_id"`
ExtNetIP string `json:"ext_net_ip"` ExtNetIP string `json:"ext_net_ip"`
ExtNetMask int `json:"ext_net_mask"` ExtNetMask int `json:"ext_net_mask"`
DefaultGW string `json:"default_gw"` DefaultGW string `json:"default_gw"`
} }
type VinsRecord struct { // represents part of the response from API vins/get type VinsRecord struct { // represents part of the response from API vins/get
ID int `json:"id"` ID int `json:"id"`
Name string `json:"name"` Name string `json:"name"`
IPCidr string `json:"network"` IPCidr string `json:"network"`
VxLanID int `json:"vxlanId"` VxLanID int `json:"vxlanId"`
ExternalIP string `json:"externalIP"` ExternalIP string `json:"externalIP"`
AccountID int `json:"accountId"` AccountID int `json:"accountId"`
AccountName string `json:"accountName"` AccountName string `json:"accountName"`
RgID int `json:"rgid"` RgID int `json:"rgid"`
RgName string `json:"rgName"` RgName string `json:"rgName"`
VNFs map[string]VnfRecord `json:"vnfs"` VNFs map[string]VnfRecord `json:"vnfs"`
Desc string `json:"desc"` Desc string `json:"desc"`
} }
const VinsGetAPI = "/restmachine/cloudapi/vins/get" const VinsGetAPI = "/restmachine/cloudapi/vins/get"
@ -572,13 +574,13 @@ const VinsDeleteAPI = "/restmachine/cloudapi/vins/delete"
// //
// Grid ID structures // Grid ID structures
// //
type LocationRecord struct { type LocationRecord struct {
GridID int `json:"gid"` GridID int `json:"gid"`
Id int `json:"id"` Id int `json:"id"`
LocationCode string `json:"locationCode"` LocationCode string `json:"locationCode"`
Name string `json:"name"` Name string `json:"name"`
Flag string `json:"flag"` Flag string `json:"flag"`
} }
const LocationsListAPI = "/restmachine/cloudapi/locations/list" // Returns list of GridRecord on success const LocationsListAPI = "/restmachine/cloudapi/locations/list" // Returns list of GridRecord on success

@ -50,15 +50,15 @@ func cloudInitDiffSupperss(key, oldVal, newVal string, d *schema.ResourceData) b
} }
func resourceComputeCreate(d *schema.ResourceData, m interface{}) error { func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
// we assume all mandatory 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 // 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)) log.Debugf("resourceComputeCreate: called for Compute name %q, RG ID %d", d.Get("name").(string), d.Get("rg_id").(int))
// create basic Compute (i.e. without extra disks and network connections - those will be attached // create basic Compute (i.e. without extra disks and network connections - those will be attached
// by subsequent individual API calls). // by subsequent individual API calls).
// creating Compute is a multi-step workflow, which may fail at some step, so we use "partial" feature of Terraform // creating Compute is a multi-step workflow, which may fail at some step, so we use "partial" feature of Terraform
d.Partial(true) d.Partial(true)
controller := m.(*ControllerCfg) controller := m.(*ControllerCfg)
urlValues := &url.Values{} urlValues := &url.Values{}
urlValues.Add("rgId", fmt.Sprintf("%d", d.Get("rg_id").(int))) urlValues.Add("rgId", fmt.Sprintf("%d", d.Get("rg_id").(int)))
@ -68,32 +68,32 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
urlValues.Add("imageId", fmt.Sprintf("%d", d.Get("image_id").(int))) urlValues.Add("imageId", fmt.Sprintf("%d", d.Get("image_id").(int)))
urlValues.Add("bootDisk", fmt.Sprintf("%d", d.Get("boot_disk_size").(int))) urlValues.Add("bootDisk", fmt.Sprintf("%d", d.Get("boot_disk_size").(int)))
urlValues.Add("netType", "NONE") // at the 1st step create isolated compute urlValues.Add("netType", "NONE") // at the 1st step create isolated compute
urlValues.Add("start", "0") // at the 1st step create compute in a stopped state urlValues.Add("start", "0") // at the 1st step create compute in a stopped state
argVal, argSet := d.GetOk("description") argVal, argSet := d.GetOk("description")
if argSet { if argSet {
urlValues.Add("desc", argVal.(string)) urlValues.Add("desc", argVal.(string))
} }
/* /*
sshKeysVal, sshKeysSet := d.GetOk("ssh_keys") sshKeysVal, sshKeysSet := d.GetOk("ssh_keys")
if sshKeysSet { if sshKeysSet {
// process SSH Key settings and set API values accordingly // process SSH Key settings and set API values accordingly
log.Debugf("resourceComputeCreate: calling makeSshKeysArgString to setup SSH keys for guest login(s)") log.Debugf("resourceComputeCreate: calling makeSshKeysArgString to setup SSH keys for guest login(s)")
urlValues.Add("userdata", makeSshKeysArgString(sshKeysVal.([]interface{}))) urlValues.Add("userdata", makeSshKeysArgString(sshKeysVal.([]interface{})))
} }
*/ */
computeCreateAPI := KvmX86CreateAPI computeCreateAPI := KvmX86CreateAPI
arch := d.Get("arch").(string) driver := d.Get("driver").(string)
if arch == "KVM_PPC" { if driver == "KVM_PPC" {
computeCreateAPI = KvmPPCCreateAPI computeCreateAPI = KvmPPCCreateAPI
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM PowerPC") log.Debugf("resourceComputeCreate: creating Compute of type KVM VM PowerPC")
} else { // note that we do not validate arch value for explicit "KVM_X86" here } else { // note that we do not validate arch value for explicit "KVM_X86" here
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86") log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86")
} }
argVal, argSet = d.GetOk("cloud_init") argVal, argSet = d.GetOk("cloud_init")
if argSet { if argSet {
// userdata must not be empty string and must not be a reserved keyword "applied" // userdata must not be empty string and must not be a reserved keyword "applied"
userdata := argVal.(string) userdata := argVal.(string)
@ -101,7 +101,7 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
urlValues.Add("userdata", userdata) urlValues.Add("userdata", userdata)
} }
} }
apiResp, err := controller.decortAPICall("POST", computeCreateAPI, urlValues) apiResp, err := controller.decortAPICall("POST", computeCreateAPI, urlValues)
if err != nil { if err != nil {
return err return err
@ -117,16 +117,16 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
d.SetPartial("image_id") d.SetPartial("image_id")
d.SetPartial("boot_disk_size") d.SetPartial("boot_disk_size")
/* /*
if sshKeysSet { if sshKeysSet {
d.SetPartial("ssh_keys") d.SetPartial("ssh_keys")
} }
*/ */
log.Debugf("resourceComputeCreate: new simple Compute ID %d, name %s created", compId, d.Get("name").(string)) log.Debugf("resourceComputeCreate: new simple Compute ID %d, name %s created", compId, d.Get("name").(string))
// Configure data disks if any // Configure data disks if any
extraDisksOk := true extraDisksOk := true
argVal, argSet = d.GetOk("extra_disks") argVal, argSet = d.GetOk("extra_disks")
if argSet && argVal.(*schema.Set).Len() > 0 { if argSet && argVal.(*schema.Set).Len() > 0 {
// urlValues.Add("desc", argVal.(string)) // urlValues.Add("desc", argVal.(string))
log.Debugf("resourceComputeCreate: calling utilityComputeExtraDisksConfigure to attach %d extra disk(s)", argVal.(*schema.Set).Len()) log.Debugf("resourceComputeCreate: calling utilityComputeExtraDisksConfigure to attach %d extra disk(s)", argVal.(*schema.Set).Len())
@ -142,8 +142,8 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
// Configure external networks if any // Configure external networks if any
netsOk := true netsOk := true
argVal, argSet = d.GetOk("network") argVal, argSet = d.GetOk("network")
if argSet && argVal.(*schema.Set).Len() > 0 { if argSet && argVal.(*schema.Set).Len() > 0 {
log.Debugf("resourceComputeCreate: calling utilityComputeNetworksConfigure to attach %d network(s)", argVal.(*schema.Set).Len()) log.Debugf("resourceComputeCreate: calling utilityComputeNetworksConfigure to attach %d network(s)", argVal.(*schema.Set).Len())
err = controller.utilityComputeNetworksConfigure(d, false) // do_delta=false, as we are working on a new compute err = controller.utilityComputeNetworksConfigure(d, false) // do_delta=false, as we are working on a new compute
if err != nil { if err != nil {
@ -161,23 +161,25 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
d.Partial(false) d.Partial(false)
} }
// Note bene: we created compute in a STOPPED state (this is required to properly attach 1st network interface), // Note bene: we created compute in a STOPPED state (this is required to properly attach 1st network interface),
// now we need to start it before we report the sequence complete // now we need to start it before we report the sequence complete
reqValues := &url.Values{} if d.Get("started").(bool) {
reqValues.Add("computeId", fmt.Sprintf("%d", compId)) reqValues := &url.Values{}
log.Debugf("resourceComputeCreate: starting Compute ID %d after completing its resource configuration", compId) reqValues.Add("computeId", fmt.Sprintf("%d", compId))
apiResp, err = controller.decortAPICall("POST", ComputeStartAPI, reqValues) log.Debugf("resourceComputeCreate: starting Compute ID %d after completing its resource configuration", compId)
if err != nil { apiResp, err = controller.decortAPICall("POST", ComputeStartAPI, reqValues)
return err if err != nil {
return err
}
} }
log.Debugf("resourceComputeCreate: new Compute ID %d, name %s creation sequence complete", compId, d.Get("name").(string)) log.Debugf("resourceComputeCreate: new Compute ID %d, name %s creation sequence complete", compId, d.Get("name").(string))
// We may reuse dataSourceComputeRead here as we maintain similarity // We may reuse dataSourceComputeRead here as we maintain similarity
// between Compute resource and Compute data source schemas // between Compute resource and Compute data source schemas
// Compute read function will also update resource ID on success, so that Terraform // Compute read function will also update resource ID on success, so that Terraform
// will know the resource exists // will know the resource exists
return dataSourceComputeRead(d, m) return dataSourceComputeRead(d, m)
} }
func resourceComputeRead(d *schema.ResourceData, m interface{}) error { func resourceComputeRead(d *schema.ResourceData, m interface{}) error {
@ -209,11 +211,12 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
controller := m.(*ControllerCfg) controller := m.(*ControllerCfg)
/* /*
1. Resize CPU/RAM 1. Resize CPU/RAM
2. Resize (grow) boot disk 2. Resize (grow) boot disk
3. Update extra disks 3. Update extra disks
4. Update networks 4. Update networks
5. Start/stop
*/ */
// 1. Resize CPU/RAM // 1. Resize CPU/RAM
@ -230,7 +233,7 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
} else { } else {
params.Add("cpu", "0") // no change to CPU allocation params.Add("cpu", "0") // no change to CPU allocation
} }
oldRam, newRam := d.GetChange("ram") oldRam, newRam := d.GetChange("ram")
if oldRam.(int) != newRam.(int) { if oldRam.(int) != newRam.(int) {
params.Add("ram", fmt.Sprintf("%d", newRam.(int))) params.Add("ram", fmt.Sprintf("%d", newRam.(int)))
@ -241,8 +244,8 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
if doUpdate { if doUpdate {
log.Debugf("resourceComputeUpdate: changing CPU %d -> %d and/or RAM %d -> %d", log.Debugf("resourceComputeUpdate: changing CPU %d -> %d and/or RAM %d -> %d",
oldCpu.(int), newCpu.(int), oldCpu.(int), newCpu.(int),
oldRam.(int), newRam.(int)) oldRam.(int), newRam.(int))
_, err := controller.decortAPICall("POST", ComputeResizeAPI, params) _, err := controller.decortAPICall("POST", ComputeResizeAPI, params)
if err != nil { if err != nil {
return err return err
@ -251,14 +254,14 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
d.SetPartial("ram") d.SetPartial("ram")
} }
// 2. Resize (grow) Boot disk // 2. Resize (grow) Boot disk
oldSize, newSize := d.GetChange("boot_disk_size") oldSize, newSize := d.GetChange("boot_disk_size")
if oldSize.(int) < newSize.(int) { if oldSize.(int) < newSize.(int) {
bdsParams := &url.Values{} bdsParams := &url.Values{}
bdsParams.Add("diskId", fmt.Sprintf("%d", d.Get("boot_disk_id").(int))) bdsParams.Add("diskId", fmt.Sprintf("%d", d.Get("boot_disk_id").(int)))
bdsParams.Add("size", fmt.Sprintf("%d", newSize.(int))) bdsParams.Add("size", fmt.Sprintf("%d", newSize.(int)))
log.Debugf("resourceComputeUpdate: compute ID %s, boot disk ID %d resize %d -> %d", log.Debugf("resourceComputeUpdate: compute ID %s, boot disk ID %d resize %d -> %d",
d.Id(), d.Get("boot_disk_id").(int), oldSize.(int), newSize.(int)) d.Id(), d.Get("boot_disk_id").(int), oldSize.(int), newSize.(int))
_, err := controller.decortAPICall("POST", DisksResizeAPI, params) _, err := controller.decortAPICall("POST", DisksResizeAPI, params)
if err != nil { if err != nil {
return err return err
@ -284,17 +287,32 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
d.SetPartial("network") d.SetPartial("network")
} }
if d.HasChange("started") {
params := &url.Values{}
params.Add("computeId", d.Id())
if d.Get("started").(bool) {
if _, err := controller.decortAPICall("POST", ComputeStartAPI, params); err != nil {
return err
}
} else {
if _, err := controller.decortAPICall("POST", ComputeStopAPI, params); err != nil {
return err
}
}
d.SetPartial("started")
}
d.Partial(false) d.Partial(false)
// we may reuse dataSourceComputeRead here as we maintain similarity // we may reuse dataSourceComputeRead here as we maintain similarity
// between Compute resource and Compute data source schemas // between Compute resource and Compute data source schemas
return dataSourceComputeRead(d, m) return dataSourceComputeRead(d, m)
} }
func resourceComputeDelete(d *schema.ResourceData, m interface{}) error { func resourceComputeDelete(d *schema.ResourceData, m interface{}) error {
// NOTE: this function destroys target Compute instance "permanently", so // NOTE: this function destroys target Compute instance "permanently", so
// there is no way to restore it. // there is no way to restore it.
// If compute being destroyed has some extra disks attached, they are // If compute being destroyed has some extra disks attached, they are
// detached from the compute // detached from the compute
log.Debugf("resourceComputeDelete: called for Compute name %s, RG ID %d", log.Debugf("resourceComputeDelete: called for Compute name %s, RG ID %d",
d.Get("name").(string), d.Get("rg_id").(int)) d.Get("name").(string), d.Get("rg_id").(int))
@ -312,7 +330,7 @@ func resourceComputeDelete(d *schema.ResourceData, m interface{}) error {
log.Debugf("resourceComputeDelete: ready to unmarshal string %s", compFacts) log.Debugf("resourceComputeDelete: ready to unmarshal string %s", compFacts)
err = json.Unmarshal([]byte(compFacts), &model) err = json.Unmarshal([]byte(compFacts), &model)
if err == nil && len(model.Disks) > 0 { if err == nil && len(model.Disks) > 0 {
// prepare to detach data disks from compute - do it only if compFacts unmarshalled // prepare to detach data disks from compute - do it only if compFacts unmarshalled
// properly and the resulting model contains non-empty Disks list // properly and the resulting model contains non-empty Disks list
for _, diskFacts := range model.Disks { for _, diskFacts := range model.Disks {
if diskFacts.Type == "B" { if diskFacts.Type == "B" {
@ -338,7 +356,7 @@ func resourceComputeDelete(d *schema.ResourceData, m interface{}) error {
params.Add("computeId", d.Id()) params.Add("computeId", d.Id())
params.Add("permanently", "1") params.Add("permanently", "1")
// TODO: this is for the upcoming API update - params.Add("detachdisks", "1") // TODO: this is for the upcoming API update - params.Add("detachdisks", "1")
_, err = controller.decortAPICall("POST", ComputeDeleteAPI, params) _, err = controller.decortAPICall("POST", ComputeDeleteAPI, params)
if err != nil { if err != nil {
return err return err
@ -398,13 +416,13 @@ func resourceCompute() *schema.Resource {
Description: "ID of the resource group where this compute should be deployed.", Description: "ID of the resource group where this compute should be deployed.",
}, },
"arch": { "driver": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
StateFunc: stateFuncToUpper, StateFunc: stateFuncToUpper,
ValidateFunc: validation.StringInSlice([]string{"KVM_X86", "KVM_PPC"}, false), // observe case while validating ValidateFunc: validation.StringInSlice([]string{"KVM_X86", "KVM_PPC"}, false), // observe case while validating
Description: "Hardware architecture of this compute instance.", Description: "Hardware architecture of this compute instance.",
}, },
"cpu": { "cpu": {
@ -422,16 +440,16 @@ func resourceCompute() *schema.Resource {
}, },
"image_id": { "image_id": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
ValidateFunc: validation.IntAtLeast(1), ValidateFunc: validation.IntAtLeast(1),
Description: "ID of the OS image to base this compute instance on.", Description: "ID of the OS image to base this compute instance on.",
}, },
"boot_disk_size": { "boot_disk_size": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
Description: "This compute instance boot disk size in GB. Make sure it is large enough to accomodate selected OS image.", Description: "This compute instance boot disk size in GB. Make sure it is large enough to accomodate selected OS image.",
}, },
@ -456,15 +474,15 @@ func resourceCompute() *schema.Resource {
}, },
/* /*
"ssh_keys": { "ssh_keys": {
Type: schema.TypeList, Type: schema.TypeList,
Optional: true, Optional: true,
MaxItems: MaxSshKeysPerCompute, MaxItems: MaxSshKeysPerCompute,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: sshSubresourceSchemaMake(), Schema: sshSubresourceSchemaMake(),
},
Description: "SSH keys to authorize on this compute instance.",
}, },
Description: "SSH keys to authorize on this compute instance.",
},
*/ */
"description": { "description": {
@ -473,13 +491,12 @@ func resourceCompute() *schema.Resource {
Description: "Optional text description of this compute instance.", Description: "Optional text description of this compute instance.",
}, },
"cloud_init": { "cloud_init": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Default: "applied", Default: "applied",
DiffSuppressFunc: cloudInitDiffSupperss, DiffSuppressFunc: cloudInitDiffSupperss,
Description: "Optional cloud_init parameters. Applied when creating new compute instance only, ignored in all other cases.", Description: "Optional cloud_init parameters. Applied when creating new compute instance only, ignored in all other cases.",
}, },
// The rest are Compute properties, which are "computed" once it is created // The rest are Compute properties, which are "computed" once it is created
@ -516,37 +533,44 @@ func resourceCompute() *schema.Resource {
Description: "Guest OS users provisioned on this compute instance.", Description: "Guest OS users provisioned on this compute instance.",
}, },
"started": {
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "Is compute started.",
},
/* /*
"disks": { "disks": {
Type: schema.TypeList, Type: schema.TypeList,
Computed: true, Computed: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: dataSourceDiskSchemaMake(), // ID, type, name, size, account ID, SEP ID, SEP type, pool, status, tech status, compute ID, image ID Schema: dataSourceDiskSchemaMake(), // ID, type, name, size, account ID, SEP ID, SEP type, pool, status, tech status, compute ID, image ID
},
Description: "Detailed specification for all disks attached to this compute instance (including bood disk).",
}, },
Description: "Detailed specification for all disks attached to this compute instance (including bood disk).",
},
"interfaces": { "interfaces": {
Type: schema.TypeList, Type: schema.TypeList,
Computed: true, Computed: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: interfaceSubresourceSchemaMake(), Schema: interfaceSubresourceSchemaMake(),
},
Description: "Specification for the virtual NICs configured on this compute instance.",
}, },
Description: "Specification for the virtual NICs configured on this compute instance.",
},
"status": { "status": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
Description: "Current model status of this compute instance.", Description: "Current model status of this compute instance.",
}, },
"tech_status": { "tech_status": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
Description: "Current technical status of this compute instance.", Description: "Current technical status of this compute instance.",
}, },
*/ */
}, },
} }

Loading…
Cancel
Save