4.5.0-alpha

This commit is contained in:
Nikita Sorokin
2023-11-07 18:26:09 +03:00
parent 2453a32d01
commit 2bc0fbae9a
198 changed files with 18877 additions and 4003 deletions

View File

@@ -76,17 +76,6 @@ func parseComputeDisksToExtraDisks(disks compute.ListDisks) []interface{} {
return result
}
func findBootDisk(disks compute.ListDisks) *compute.ItemDisk {
for _, d := range disks {
if d.Type == "B" {
return &d
}
}
// some computes don't have a boot disk, so...
return &compute.ItemDisk{}
}
// Parse the list of interfaces from compute/get response into a list of networks
// attached to this compute
func parseComputeInterfacesToNetworks(ifaces compute.ListInterfaces) []interface{} {
@@ -113,7 +102,7 @@ func parseComputeInterfacesToNetworks(ifaces compute.ListInterfaces) []interface
return result
}
func flattenCompute(d *schema.ResourceData, compFacts *compute.RecordCompute) error {
func flattenDataCompute(d *schema.ResourceData, compFacts *compute.RecordCompute) error {
// This function expects that compFacts string contains response from API compute/get,
// i.e. detailed information about compute instance.
//
@@ -179,7 +168,7 @@ func dataSourceComputeRead(ctx context.Context, d *schema.ResourceData, m interf
return diag.FromErr(err)
}
if err = flattenCompute(d, compFacts); err != nil {
if err = flattenDataCompute(d, compFacts); err != nil {
return diag.FromErr(err)
}
@@ -297,15 +286,15 @@ func DataSourceCompute() *schema.Resource {
},
*/
"network": {
Type: schema.TypeSet,
Optional: true,
MaxItems: constants.MaxNetworksPerCompute,
Elem: &schema.Resource{
Schema: networkSubresourceSchemaMake(),
},
Description: "Network connection(s) for this compute.",
},
// "network": {
// Type: schema.TypeSet,
// Optional: true,
// MaxItems: constants.MaxNetworksPerCompute,
// Elem: &schema.Resource{
// Schema: networkSubresourceSchemaMake(),
// },
// Description: "Network connection(s) for this compute.",
// },
"os_users": {
Type: schema.TypeList,

View File

@@ -0,0 +1,219 @@
package kvmvm
import (
"encoding/json"
"sort"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/compute"
)
func flattenCompute(d *schema.ResourceData, computeRec *compute.RecordCompute) error {
log.Debugf("flattenCompute: ID %d, RG ID %d", computeRec.ID, computeRec.RGID)
customFields, _ := json.Marshal(computeRec.CustomFields)
devices, _ := json.Marshal(computeRec.Devices)
bootDisk := findBootDisk(computeRec.Disks)
d.Set("account_id", computeRec.AccountID)
d.Set("account_name", computeRec.AccountName)
d.Set("affinity_label", computeRec.AffinityLabel)
d.Set("affinity_weight", computeRec.AffinityWeight)
d.Set("affinity_rules", flattenAffinityRules(computeRec.AffinityRules))
d.Set("anti_affinity_rules", flattenAffinityRules(computeRec.AntiAffinityRules))
d.Set("arch", computeRec.Arch)
d.Set("boot_order", computeRec.BootOrder)
d.Set("boot_disk_size", computeRec.BootDiskSize)
d.Set("clone_reference", computeRec.CloneReference)
d.Set("clones", computeRec.Clones)
d.Set("computeci_id", computeRec.ComputeCIID)
d.Set("created_by", computeRec.CreatedBy)
d.Set("created_time", computeRec.CreatedTime)
d.Set("custom_fields", string(customFields))
d.Set("deleted_by", computeRec.DeletedBy)
d.Set("deleted_time", computeRec.DeletedTime)
d.Set("description", computeRec.Description)
d.Set("devices", string(devices))
d.Set("disks",
flattenComputeDisks(
computeRec.Disks,
d.Get("extra_disks").(*schema.Set).List(),
bootDisk.ID,
),
)
d.Set("gid", computeRec.GID)
d.Set("guid", computeRec.GUID)
d.Set("compute_id", computeRec.ID)
d.Set("image_id", computeRec.ImageID)
d.Set("interfaces", flattenInterfaces(computeRec.Interfaces))
d.Set("lock_status", computeRec.LockStatus)
d.Set("manager_id", computeRec.ManagerID)
d.Set("manager_type", computeRec.ManagerType)
d.Set("migrationjob", computeRec.MigrationJob)
d.Set("milestones", computeRec.Milestones)
d.Set("os_users", flattenOSUsers(computeRec.OSUsers))
d.Set("pinned", computeRec.Pinned)
d.Set("reference_id", computeRec.ReferenceID)
d.Set("registered", computeRec.Registered)
d.Set("res_name", computeRec.ResName)
d.Set("rg_name", computeRec.RGName)
d.Set("snap_sets", flattenSnapSets(computeRec.SnapSets))
d.Set("stack_id", computeRec.StackID)
d.Set("stack_name", computeRec.StackName)
d.Set("stateless_sep_id", computeRec.StatelessSEPID)
d.Set("stateless_sep_type", computeRec.StatelessSEPType)
d.Set("status", computeRec.Status)
d.Set("tags", flattenTags(computeRec.Tags))
d.Set("tech_status", computeRec.TechStatus)
d.Set("updated_by", computeRec.UpdatedBy)
d.Set("updated_time", computeRec.UpdatedTime)
d.Set("user_managed", computeRec.UserManaged)
d.Set("vgpus", computeRec.VGPUs)
d.Set("virtual_image_id", computeRec.VirtualImageID)
return nil
}
func flattenTags(tags map[string]interface{}) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(tags))
for k, v := range tags {
res = append(res, map[string]interface{}{
"key": k,
"val": v,
})
}
return res
}
func flattenSnapSets(snaps compute.ListSnapshots) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(snaps))
for _, snap := range snaps {
res = append(res, map[string]interface{}{
"disks": snap.Disks,
"guid": snap.GUID,
"label": snap.Label,
"timestamp": snap.Timestamp,
})
}
return res
}
func flattenOSUsers(users compute.ListOSUsers) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(users))
for _, user := range users {
res = append(res, map[string]interface{}{
"guid": user.GUID,
"login": user.Login,
"password": user.Password,
"public_key": user.PubKey,
})
}
return res
}
func flattenInterfaces(ifaces compute.ListInterfaces) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(ifaces))
for _, iface := range ifaces {
res = append(res, map[string]interface{}{
"conn_id": iface.ConnID,
"conn_type": iface.ConnType,
"def_gw": iface.DefGW,
"flip_group_id": iface.FLIPGroupID,
"guid": iface.GUID,
"ip_address": iface.IPAddress,
"listen_ssh": iface.ListenSSH,
"mac": iface.MAC,
"name": iface.Name,
"net_id": iface.NetID,
"netmask": iface.NetMask,
"net_type": iface.NetType,
"pci_slot": iface.PCISlot,
"qos": flattenQOS(iface.QOS),
"target": iface.Target,
"type": iface.Type,
"vnfs": iface.VNFs,
})
}
return res
}
func flattenQOS(qos compute.QOS) []map[string]interface{} {
return []map[string]interface{}{
{
"e_rate": qos.ERate,
"guid": qos.GUID,
"in_brust": qos.InBurst,
"in_rate": qos.InRate,
},
}
}
func flattenComputeDisks(disksList compute.ListDisks, extraDisks []interface{}, bootDiskId uint64) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(disksList))
for _, disk := range disksList {
if disk.ID == bootDiskId || findInExtraDisks(uint(disk.ID), extraDisks) { //skip main bootdisk and extraDisks
continue
}
temp := map[string]interface{}{
"disk_name": disk.Name,
"size": disk.SizeMax,
"sep_id": disk.SEPID,
"disk_type": disk.Type,
"pool": disk.Pool,
"desc": disk.Description,
"image_id": disk.ImageID,
"disk_id": disk.ID,
"shareable": disk.Shareable,
"size_used": disk.SizeUsed,
}
res = append(res, temp)
}
sort.Slice(res, func(i, j int) bool {
return res[i]["disk_id"].(uint64) < res[j]["disk_id"].(uint64)
})
return res
}
func findInExtraDisks(diskId uint, extraDisks []interface{}) bool {
for _, ExtraDisk := range extraDisks {
if diskId == uint(ExtraDisk.(int)) {
return true
}
}
return false
}
func findBootDisk(disks compute.ListDisks) *compute.ItemDisk {
for _, disk := range disks {
if disk.Type == "B" {
return &disk
}
}
return nil
}
func flattenAffinityRules(rules compute.ListRules) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(rules))
for _, rule := range rules {
res = append(res, map[string]interface{}{
"topology": rule.Topology,
"policy": rule.Policy,
"mode": rule.Mode,
"key": rule.Key,
"value": rule.Value,
})
}
return res
}

View File

@@ -1,190 +0,0 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
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.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/
package kvmvm
type DiskRecord struct {
Acl map[string]interface{} `json:"acl"`
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
BootPartition int `json:"bootPartition"`
CreatedTime uint64 `json:"creationTime"`
ComputeID int `json:"computeId"`
ComputeName string `json:"computeName"`
DeletedTime uint64 `json:"deletionTime"`
DeviceName string `json:"devicename"`
Desc string `json:"desc"`
DestructionTime uint64 `json:"destructionTime"`
DiskPath string `json:"diskPath"`
GridID int `json:"gid"`
GUID int `json:"guid"`
ID uint `json:"id"`
ImageID int `json:"imageId"`
Images []int `json:"images"`
IOTune map[string]interface{} `json:"iotune"`
IQN string `json:"iqn"`
Login string `json:"login"`
Name string `json:"name"`
MachineId int `json:"machineId"`
MachineName string `json:"machineName"`
Milestones uint64 `json:"milestones"`
Order int `json:"order"`
Params string `json:"params"`
Passwd string `json:"passwd"`
ParentId int `json:"parentId"`
PciSlot int `json:"pciSlot"`
Pool string `json:"pool"`
PurgeTime uint64 `json:"purgeTime"`
PurgeAttempts uint64 `json:"purgeAttempts"`
RealityDeviceNumber int `json:"realityDeviceNumber"`
ReferenceId string `json:"referenceId"`
ResID string `json:"resId"`
ResName string `json:"resName"`
Role string `json:"role"`
SepType string `json:"sepType"`
SepID int `json:"sepId"` // NOTE: absent from compute/get output
SizeMax int `json:"sizeMax"`
SizeUsed float64 `json:"sizeUsed"` // sum over all snapshots of this disk to report total consumed space
Snapshots []SnapshotRecord `json:"snapshots"`
Status string `json:"status"`
TechStatus string `json:"techStatus"`
Type string `json:"type"`
UpdateBy uint64 `json:"updateBy"`
VMID int `json:"vmid"`
}
type InterfaceRecord struct {
ConnID int `json:"connId"` // This is VLAN ID or VxLAN ID, depending on ConnType
ConnType string `json:"connType"` // Either "VLAN" or "VXLAN" tag
DefaultGW string `json:"defGw"`
Guid string `json:"guid"`
IPAddress string `json:"ipAddress"` // without trailing network mask, i.e. "192.168.1.3"
MAC string `json:"mac"`
Name string `json:"name"`
NetID int `json:"netId"` // This is either ExtNet ID or ViNS ID, depending on NetType
NetMask int `json:"netMask"`
NetType string `json:"netType"` // Either "EXTNET" or "VINS" tag
PciSlot int `json:"pciSlot"`
Target string `json:"target"`
Type string `json:"type"`
VNFs []int `json:"vnfs"`
QOS InterfaceQosRecord `json:"qos"`
}
type InterfaceQosRecord struct {
ERate int `json:"eRate"`
Guid string `json:"guid"`
InBurst int `json:"inBurst"`
InRate int `json:"inRate"`
}
type SnapshotRecord struct {
Guid string `json:"guid"`
Label string `json:"label"`
ResId string `json:"resId"`
SnapSetGuid string `json:"snapSetGuid"`
SnapSetTime uint64 `json:"snapSetTime"`
TimeStamp uint64 `json:"timestamp"`
}
type SnapshotRecordList []SnapshotRecord
type ComputeGetResp struct {
// ACLs `json:"ACL"` - it is a dictionary, special parsing required
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
Arch string `json:"arch"`
BootDiskSize int `json:"bootdiskSize"`
CloneReference int `json:"cloneReference"`
Clones []int `json:"clones"`
Cpu int `json:"cpus"`
Desc string `json:"desc"`
Disks []DiskRecord `json:"disks"`
Driver string `json:"driver"`
GridID int `json:"gid"`
ID uint `json:"id"`
ImageID int `json:"imageId"`
ImageName string `json:"imageName"`
Interfaces []InterfaceRecord `json:"interfaces"`
LockStatus string `json:"lockStatus"`
ManagerID int `json:"managerId"`
ManagerType string `json:"manageType"`
Name string `json:"name"`
NatableVinsID int `json:"natableVinsId"`
NatableVinsIP string `json:"natableVinsIp"`
NatableVinsName string `json:"natableVinsName"`
NatableVinsNet string `json:"natableVinsNetwork"`
NatableVinsNetName string `json:"natableVinsNetworkName"`
OsUsers []OsUserRecord `json:"osUsers"`
Ram int `json:"ram"`
RgID int `json:"rgId"`
RgName string `json:"rgName"`
SnapSets []SnapSetRecord `json:"snapSets"`
Status string `json:"status"`
// Tags []string `json:"tags"` // Tags were reworked since DECORT 3.7.1
TechStatus string `json:"techStatus"`
TotalDiskSize int `json:"totalDiskSize"`
UpdatedBy string `json:"updatedBy"`
UpdateTime uint64 `json:"updateTime"`
UserManaged bool `json:"userManaged"`
Vgpus []int `json:"vgpus"`
VinsConnected int `json:"vinsConnected"`
VirtualImageID int `json:"virtualImageId"`
}
type OsUserRecord struct {
Guid string `json:"guid"`
Login string `json:"login"`
Password string `json:"password"`
PubKey string `json:"pubkey"`
}
type SnapSetRecord struct {
Disks []int `json:"disks"`
Guid string `json:"guid"`
Label string `json:"label"`
TimeStamp uint64 `json:"timestamp"`
}
type ComputeBriefRecord struct { // this is a brief compute specifiaction as returned by API rg/listComputes
// we do not even include here all fields as returned by this API, but only the most important that
// are really necessary to identify and distinguish computes
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
Name string `json:"name"`
ID uint `json:"id"`
RgID int `json:"rgId"`
RgName string `json:"rgName"`
Status string `json:"status"`
TechStatus string `json:"techStatus"`
}
type RgListComputesResp []ComputeBriefRecord

View File

@@ -1,154 +0,0 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
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.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/
package kvmvm
import (
"bytes"
"hash/fnv"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/statefuncs"
log "github.com/sirupsen/logrus"
"sort"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
// This is subresource of compute resource used when creating/managing compute network connections
func networkSubresIPAddreDiffSupperss(key, oldVal, newVal string, d *schema.ResourceData) bool {
if newVal != "" && newVal != oldVal {
log.Debugf("networkSubresIPAddreDiffSupperss: key=%s, oldVal=%q, newVal=%q -> suppress=FALSE", key, oldVal, newVal)
return false
}
log.Debugf("networkSubresIPAddreDiffSupperss: key=%s, oldVal=%q, newVal=%q -> suppress=TRUE", key, oldVal, newVal)
return true // suppress difference
}
// This function is based on the original Terraform SerializeResourceForHash found
// in helper/schema/serialize.go
// It skips network subresource attributes, which are irrelevant for identification
// of unique network blocks
func networkSubresourceSerialize(output *bytes.Buffer, val interface{}, resource *schema.Resource) {
if val == nil {
return
}
rs := resource.Schema
m := val.(map[string]interface{})
keys := make([]string, 0, len(rs))
allComputed := true
for k, val := range rs {
if val.Optional || val.Required {
allComputed = false
}
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
// explicitly ignore "ip_address" when hashing
if k == "ip_address" {
continue
}
subSchema := rs[k]
// Skip attributes that are not user-provided. Computed attributes
// do not contribute to the hash since their ultimate value cannot
// be known at plan/diff time.
if !allComputed && !(subSchema.Required || subSchema.Optional) {
continue
}
output.WriteString(k)
output.WriteRune(':')
value := m[k]
schema.SerializeValueForHash(output, value, subSchema)
}
}
// HashNetworkSubresource hashes network subresource of compute resource. It uses
// specially designed networkSubresourceSerialize (see above) to make sure hashing
// does not involve attributes that we deem irrelevant to the uniqueness of network
// subresource definitions.
// It is this function that should be specified as SchemaSetFunc when creating Set
// from network subresource (e.g. in flattenCompute)
//
// This function is based on the original Terraform function HashResource from
// helper/schema/set.go
func HashNetworkSubresource(resource *schema.Resource) schema.SchemaSetFunc {
return func(v interface{}) int {
var serialized bytes.Buffer
networkSubresourceSerialize(&serialized, v, resource)
hs := fnv.New32a()
hs.Write(serialized.Bytes())
return int(hs.Sum32())
}
}
func networkSubresourceSchemaMake() map[string]*schema.Schema {
rets := map[string]*schema.Schema{
"net_type": {
Type: schema.TypeString,
Required: true,
StateFunc: statefuncs.StateFuncToUpper,
ValidateFunc: validation.StringInSlice([]string{"EXTNET", "VINS"}, false), // observe case while validating
Description: "Type of the network for this connection, either EXTNET or VINS.",
},
"net_id": {
Type: schema.TypeInt,
Required: true,
Description: "ID of the network for this connection.",
},
"ip_address": {
Type: schema.TypeString,
Optional: true,
Computed: true,
DiffSuppressFunc: networkSubresIPAddreDiffSupperss,
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
}

View File

@@ -0,0 +1,63 @@
package kvmvm
import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/dc"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/service/cloudbroker/ic"
)
func checkParamsExistence(ctx context.Context, d *schema.ResourceData, c *controller.ControllerCfg) diag.Diagnostics {
errs := []error{}
if err := ic.ExistRG(ctx, uint64(d.Get("rg_id").(int)), c); err != nil {
errs = append(errs, err)
}
if err := ic.ExistImage(ctx, uint64(d.Get("image_id").(int)), c); err != nil {
errs = append(errs, err)
}
if netErrs := existNetworks(ctx, d, c); errs != nil {
errs = append(errs, netErrs...)
}
return dc.ErrorsToDiagnostics(errs)
}
func existNetworks(ctx context.Context, d *schema.ResourceData, c *controller.ControllerCfg) []error {
var errs []error
var vinsIds, extNetIds []uint64
networksIface, ok := d.GetOk("network")
if !ok {
return nil
}
networkList := networksIface.(*schema.Set).List()
for _, elem := range networkList {
network := elem.(map[string]interface{})
switch network["net_type"].(string) {
case "VINS":
vinsIds = append(vinsIds, uint64(network["net_id"].(int)))
case "EXTNET":
extNetIds = append(extNetIds, uint64(network["net_id"].(int)))
default:
continue
}
}
if vinsErrs := ic.ExistVinses(ctx, vinsIds, c); vinsErrs != nil {
errs = append(errs, vinsErrs...)
}
if extNetErrs := ic.ExistExtNets(ctx, extNetIds, c); extNetErrs != nil {
errs = append(errs, extNetErrs...)
}
return errs
}

File diff suppressed because it is too large Load Diff

View File

@@ -33,12 +33,10 @@ package kvmvm
import (
"context"
"fmt"
"strconv"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/compute"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/rg"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -46,7 +44,6 @@ import (
func utilityComputeExtraDisksConfigure(ctx context.Context, d *schema.ResourceData, m interface{}, do_delta bool) error {
c := m.(*controller.ControllerCfg)
computeID, _ := strconv.ParseUint(d.Id(), 10, 64)
log.Debugf("utilityComputeExtraDisksConfigure: called for Compute ID %s with do_delta = %t", d.Id(), do_delta)
@@ -61,8 +58,9 @@ func utilityComputeExtraDisksConfigure(ctx context.Context, d *schema.ResourceDa
}
for _, disk := range new_set.(*schema.Set).List() {
computeId, _ := strconv.ParseUint(d.Id(), 10, 64)
req := compute.DiskAttachRequest{
ComputeID: computeID,
ComputeID: computeId,
DiskID: uint64(disk.(int)),
}
@@ -84,32 +82,52 @@ func utilityComputeExtraDisksConfigure(ctx context.Context, d *schema.ResourceDa
detach_set := old_set.(*schema.Set).Difference(new_set.(*schema.Set))
log.Debugf("utilityComputeExtraDisksConfigure: detach set has %d items for Compute ID %s", detach_set.Len(), d.Id())
for _, diskId := range detach_set.List() {
req := compute.DiskDetachRequest{
ComputeID: computeID,
DiskID: uint64(diskId.(int)),
if detach_set.Len() > 0 {
computeId, _ := strconv.ParseUint(d.Id(), 10, 64)
stopReq := compute.StopRequest{
ComputeID: computeId,
Force: false,
}
_, err := c.CloudBroker().Compute().Stop(ctx, stopReq)
if err != nil {
return err
}
_, err := c.CloudBroker().Compute().DiskDetach(ctx, req)
for _, diskId := range detach_set.List() {
req := compute.DiskDetachRequest{
ComputeID: computeId,
DiskID: uint64(diskId.(int)),
}
_, err := c.CloudBroker().Compute().DiskDetach(ctx, req)
if err != nil {
log.Errorf("utilityComputeExtraDisksConfigure: failed to detach disk ID %d from Compute ID %s: %s", diskId.(int), d.Id(), err)
apiErrCount++
lastSavedError = err
}
}
req := compute.StartRequest{
ComputeID: computeId,
AltBootID: 0,
}
_, err = c.CloudBroker().Compute().Start(ctx, req)
if err != nil {
// failed to detach disk - there will be partial resource update
log.Errorf("utilityComputeExtraDisksConfigure: failed to detach disk ID %d from Compute ID %s: %s", diskId.(int), d.Id(), err)
apiErrCount++
lastSavedError = err
return err
}
}
attach_set := new_set.(*schema.Set).Difference(old_set.(*schema.Set))
log.Debugf("utilityComputeExtraDisksConfigure: attach set has %d items for Compute ID %s", attach_set.Len(), d.Id())
for _, diskId := range attach_set.List() {
computeId, _ := strconv.ParseUint(d.Id(), 10, 64)
req := compute.DiskAttachRequest{
ComputeID: computeID,
ComputeID: computeId,
DiskID: uint64(diskId.(int)),
}
_, err := c.CloudBroker().Compute().DiskAttach(ctx, req)
if err != nil {
// failed to attach disk - there will be partial resource update
log.Errorf("utilityComputeExtraDisksConfigure: failed to attach disk ID %d to Compute ID %s: %s", diskId.(int), d.Id(), err)
apiErrCount++
lastSavedError = err
@@ -125,12 +143,50 @@ func utilityComputeExtraDisksConfigure(ctx context.Context, d *schema.ResourceDa
return nil
}
func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData, m interface{}, do_delta bool) error {
func utilityComputeCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (*compute.RecordCompute, error) {
c := m.(*controller.ControllerCfg)
req := compute.GetRequest{}
if d.Id() != "" {
computeId, _ := strconv.ParseUint(d.Id(), 10, 64)
req.ComputeID = computeId
} else {
req.ComputeID = uint64(d.Get("compute_id").(int))
}
res, err := c.CloudBroker().Compute().Get(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
func networkSubresIPAddreDiffSupperss(key, oldVal, newVal string, d *schema.ResourceData) bool {
if newVal != "" && newVal != oldVal {
log.Debugf("networkSubresIPAddreDiffSupperss: key=%s, oldVal=%q, newVal=%q -> suppress=FALSE", key, oldVal, newVal)
return false
}
log.Debugf("networkSubresIPAddreDiffSupperss: key=%s, oldVal=%q, newVal=%q -> suppress=TRUE", key, oldVal, newVal)
return true // suppress difference
}
func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData, m interface{}, do_delta bool, skip_zero bool, computeID uint64) error {
c := m.(*controller.ControllerCfg)
computeID, _ := strconv.ParseUint(d.Id(), 10, 64)
old_set, new_set := d.GetChange("network")
req := compute.StopRequest{
ComputeID: computeID,
Force: true,
}
log.Debugf("utilityComputeNetworksConfigure: stopping compute %d", computeID)
_, err := c.CloudBroker().Compute().Stop(ctx, req)
if err != nil {
return err
}
apiErrCount := 0
var lastSavedError error
@@ -139,10 +195,14 @@ func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData
return nil
}
for _, runner := range new_set.(*schema.Set).List() {
for i, runner := range new_set.(*schema.Set).List() {
if i == 0 && skip_zero {
continue
}
net_data := runner.(map[string]interface{})
computeId, _ := strconv.ParseUint(d.Id(), 10, 64)
req := compute.NetAttachRequest{
ComputeID: computeID,
ComputeID: computeId,
NetType: net_data["net_type"].(string),
NetID: uint64(net_data["net_id"].(int)),
}
@@ -170,15 +230,15 @@ func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData
log.Debugf("utilityComputeNetworksConfigure: detach set has %d items for Compute ID %s", detach_set.Len(), d.Id())
for _, runner := range detach_set.List() {
net_data := runner.(map[string]interface{})
computeId, _ := strconv.ParseUint(d.Id(), 10, 64)
req := compute.NetDetachRequest{
ComputeID: computeID,
ComputeID: computeId,
IPAddr: net_data["ip_address"].(string),
MAC: net_data["mac"].(string),
}
_, err := c.CloudBroker().Compute().NetDetach(ctx, req)
if err != nil {
// failed to detach this network - there will be partial resource update
log.Errorf("utilityComputeNetworksConfigure: failed to detach net ID %d of type %s from Compute ID %s: %s",
net_data["net_id"].(int), net_data["net_type"].(string), d.Id(), err)
apiErrCount++
@@ -190,10 +250,11 @@ func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData
log.Debugf("utilityComputeNetworksConfigure: attach set has %d items for Compute ID %s", attach_set.Len(), d.Id())
for _, runner := range attach_set.List() {
net_data := runner.(map[string]interface{})
computeId, _ := strconv.ParseUint(d.Id(), 10, 64)
req := compute.NetAttachRequest{
ComputeID: computeID,
NetID: uint64(net_data["net_id"].(int)),
ComputeID: computeId,
NetType: net_data["net_type"].(string),
NetID: uint64(net_data["net_id"].(int)),
}
if net_data["ip_address"].(string) != "" {
@@ -202,7 +263,6 @@ func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData
_, err := c.CloudBroker().Compute().NetAttach(ctx, req)
if err != nil {
// failed to attach this network - there will be partial resource update
log.Errorf("utilityComputeNetworksConfigure: failed to attach net ID %d of type %s to Compute ID %s: %s",
net_data["net_id"].(int), net_data["net_type"].(string), d.Id(), err)
apiErrCount++
@@ -210,6 +270,15 @@ func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData
}
}
startReq := compute.StartRequest{ComputeID: computeID}
log.Debugf("utilityComputeNetworksConfigure: starting compute %d", computeID)
_, err = c.CloudBroker().Compute().Start(ctx, startReq)
if err != nil {
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)
@@ -219,73 +288,40 @@ func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData
return nil
}
func utilityComputeCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (*compute.RecordCompute, error) {
c := m.(*controller.ControllerCfg)
idSet := false
computeID, err := strconv.ParseUint(d.Id(), 10, 64)
if err != nil || computeID <= 0 {
computeId, argSet := d.GetOk("compute_id") // NB: compute_id is NOT present in computeResource schema!
if argSet {
computeID = uint64(computeId.(int))
idSet = true
}
} else {
idSet = true
}
if idSet {
// compute ID is specified, try to get compute instance straight by this ID
log.Debugf("utilityComputeCheckPresence: locating compute by its ID %d", computeID)
req := compute.GetRequest{
ComputeID: computeID,
}
computeFacts, err := c.CloudBroker().Compute().Get(ctx, req)
if err != nil {
return nil, err
}
return computeFacts, nil
}
// ID was not set in the schema upon entering this function - work through Compute name
// and RG ID
computeName, argSet := d.GetOk("name")
if !argSet {
return nil, fmt.Errorf("Cannot locate compute instance if name is empty and no compute ID specified")
}
rgId, argSet := d.GetOk("rg_id")
if !argSet {
return nil, fmt.Errorf("Cannot locate compute by name %s if no resource group ID is set", computeName.(string))
}
rgListComputesReq := rg.ListComputesRequest{
RGID: uint64(rgId.(int)),
}
computeList, err := c.CloudBroker().RG().ListComputes(ctx, rgListComputesReq)
if err != nil {
return nil, err
}
log.Debugf("utilityComputeCheckPresence: traversing decoded JSON of length %d", len(computeList.Data))
for index, item := range computeList.Data {
// need to match Compute by name, skip Computes with the same name in DESTROYED satus
if item.Name == computeName.(string) && item.Status != "DESTROYED" {
log.Debugf("utilityComputeCheckPresence: index %d, matched name %s", index, item.Name)
// we found the Compute we need - now get detailed information via compute/get API
req := compute.GetRequest{
ComputeID: item.ID,
}
apiResp, err := c.CloudBroker().Compute().Get(ctx, req)
if err != nil {
return nil, err
}
return apiResp, nil
func isChangeDisk(els []interface{}, el interface{}) bool {
for _, elOld := range els {
elOldConv := elOld.(map[string]interface{})
elConv := el.(map[string]interface{})
if elOldConv["disk_id"].(int) == elConv["disk_id"].(int) &&
elOldConv["size"].(int) != elConv["size"].(int) {
return true
}
}
return nil, nil
return false
}
func isContainsDisk(els []interface{}, el interface{}) bool {
for _, elOld := range els {
elOldConv := elOld.(map[string]interface{})
elConv := el.(map[string]interface{})
if elOldConv["disk_name"].(string) == elConv["disk_name"].(string) {
return true
}
}
return false
}
func isContainsAR(els []interface{}, el interface{}) bool {
for _, elOld := range els {
elOldConv := elOld.(map[string]interface{})
elConv := el.(map[string]interface{})
if elOldConv["key"].(string) == elConv["key"].(string) &&
elOldConv["value"].(string) == elConv["value"].(string) &&
elOldConv["mode"].(string) == elConv["mode"].(string) &&
elOldConv["topology"].(string) == elConv["topology"].(string) &&
elOldConv["policy"].(string) == elConv["policy"].(string) {
return true
}
}
return false
}

View File

@@ -1,46 +1,57 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
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.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/
package kvmvm
const KvmX86CreateAPI = "/restmachine/cloudbroker/kvmx86/create"
const KvmPPCCreateAPI = "/restmachine/cloudbroker/kvmppc/create"
const ComputeGetAPI = "/restmachine/cloudbroker/compute/get"
const RgListComputesAPI = "/restmachine/cloudbroker/rg/listComputes"
const ComputeNetAttachAPI = "/restmachine/cloudbroker/compute/netAttach"
const ComputeNetDetachAPI = "/restmachine/cloudbroker/compute/netDetach"
const ComputeDiskAttachAPI = "/restmachine/cloudbroker/compute/diskAttach"
const ComputeDiskDetachAPI = "/restmachine/cloudbroker/compute/diskDetach"
const ComputeStartAPI = "/restmachine/cloudbroker/compute/start"
const ComputeStopAPI = "/restmachine/cloudbroker/compute/stop"
const ComputeResizeAPI = "/restmachine/cloudbroker/compute/resize"
const DisksResizeAPI = "/restmachine/cloudbroker/disks/resize2"
const ComputeDeleteAPI = "/restmachine/cloudbroker/compute/delete"
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Kasim Baybikov, <kmbaybikov@basistech.ru>
Nikita Sorokin, <nesorokin@basistech.ru>
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.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/
package kvmvm
import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/compute"
)
func utilityComputeBootDiskCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (*compute.ItemDisk, error) {
computeRecord, err := utilityComputeCheckPresence(ctx, d, m)
if err != nil {
return nil, err
}
bootDisk := &compute.ItemDisk{}
for _, disk := range computeRecord.Disks {
if disk.Name == "bootdisk" {
*bootDisk = disk
break
}
}
return bootDisk, nil
}