Implement update logic for compute resource

rc-1.0
Sergey Shubin svs1370 4 years ago
parent 509fc0f69d
commit 5500dad554

@ -35,3 +35,9 @@ const MaxExtraDisksPerCompute=12
// MaxNetworksPerCompute sets maximum number of vNICs per compute // MaxNetworksPerCompute sets maximum number of vNICs per compute
const MaxNetworksPerCompute=8 const MaxNetworksPerCompute=8
// MaxCpusPerCompute sets maximum number of vCPUs per compute
const MaxCpusPerCompute=128
// MinRamPerCompute sets minimum amount of RAM per compute in MB
const MinRamPerCompute=128

@ -136,6 +136,21 @@ func parseBootDiskSize(disks []DiskRecord) int {
return 0 return 0
} }
func parseBootDiskId(disks []DiskRecord) uint {
// this return value will be used to d.Set("boot_disk_id",) item of dataSourceCompute schema
if len(disks) == 0 {
return 0
}
for _, value := range disks {
if value.Type == "B" {
return value.ID
}
}
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{} {
@ -157,6 +172,7 @@ func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []interface{} {
elem["net_id"] = value.NetID elem["net_id"] = value.NetID
elem["net_type"] = value.NetType elem["net_type"] = value.NetType
elem["ip_address"] = value.IPAddress elem["ip_address"] = value.IPAddress
elem["mac"] = value.MAC
result[i] = elem result[i] = elem
} }
@ -233,6 +249,7 @@ func flattenCompute(d *schema.ResourceData, compFacts string) error {
d.Set("ram", model.Ram) d.Set("ram", model.Ram)
// d.Set("boot_disk_size", model.BootDiskSize) - bootdiskSize key in API compute/get is always zero, so we set boot_disk_size in another way // d.Set("boot_disk_size", model.BootDiskSize) - bootdiskSize key in API compute/get is always zero, so we set boot_disk_size in another way
d.Set("boot_disk_size", parseBootDiskSize(model.Disks)) d.Set("boot_disk_size", parseBootDiskSize(model.Disks))
d.Set("boot_disk_id", parseBootDiskId(model.Disks)) // we may need boot disk ID in resize operations
d.Set("image_id", model.ImageID) d.Set("image_id", model.ImageID)
d.Set("description", model.Desc) d.Set("description", model.Desc)
d.Set("status", model.Status) d.Set("status", model.Status)
@ -360,6 +377,12 @@ func dataSourceCompute() *schema.Resource {
Description: "This compute instance boot disk size in GB.", Description: "This compute instance boot disk size in GB.",
}, },
"boot_disk_id": {
Type: schema.TypeInt,
Computed: true,
Description: "This compute instance boot disk ID.",
},
"extra_disks": { "extra_disks": {
Type: schema.TypeList, Type: schema.TypeList,
Computed: true, Computed: true,

@ -282,6 +282,8 @@ const ComputeListAPI = "/restmachine/cloudapi/compute/list"
type ComputeListResp []ComputeRecord type ComputeListResp []ComputeRecord
const ComputeResizeAPI = "/restmachine/cloudapi/compute/resize"
// //
// structures related to /cloudapi/compute/get // structures related to /cloudapi/compute/get
// //
@ -462,6 +464,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
ID int
Type string
IPAddress 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"

@ -51,6 +51,12 @@ func networkSubresourceSchemaMake() map[string]*schema.Schema {
Description: "Optional IP address to assign to this connection. This IP should belong to the selected network and free for use.", Description: "Optional IP address to assign to this connection. This IP should belong to the selected network and free for use.",
}, },
"mac": {
Type: schema.TypeString,
Computed: true,
Description: "MAC address associated with this connection. MAC address is assigned automatically.",
},
} }
return rets return rets
} }

@ -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, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com> Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
@ -168,10 +168,77 @@ func resourceComputeRead(d *schema.ResourceData, m interface{}) error {
} }
func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error { func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
log.Debugf("resourceComputeUpdate: called for Compute name %s, RGID %d", log.Debugf("resourceComputeUpdate: called for Compute ID %s / name %s, RGID %d",
d.Get("name").(string), d.Get("rg_id").(int)) d.Id(), d.Get("name").(string), d.Get("rg_id").(int))
controller := m.(*ControllerCfg)
/*
1. Resize CPU/RAM
2. Resize (grow) boot disk
3. Update extra disks
4. Update networks
5. Update port forwards
*/
// 1. Resize CPU/RAM
params := &url.Values{}
doUpdate := false
params.Add("computeId", d.Id())
oldCpu, newCpu := d.GetChange("cpu")
if oldCpu.(int) != newCpu.(int) {
params.Add("cpu", fmt.Sprintf("%d", newCpu.(int)))
doUpdate = true
} else {
params.Add("cpu", "0") // no change to CPU allocation
}
oldRam, newRam := d.GetChange("ram")
if oldRam.(int) != newRam.(int) {
params.Add("ram", fmt.Sprintf("%d", newRam.(int)))
doUpdate = true
} else {
params.Add("ram", "0")
}
log.Printf("resourceComputeUpdate: NOT IMPLEMENTED YET!") if doUpdate {
log.Debugf("resourceComputeUpdate: changing CPU %d -> %d and/or RAM %d -> %d",
oldCpu.(int), newCpu.(int),
oldRam.(int), newRam.(int))
_, err := controller.decortAPICall("POST", ComputeResizeAPI, params)
if err != nil {
return err
}
}
// 2. Resize (grow) Boot disk
oldSize, newSize := d.GetChange("boot_disk_size")
if oldSize.(int) < newSize.(int) {
bdsParams := &url.Values{}
bdsParams.Add("diskId", fmt.Sprintf("%d", d.Get("boot_disk_id").(int)))
bdsParams.Add("size", fmt.Sprintf("%d", newSize.(int)))
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))
_, err := controller.decortAPICall("POST", DisksResizeAPI, params)
if err != nil {
return err
}
} else if oldSize.(int) > newSize.(int) {
log.Warnf("resourceComputeUpdate: compute ID %d - shrinking boot disk is not allowed", d.Id())
}
// 3. Calculate and apply changes to data disks
err := controller.utilityComputeExtraDisksConfigure(d, true) // pass do_delta = true to apply changes, if any
if err != nil {
return err
}
// 4. Calculate and apply changes to network connections
err = controller.utilityComputeNetworksConfigure(d, true) // pass do_delta = true to apply changes, if any
if err != nil {
return err
}
// 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
@ -267,14 +334,14 @@ func resourceCompute() *schema.Resource {
"cpu": { "cpu": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ValidateFunc: validation.IntBetween(1, 64), ValidateFunc: validation.IntBetween(1, MaxCpusPerCompute),
Description: "Number of CPUs to allocate to this compute instance.", Description: "Number of CPUs to allocate to this compute instance.",
}, },
"ram": { "ram": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ValidateFunc: validation.IntAtLeast(512), ValidateFunc: validation.IntAtLeast(MinRamPerCompute),
Description: "Amount of RAM in MB to allocate to this compute instance.", Description: "Amount of RAM in MB to allocate to this compute instance.",
}, },
@ -346,6 +413,12 @@ func resourceCompute() *schema.Resource {
Description: "Name of the account this compute instance belongs to.", Description: "Name of the account this compute instance belongs to.",
}, },
"boot_disk_id": {
Type: schema.TypeInt,
Computed: true,
Description: "This compute instance boot disk ID.",
},
/* /*
"disks": { "disks": {
Type: schema.TypeList, Type: schema.TypeList,

@ -149,7 +149,7 @@ func (ctrl *ControllerCfg) utilityComputeExtraDisksConfigure(d *schema.ResourceD
} }
if apiErrCount > 0 { if apiErrCount > 0 {
log.Errorf("utilityComputeExtraDisksConfigure: there were %d error(s) when managing disks on Compute ID %s. Last error was: %s", log.Errorf("utilityComputeExtraDisksConfigure: there were %d error(s) when managing disks of Compute ID %s. Last error was: %s",
apiErrCount, d.Id(), lastSavedError) apiErrCount, d.Id(), lastSavedError)
return lastSavedError return lastSavedError
} }
@ -162,14 +162,32 @@ func (ctrl *ControllerCfg) utilityComputeNetworksConfigure(d *schema.ResourceDat
// "d" is filled with data according to computeResource schema, so extra networks config is retrieved via "network" key // "d" is filled with data according to computeResource schema, so extra networks config is retrieved via "network" key
// If do_delta is true, this function will identify changes between new and existing specs for network and try to // If do_delta is true, this function will identify changes between new and existing specs for network and try to
// update compute configuration accordingly // update compute configuration accordingly
/*
argVal, argSet := d.GetOk("network") argVal, argSet := d.GetOk("network")
if !argSet || len(argVal.([]interface{})) < 1 { if !argSet || len(argVal.([]interface{})) < 1 {
return nil return nil
} }
net_list := argVal.([]interface{}) // network is ar array of maps; for keys see func networkSubresourceSchemaMake() definition net_list := argVal.([]interface{}) // network is ar array of maps; for keys see func networkSubresourceSchemaMake() definition
*/
old_set, new_set := d.GetChange("network")
oldNets := make([]interface{},0,0)
if old_set != nil {
oldNets = old_set.([]interface{}) // network is ar array of maps; for keys see func networkSubresourceSchemaMake() definition
}
newNets := make([]interface{},0,0)
if new_set != nil {
newNets = new_set.([]interface{}) // network is ar array of maps; for keys see func networkSubresourceSchemaMake() definition
}
for _, net := range net_list { apiErrCount := 0
var lastSavedError error
if !do_delta {
for _, net := range newNets {
urlValues := &url.Values{} urlValues := &url.Values{}
net_data := net.(map[string]interface{}) net_data := net.(map[string]interface{})
urlValues.Add("computeId", d.Id()) urlValues.Add("computeId", d.Id())
@ -182,9 +200,107 @@ func (ctrl *ControllerCfg) utilityComputeNetworksConfigure(d *schema.ResourceDat
_, err := ctrl.decortAPICall("POST", ComputeNetAttachAPI, urlValues) _, err := ctrl.decortAPICall("POST", ComputeNetAttachAPI, urlValues)
if err != nil { if err != nil {
// failed to attach network - partial resource update // failed to attach network - partial resource update
return err apiErrCount++
lastSavedError = err
}
}
if apiErrCount > 0 {
log.Errorf("utilityComputeNetworksConfigure: there were %d error(s) when managing networks of Compute ID %s. Last error was: %s",
apiErrCount, d.Id(), lastSavedError)
return lastSavedError
}
return nil
}
attachList := make([]ComputeNetMgmtRecord, 0, MaxNetworksPerCompute)
detachList := make([]ComputeNetMgmtRecord, 0, MaxNetworksPerCompute)
attIdx := 0
detIdx := 0
match := false
for _, oRunner := range oldNets {
match = false
oSpecs := oRunner.(map[string]interface{})
for _, nRunner := range newNets {
nSpecs := nRunner.(map[string]interface{})
if oSpecs["net_id"].(int) == nSpecs["net_id"].(int) && oSpecs["net_type"].(string) == nSpecs["net_type"].(string) {
match = true
break
}
}
if !match {
detachList[attIdx].ID = oSpecs["net_id"].(int)
detachList[detIdx].Type = oSpecs["net_type"].(string)
detachList[detIdx].IPAddress = oSpecs["ip_address"].(string)
detachList[detIdx].MAC = oSpecs["mac"].(string)
detIdx++
} }
} }
log.Debugf("utilityComputeNetworksConfigure: detach list has %d items for Compute ID %s", len(detachList), d.Id())
for _, nRunner := range newNets {
match = false
nSpecs := nRunner.(map[string]interface{})
for _, oRunner := range oldNets {
oSpecs := oRunner.(map[string]interface{})
if nSpecs["net_id"].(int) == oSpecs["net_id"].(int) && nSpecs["net_type"].(string) == oSpecs["net_type"].(string) {
match = true
break
}
}
if !match {
attachList[attIdx].ID = nSpecs["net_id"].(int)
attachList[detIdx].Type = nSpecs["net_type"].(string)
if nSpecs["ip_address"] != nil {
attachList[detIdx].IPAddress = nSpecs["ip_address"].(string)
} else {
attachList[detIdx].IPAddress = "" // make sure it is empty, if not coming from the schema
}
attIdx++
}
}
log.Debugf("utilityComputeNetworksConfigure: attach list has %d items for Compute ID %s", len(attachList), d.Id())
for _, netRec := range detachList {
urlValues := &url.Values{}
urlValues.Add("computeId", d.Id())
urlValues.Add("ipAddr", netRec.IPAddress)
urlValues.Add("mac", netRec.MAC)
_, err := ctrl.decortAPICall("POST", ComputeNetDetachAPI, urlValues)
if err != nil {
// failed to detach this network - there will be partial resource update
log.Debugf("utilityComputeNetworksConfigure: failed to detach net ID %d of type %s from Compute ID %s: %s",
netRec.ID, netRec.Type, d.Id(), err)
apiErrCount++
lastSavedError = err
}
}
for _, netRec := range attachList {
urlValues := &url.Values{}
urlValues.Add("computeId", d.Id())
urlValues.Add("netId", fmt.Sprintf("%d",netRec.ID))
urlValues.Add("netType", netRec.Type)
if netRec.IPAddress != "" {
urlValues.Add("ipAddr", netRec.IPAddress)
}
_, err := ctrl.decortAPICall("POST", ComputeNetAttachAPI, urlValues)
if err != nil {
// failed to attach this network - there will be partial resource update
log.Debugf("utilityComputeNetworksConfigure: failed to attach net ID %d of type %s from Compute ID %s: %s",
netRec.ID, netRec.Type, d.Id(), err)
apiErrCount++
lastSavedError = err
}
}
if apiErrCount > 0 {
log.Errorf("utilityComputeNetworksConfigure: there were %d error(s) when managing networks of Compute ID %s. Last error was: %s",
apiErrCount, d.Id(), lastSavedError)
return lastSavedError
}
return nil return nil
} }

Loading…
Cancel
Save