From e459fcb4c411cc1545d88c39600dc66262eef1fc Mon Sep 17 00:00:00 2001 From: Alexey Fetisov Date: Mon, 15 Jun 2026 13:23:15 +0300 Subject: [PATCH] 4.10.6 --- CHANGELOG.md | 36 +++++++- Makefile | 2 +- docs/resources/cb_kvmvm.md | 3 +- docs/resources/kvmvm.md | 4 +- go.mod | 2 +- go.sum | 4 +- .../cloudapi/kvmvm/resource_compute.go | 91 ++++++++++++++----- .../service/cloudapi/kvmvm/utility_compute.go | 14 ++- .../service/cloudbroker/flipgroup/flattens.go | 30 ++++++ .../flipgroup/resource_flipgroup.go | 2 +- .../kvmvm/resource_check_input_values.go | 6 +- .../cloudbroker/kvmvm/resource_compute.go | 30 +++++- internal/service/cloudbroker/kvmvm/schema.go | 14 ++- .../cloudbroker/kvmvm/utility_compute.go | 32 +++++-- .../service/cloudbroker/trunk/flattens.go | 8 +- .../cloudbroker/vfpool/resource_vfpool.go | 23 ++--- .../cloudbroker/vfpool/utility_vfpool.go | 41 +++------ samples/cloudapi/kvmvm/resource_kvmvm/main.tf | 17 +++- .../cloudbroker/kvmvm/resource_kvmvm/main.tf | 13 +-- 19 files changed, 268 insertions(+), 104 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc2f54bc..5c830c9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,38 @@ -## Version 4.10.5 +## Version 4.10.6 + +### Добавлено + +#### kvmvm +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-1276 | Добавлено опциональное поле `create_blank` в resource `decort_kvmvm` в cloudapi/kvmvm и в resource `decort_cb_kvmvm` в cloudbroker/kvmvm | +| BATF-1276 | Опциональное поле `alt_boot_id` в resource `decort_kvmvm` в cloudapi/kvmvm | + +### Изменено +#### kvmvm +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-1276 | Тип поля `disk_type` с опционального на вычисляемый в resource `decort_kvmvm` в cloudapi/kvmvm и в resource `decort_cb_kvmvm` в cloudbroker/kvmvm | ### Исправлено -#### kvmvmm +#### flipgroup | Идентификатор
задачи | Описание | | --- | --- | -| BATF-1270 | Опциональное поле `iotune` в блоке `disks` в resource `decort_kvmvm` в cloudapi/kvmvm и в resource `decort_cb_kvmvm` в cloudbroker/kvmvm | \ No newline at end of file +| BATF-1283 | Установка поля `desc` с платформы в ресурсе `decort_cb_flipgroup` в cloudbroker/flipgroup | + +#### kvmvm +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-1276 | Ошибка при старте ВМ с указанием поля `alt_boot_id` в resource `decort_cb_kvmvm` в cloudbroker/kvmvm | + +#### trunk +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-1285 | Установка полей `account_ids`, `ovs_bridge`, `native_vlan_id`, `trunk_tags` с платформы в ресурсе `decort_cb_trunk ` в cloudbroker/trunk | + +#### vfpool +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-1289 | Разрешено создавать пул виртуальных функций с блоком `config` при значении поля `enable` равным `false` в resource `decort_cb_vfpool` в cloudbroker/vfpool | +| BATF-1289 | Разрешено обновлять поля `name`, `description`, `account_access` и `rg_access` без блока `config` в resource `decort_cb_vfpool` в cloudbroker/vfpool | \ No newline at end of file diff --git a/Makefile b/Makefile index 28d60669..ce9a573b 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ ZIPDIR = ./zip BINARY=${NAME} WORKPATH= ./examples/terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAMESPACE}/${VERSION}/${OS_ARCH} MAINPATH = ./cmd/decort/ -VERSION=4.10.5 +VERSION=4.10.6 OS_ARCH=$(shell go env GOHOSTOS)_$(shell go env GOHOSTARCH) FILES = ${BINARY}_${VERSION}_darwin_amd64\ diff --git a/docs/resources/cb_kvmvm.md b/docs/resources/cb_kvmvm.md index be5995a0..5d74b75e 100644 --- a/docs/resources/cb_kvmvm.md +++ b/docs/resources/cb_kvmvm.md @@ -36,6 +36,7 @@ description: |- - `chipset` (String) Type of the emulated system. - `cloud_init` (String) Optional cloud_init parameters. Applied when creating new compute instance only, ignored in all other cases. - `cpu_pin` (Boolean) Run VM on dedicated CPUs. To use this feature, the system must be pre-configured by allocating CPUs on the physical node. +- `create_blank` (Boolean) If True, the compute is created via kvmx86/createBlank endpoint (without OS image). The image_id field is not required in this case. - `custom_fields` (String) - `description` (String) Optional text description of this compute instance. - `detach_disks` (Boolean) @@ -188,7 +189,6 @@ Required: Optional: - `desc` (String) Optional description -- `disk_type` (String) The type of disk in terms of its role in compute: 'B=Boot, D=Data' - `image_id` (Number) Specify image id for create disk from template - `iotune` (Block List, Max: 1) (see [below for nested schema](#nestedblock--disks--iotune)) - `node_ids` (Set of Number) @@ -204,6 +204,7 @@ Read-Only: - `delete_time` (Number) - `devicename` (String) - `disk_id` (Number) Disk ID +- `disk_type` (String) The type of disk in terms of its role in compute: 'B=Boot, D=Data' - `present_to` (Map of Number) - `shareable` (Boolean) - `size_max` (Number) diff --git a/docs/resources/kvmvm.md b/docs/resources/kvmvm.md index 220fc806..a7267354 100644 --- a/docs/resources/kvmvm.md +++ b/docs/resources/kvmvm.md @@ -27,6 +27,7 @@ description: |- - `affinity_label` (String) Set affinity label for compute - `affinity_rules` (Block List) (see [below for nested schema](#nestedblock--affinity_rules)) +- `alt_boot_id` (Number) ID of CD-ROM live image to boot - `anti_affinity_rules` (Block List) (see [below for nested schema](#nestedblock--anti_affinity_rules)) - `auto_start_w_node` (Boolean) Flag for start compute after node exits from MAINTENANCE state - `boot_disk_size` (Number) This compute instance boot disk size in GB. Make sure it is large enough to accomodate selected OS image. @@ -35,6 +36,7 @@ description: |- - `chipset` (String) Type of the emulated system. - `cloud_init` (String) Optional cloud_init parameters. Applied when creating new compute instance only, ignored in all other cases. - `cpu_pin` (Boolean) Run VM on dedicated CPUs. To use this feature, the system must be pre-configured by allocating CPUs on the physical node. +- `create_blank` (Boolean) If True, the compute is created via kvmx86/createBlank endpoint (without OS image). The image_id field is not required in this case. - `custom_fields` (String) - `description` (String) Optional text description of this compute instance. - `detach_disks` (Boolean) @@ -182,7 +184,6 @@ Required: Optional: - `desc` (String) Optional description -- `disk_type` (String) The type of disk in terms of its role in compute: 'B=Boot, D=Data' - `image_id` (Number) Specify image id for create disk from template - `iotune` (Block List, Max: 1) (see [below for nested schema](#nestedblock--disks--iotune)) - `permanently` (Boolean) Disk deletion status @@ -197,6 +198,7 @@ Read-Only: - `deleted_time` (Number) - `devicename` (String) - `disk_id` (Number) Disk ID +- `disk_type` (String) The type of disk in terms of its role in compute: 'B=Boot, D=Data' - `present_to` (Map of Number) - `shareable` (Boolean) - `size_max` (Number) diff --git a/go.mod b/go.mod index 9ad304eb..4709c87b 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 github.com/sirupsen/logrus v1.9.0 golang.org/x/net v0.44.0 - repository.basistech.ru/BASIS/decort-golang-sdk v1.12.11 + repository.basistech.ru/BASIS/decort-golang-sdk v1.12.12 ) require ( diff --git a/go.sum b/go.sum index 69942e2e..b43fab2e 100644 --- a/go.sum +++ b/go.sum @@ -318,5 +318,5 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -repository.basistech.ru/BASIS/decort-golang-sdk v1.12.11 h1:Y5meH2uCSsH7QOsQqqyRxSObRIGtmXB9pKbJZDCKzsw= -repository.basistech.ru/BASIS/decort-golang-sdk v1.12.11/go.mod h1:S/f7GxwWcE88eFpORV+I9xqEf8zDW5srQHpG2XQCLZM= +repository.basistech.ru/BASIS/decort-golang-sdk v1.12.12 h1:dkLPikeIh9un93zDB2FMtF5E0hJnp8kEKBrC9YbSki8= +repository.basistech.ru/BASIS/decort-golang-sdk v1.12.12/go.mod h1:S/f7GxwWcE88eFpORV+I9xqEf8zDW5srQHpG2XQCLZM= diff --git a/internal/service/cloudapi/kvmvm/resource_compute.go b/internal/service/cloudapi/kvmvm/resource_compute.go index cdca311c..0e8f685b 100644 --- a/internal/service/cloudapi/kvmvm/resource_compute.go +++ b/internal/service/cloudapi/kvmvm/resource_compute.go @@ -71,13 +71,15 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf return diag.Errorf("resourceComputeCreate: can't create Compute because rgID %d is not allowed or does not exist", d.Get("rg_id").(int)) } - hasImage, err := existImageId(ctx, d, m) - if err != nil { - return diag.FromErr(err) - } + if !d.Get("create_blank").(bool) { + hasImage, err := existImageId(ctx, d, m) + if err != nil { + return diag.FromErr(err) + } - if !hasImage { - return diag.Errorf("resourceComputeCreate: can't create Compute because imageID %d is not allowed or does not exist", d.Get("image_id").(int)) + if !hasImage { + return diag.Errorf("resourceComputeCreate: can't create Compute because imageID %d is not allowed or does not exist", d.Get("image_id").(int)) + } } if zoneID, ok := d.GetOk("zone_id"); ok { @@ -288,7 +290,31 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf } log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86") - apiResp, err := c.CloudAPI().KVMX86().Create(ctx, createReqX86) + var apiResp uint64 + if d.Get("create_blank").(bool) { + log.Debugf("resourceComputeCreate: using createBlank endpoint") + createBlankReq := kvmx86.CreateBlankRequest{ + RGID: createReqX86.RGID, + Name: createReqX86.Name, + CPU: createReqX86.CPU, + RAM: createReqX86.RAM, + StoragePolicyID: createReqX86.StoragePolicyID, + WithoutBootDisk: createReqX86.WithoutBootDisk, + BootDisk: createReqX86.BootDisk, + SEPID: createReqX86.SepID, + Pool: createReqX86.Pool, + DataDisks: createReqX86.DataDisks, + Interfaces: createReqX86.Interfaces, + Description: createReqX86.Description, + Chipset: createReqX86.Chipset, + PreferredCPU: createReqX86.PreferredCPU, + ZoneID: createReqX86.ZoneID, + OSVersion: createReqX86.OSVersion, + } + apiResp, err = c.CloudAPI().KVMX86().CreateBlank(ctx, createBlankReq) + } else { + apiResp, err = c.CloudAPI().KVMX86().Create(ctx, createReqX86) + } if err != nil { return diag.FromErr(err) } @@ -452,6 +478,9 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf if start, ok := d.GetOk("started"); ok { if start.(bool) { req := compute.StartRequest{ComputeID: computeId} + if altBootID, ok := d.Get("alt_boot_id").(int); ok { + req.AltBootID = uint64(altBootID) + } log.Debugf("resourceComputeCreate: starting Compute ID %d after completing its resource configuration", computeId) if _, err := c.CloudAPI().Compute().Start(ctx, req); err != nil { warnings.Add(err) @@ -763,13 +792,15 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf return diag.Errorf("resourceComputeUpdate: can't update Compute because rgID %d not allowed or does not exist", d.Get("rg_id").(int)) } - hasImage, err := existImageId(ctx, d, m) - if err != nil { - return diag.FromErr(err) - } + if !d.Get("create_blank").(bool) { + hasImage, err := existImageId(ctx, d, m) + if err != nil { + return diag.FromErr(err) + } - if !hasImage { - return diag.Errorf("resourceComputeUpdate: can't update Compute because imageID %d not allowed or does not exist", d.Get("image_id").(int)) + if !hasImage { + return diag.Errorf("resourceComputeUpdate: can't update Compute because imageID %d not allowed or does not exist", d.Get("image_id").(int)) + } } if d.HasChange("zone_id") { @@ -857,6 +888,9 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf if start, ok := d.GetOk("started"); ok { if start.(bool) { req := compute.StartRequest{ComputeID: computeRec.ID} + if altBootID, ok := d.Get("alt_boot_id").(int); ok { + req.AltBootID = uint64(altBootID) + } if _, err := c.CloudAPI().Compute().Start(ctx, req); err != nil { return diag.FromErr(err) @@ -1099,7 +1133,11 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf // If used to be STARTED, we need to start it after update if isStopRequired { - if _, err := c.CloudAPI().Compute().Start(ctx, compute.StartRequest{ComputeID: computeRec.ID}); err != nil { + req := compute.StartRequest{ComputeID: computeRec.ID} + if altBootID, ok := d.Get("alt_boot_id").(int); ok { + req.AltBootID = uint64(altBootID) + } + if _, err := c.CloudAPI().Compute().Start(ctx, req); err != nil { return diag.FromErr(err) } } @@ -1208,9 +1246,6 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf if diskConv["sep_id"].(int) != 0 { req.SepID = uint64(diskConv["sep_id"].(int)) } - if diskConv["disk_type"].(string) != "" { - req.DiskType = diskConv["disk_type"].(string) - } if diskConv["pool"].(string) != "" { req.Pool = diskConv["pool"].(string) } @@ -1856,6 +1891,9 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf req := compute.StartRequest{ ComputeID: computeRec.ID, } + if altBootID, ok := d.Get("alt_boot_id").(int); ok { + req.AltBootID = uint64(altBootID) + } if !isStopRequired { if _, err := c.CloudAPI().Compute().Start(ctx, req); err != nil { return diag.FromErr(err) @@ -2051,11 +2089,9 @@ func disksSubresourceSchemaMake() map[string]*schema.Schema { Description: "Storage endpoint provider ID; by default the same with boot disk", }, "disk_type": { - Type: schema.TypeString, - Computed: true, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{"B", "D"}, false), - Description: "The type of disk in terms of its role in compute: 'B=Boot, D=Data'", + Type: schema.TypeString, + Computed: true, + Description: "The type of disk in terms of its role in compute: 'B=Boot, D=Data'", }, "pool": { Type: schema.TypeString, @@ -2353,6 +2389,12 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema { Default: false, Description: "If True, the imageId, bootDisk, sepId, pool parameters are ignored and the compute is created without a boot disk in the stopped state.", }, + "create_blank": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "If True, the compute is created via kvmx86/createBlank endpoint (without OS image). The image_id field is not required in this case.", + }, "boot_disk_size": { Type: schema.TypeInt, Optional: true, @@ -2607,6 +2649,11 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema { Default: false, Description: "Flag for resize compute", }, + "alt_boot_id": { + Type: schema.TypeInt, + Optional: true, + Description: "ID of CD-ROM live image to boot", + }, "started": { Type: schema.TypeBool, Optional: true, diff --git a/internal/service/cloudapi/kvmvm/utility_compute.go b/internal/service/cloudapi/kvmvm/utility_compute.go index 12789c5e..6dc71e9c 100644 --- a/internal/service/cloudapi/kvmvm/utility_compute.go +++ b/internal/service/cloudapi/kvmvm/utility_compute.go @@ -293,7 +293,13 @@ func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData if needStart { computeId, _ := strconv.ParseUint(d.Id(), 10, 64) - if numErr, err := utilityComputeStart(ctx, computeId, m); err != nil { + var altBootID uint64 + if altBootIDRaw, ok := d.Get("alt_boot_id").(int); ok { + altBootID = uint64(altBootIDRaw) + } else { + altBootID = 0 + } + if numErr, err := utilityComputeStart(ctx, computeId, altBootID, m); err != nil { apiErrCount += numErr lastSavedError = err } @@ -456,10 +462,14 @@ func utilityComputeStop(ctx context.Context, computeID uint64, m interface{}) er return nil } -func utilityComputeStart(ctx context.Context, computeID uint64, m interface{}) (int, error) { +func utilityComputeStart(ctx context.Context, computeID uint64, altBootID uint64, m interface{}) (int, error) { c := m.(*controller.ControllerCfg) startReq := compute.StartRequest{ComputeID: computeID} + if altBootID > 0 { + startReq.AltBootID = altBootID + } + log.Debugf("utilityComputeNetworksConfigure: starting compute %d", computeID) _, err := c.CloudAPI().Compute().Start(ctx, startReq) if err != nil { diff --git a/internal/service/cloudbroker/flipgroup/flattens.go b/internal/service/cloudbroker/flipgroup/flattens.go index 4c35c5cb..131d42c0 100644 --- a/internal/service/cloudbroker/flipgroup/flattens.go +++ b/internal/service/cloudbroker/flipgroup/flattens.go @@ -70,6 +70,36 @@ func flattenFlipgroup(d *schema.ResourceData, flip *flipgroup.RecordFLIPGroup) { d.Set("updated_time", flip.UpdatedTime) } +func flattenFlipgroupResource(d *schema.ResourceData, flip *flipgroup.RecordFLIPGroup) { + d.Set("flipgroup_id", flip.ID) + d.Set("account_id", flip.AccountID) + d.Set("account_name", flip.AccountName) + d.Set("client_ids", flip.ClientIDs) + d.Set("client_names", flip.ClientNames) + d.Set("client_type", flip.ClientType) + d.Set("conn_id", flip.ConnID) + d.Set("conn_type", flip.ConnType) + d.Set("created_by", flip.CreatedBy) + d.Set("created_time", flip.CreatedTime) + d.Set("default_gw", flip.DefaultGW) + d.Set("deleted_by", flip.DeletedBy) + d.Set("deleted_time", flip.DeletedTime) + d.Set("desc", flip.Description) + d.Set("gid", flip.GID) + d.Set("guid", flip.GUID) + d.Set("ip", flip.IP) + d.Set("milestones", flip.Milestones) + d.Set("name", flip.Name) + d.Set("net_id", flip.NetID) + d.Set("net_type", flip.NetType) + d.Set("network", flip.Network) + d.Set("rg_id", flip.RGID) + d.Set("rg_name", flip.RGName) + d.Set("status", flip.Status) + d.Set("updated_by", flip.UpdatedBy) + d.Set("updated_time", flip.UpdatedTime) +} + func flattenFlipgroupsList(fg *flipgroup.ListFLIPGroups) []map[string]interface{} { res := make([]map[string]interface{}, 0, len(fg.Data)) for _, flip := range fg.Data { diff --git a/internal/service/cloudbroker/flipgroup/resource_flipgroup.go b/internal/service/cloudbroker/flipgroup/resource_flipgroup.go index 5e5a5ac0..fdbf6335 100644 --- a/internal/service/cloudbroker/flipgroup/resource_flipgroup.go +++ b/internal/service/cloudbroker/flipgroup/resource_flipgroup.go @@ -110,7 +110,7 @@ func resourceFlipgroupRead(ctx context.Context, d *schema.ResourceData, m interf return diag.Errorf("The flipgroup status is destroyed and cannot be read.") } - flattenFlipgroup(d, fg) + flattenFlipgroupResource(d, fg) log.Debugf("resourceFlipgroupRead: after flattenFlipgroup: flipgroup_id %s, name %s", d.Id(), d.Get("name").(string)) diff --git a/internal/service/cloudbroker/kvmvm/resource_check_input_values.go b/internal/service/cloudbroker/kvmvm/resource_check_input_values.go index c0969933..79971b88 100644 --- a/internal/service/cloudbroker/kvmvm/resource_check_input_values.go +++ b/internal/service/cloudbroker/kvmvm/resource_check_input_values.go @@ -17,8 +17,10 @@ func checkParamsExistence(ctx context.Context, d *schema.ResourceData, c *contro errs = append(errs, err) } - if err := ic.ExistImage(ctx, uint64(d.Get("image_id").(int)), c); err != nil { - errs = append(errs, err) + if !d.Get("create_blank").(bool) { + 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 { diff --git a/internal/service/cloudbroker/kvmvm/resource_compute.go b/internal/service/cloudbroker/kvmvm/resource_compute.go index cad6cf52..a90299e9 100644 --- a/internal/service/cloudbroker/kvmvm/resource_compute.go +++ b/internal/service/cloudbroker/kvmvm/resource_compute.go @@ -231,7 +231,32 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf } log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86") - apiResp, err := c.CloudBroker().KVMX86().Create(ctx, createReqX86) + var apiResp uint64 + var err error + if d.Get("create_blank").(bool) { + log.Debugf("resourceComputeCreate: using createBlank endpoint") + createBlankReq := kvmx86.CreateBlankRequest{ + RGID: createReqX86.RGID, + Name: createReqX86.Name, + CPU: createReqX86.CPU, + RAM: createReqX86.RAM, + StoragePolicyID: createReqX86.StoragePolicyID, + WithoutBootDisk: createReqX86.WithoutBootDisk, + BootDisk: createReqX86.BootDisk, + SEPID: createReqX86.SEPID, + Pool: createReqX86.Pool, + DataDisks: createReqX86.DataDisks, + Interfaces: createReqX86.Interfaces, + Description: createReqX86.Description, + Chipset: createReqX86.Chipset, + PreferredCPU: createReqX86.PreferredCPU, + ZoneID: createReqX86.ZoneID, + OSVersion: createReqX86.OSVersion, + } + apiResp, err = c.CloudBroker().KVMX86().CreateBlank(ctx, createBlankReq) + } else { + apiResp, err = c.CloudBroker().KVMX86().Create(ctx, createReqX86) + } if err != nil { return diag.FromErr(err) } @@ -424,6 +449,9 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf if start, ok := d.GetOk("started"); ok && start.(bool) { req := compute.StartRequest{ComputeID: computeId} + if altBootID, ok := d.Get("alt_boot_id").(int); ok { + req.AltBootID = uint64(altBootID) + } log.Debugf("resourceComputeCreate: starting Compute ID %d after completing its resource configuration", computeId) if _, err := c.CloudBroker().Compute().Start(ctx, req); err != nil { warnings.Add(err) diff --git a/internal/service/cloudbroker/kvmvm/schema.go b/internal/service/cloudbroker/kvmvm/schema.go index 3e341fe8..2cdc04e3 100644 --- a/internal/service/cloudbroker/kvmvm/schema.go +++ b/internal/service/cloudbroker/kvmvm/schema.go @@ -3406,6 +3406,12 @@ func resourceComputeSchemaMake() map[string]*schema.Schema { Default: false, Description: "If True, the imageId, bootDisk, sepId, pool parameters are ignored and the compute is created without a boot disk in the stopped state.", }, + "create_blank": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "If True, the compute is created via kvmx86/createBlank endpoint (without OS image). The image_id field is not required in this case.", + }, "boot_disk_size": { Type: schema.TypeInt, Optional: true, @@ -3728,11 +3734,9 @@ func resourceComputeSchemaMake() map[string]*schema.Schema { Description: "Storage endpoint provider ID; by default the same with boot disk", }, "disk_type": { - Type: schema.TypeString, - Computed: true, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{"B", "D"}, false), - Description: "The type of disk in terms of its role in compute: 'B=Boot, D=Data'", + Type: schema.TypeString, + Computed: true, + Description: "The type of disk in terms of its role in compute: 'B=Boot, D=Data'", }, "pool": { Type: schema.TypeString, diff --git a/internal/service/cloudbroker/kvmvm/utility_compute.go b/internal/service/cloudbroker/kvmvm/utility_compute.go index 2633d3a1..3100ead4 100644 --- a/internal/service/cloudbroker/kvmvm/utility_compute.go +++ b/internal/service/cloudbroker/kvmvm/utility_compute.go @@ -184,7 +184,11 @@ func utilityComputeResize(ctx context.Context, d *schema.ResourceData, m interfa } if isStopRequired { - if _, err := c.CloudBroker().Compute().Start(ctx, compute.StartRequest{ComputeID: computeId}); err != nil { + req := compute.StartRequest{ComputeID: computeId} + if altBootID, ok := d.Get("alt_boot_id").(int); ok { + req.AltBootID = uint64(altBootID) + } + if _, err := c.CloudBroker().Compute().Start(ctx, req); err != nil { return err } } @@ -324,9 +328,6 @@ func utilityComputeUpdateDisks(ctx context.Context, d *schema.ResourceData, m in if diskConv["sep_id"].(int) != 0 { req.SepID = uint64(diskConv["sep_id"].(int)) } - if diskConv["disk_type"].(string) != "" { - req.DiskType = diskConv["disk_type"].(string) - } if diskConv["pool"].(string) != "" { req.Pool = diskConv["pool"].(string) } @@ -835,7 +836,13 @@ func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData if needStart { computeId, _ := strconv.ParseUint(d.Id(), 10, 64) - if numErr, err := utilityComputeStart(ctx, computeId, m); err != nil { + var altBootID uint64 + if altBootIDRaw, ok := d.Get("alt_boot_id").(int); ok { + altBootID = uint64(altBootIDRaw) + } else { + altBootID = 0 + } + if numErr, err := utilityComputeStart(ctx, computeId, altBootID, m); err != nil { apiErrCount += numErr lastSavedError = err } @@ -1162,7 +1169,11 @@ func utilityComputeUpdate(ctx context.Context, d *schema.ResourceData, m interfa // If used to be STARTED, we need to start it after update if isStopRequired { - if _, err := c.CloudBroker().Compute().Start(ctx, compute.StartRequest{ComputeID: computeId}); err != nil { + req := compute.StartRequest{ComputeID: computeId} + if altBootID, ok := d.Get("alt_boot_id").(int); ok { + req.AltBootID = uint64(altBootID) + } + if _, err := c.CloudBroker().Compute().Start(ctx, req); err != nil { return err } } @@ -1633,6 +1644,9 @@ func utilityComputeRollback(ctx context.Context, d *schema.ResourceData, m inter } startReq := compute.StartRequest{ComputeID: computeId} + if altBootID, ok := d.Get("alt_boot_id").(int); ok { + startReq.AltBootID = uint64(altBootID) + } log.Debugf("utilityComputeRollback: starting compute %d", computeId) @@ -1890,10 +1904,14 @@ func utilityComputeStop(ctx context.Context, d *schema.ResourceData, m interface return nil } -func utilityComputeStart(ctx context.Context, computeID uint64, m interface{}) (int, error) { +func utilityComputeStart(ctx context.Context, computeID uint64, altBootID uint64, m interface{}) (int, error) { c := m.(*controller.ControllerCfg) startReq := compute.StartRequest{ComputeID: computeID} + if altBootID > 0 { + startReq.AltBootID = altBootID + } + log.Debugf("utilityComputeStart: starting compute %d", computeID) _, err := c.CloudBroker().Compute().Start(ctx, startReq) if err != nil { diff --git a/internal/service/cloudbroker/trunk/flattens.go b/internal/service/cloudbroker/trunk/flattens.go index b7591780..4cb9679f 100644 --- a/internal/service/cloudbroker/trunk/flattens.go +++ b/internal/service/cloudbroker/trunk/flattens.go @@ -15,11 +15,11 @@ func flattenTrunkResource(d *schema.ResourceData, details *trunk.ItemTrunk) { d.Set("name", details.Name) d.Set("mac", details.MAC) d.Set("description", details.Description) - d.Set("accountIds", details.AccountIDs) - d.Set("ovsBridge", details.OVSBridge) - d.Set("nativeVlanId", details.NativeVLANID) + d.Set("account_ids", details.AccountIDs) + d.Set("ovs_bridge", details.OVSBridge) + d.Set("native_vlan_id", details.NativeVLANID) d.Set("status", details.Status) - d.Set("trunkTags", details.TrunkTags) + d.Set("trunk_tags", details.TrunkTags) d.Set("created_at", details.CreatedAt) d.Set("created_by", details.CreatedBy) d.Set("updated_at", details.UpdatedAt) diff --git a/internal/service/cloudbroker/vfpool/resource_vfpool.go b/internal/service/cloudbroker/vfpool/resource_vfpool.go index 5ea466b5..1e10ce3b 100644 --- a/internal/service/cloudbroker/vfpool/resource_vfpool.go +++ b/internal/service/cloudbroker/vfpool/resource_vfpool.go @@ -33,6 +33,7 @@ package vfpool import ( "context" + "fmt" "strconv" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -85,6 +86,12 @@ func resourceVFPoolCreate(ctx context.Context, d *schema.ResourceData, m interfa } config, configOk := d.GetOk("config") + + enableVal := d.Get("enable").(bool) + if enableVal && !configOk { + return diag.FromErr(fmt.Errorf("enable requires config to be set")) + } + if configOk { configArray := config.(*schema.Set).List() req.Config = make([]vfpool.Config, 0, len(configArray)) @@ -117,10 +124,8 @@ func resourceVFPoolCreate(ctx context.Context, d *schema.ResourceData, m interfa warnings := dc.Warnings{} - if enable, ok := d.GetOk("enable"); ok { - if err := utilityVFPoolEnabled(ctx, m, enable.(bool), vfPoolID, configOk); err != nil { - warnings.Add(err) - } + if err := utilityVFPoolEnabled(ctx, m, enableVal, vfPoolID); err != nil { + warnings.Add(err) } log.Debugf("resourceVFPoolCreate: create VFPool with ID: %d, complete", vfPoolID) @@ -147,20 +152,12 @@ func resourceVFPoolUpdate(ctx context.Context, d *schema.ResourceData, m interfa log.Debugf("resourceVFPoolUpdate: called VFPool with id %d", vfPoolID) - _, ok := d.GetOk("config") - - if d.HasChanges("name,", "description", "account_access", "rg_access,", "config") { + if d.HasChanges("name", "description", "account_access", "rg_access", "config", "enable") { if err := utilityVFPoolUpdate(ctx, d, m, vfPoolID); err != nil { return diag.FromErr(err) } } - if d.HasChange("enable") { - if err := utilityVFPoolEnabled(ctx, m, d.Get("enable").(bool), vfPoolID, ok); err != nil { - return diag.FromErr(err) - } - } - log.Debugf("resourceVFPoolUpdate: update VFPool with id %d, complete", vfPoolID) return resourceVFPoolRead(ctx, d, m) diff --git a/internal/service/cloudbroker/vfpool/utility_vfpool.go b/internal/service/cloudbroker/vfpool/utility_vfpool.go index 7fd0c985..8b3e4d55 100644 --- a/internal/service/cloudbroker/vfpool/utility_vfpool.go +++ b/internal/service/cloudbroker/vfpool/utility_vfpool.go @@ -64,37 +64,26 @@ func utilityVFpoolCheckPresence(ctx context.Context, d *schema.ResourceData, m i return vfpoolData, nil } -func utilityVFPoolEnabled(ctx context.Context, m interface{}, enable bool, vfPoolID uint64, configOk bool) error { +func utilityVFPoolEnabled(ctx context.Context, m interface{}, enable bool, vfPoolID uint64) error { c := m.(*controller.ControllerCfg) - if enable && configOk { - req := vfpool.EnableRequest{ - VFPoolID: vfPoolID, - } - _, err := c.CloudBroker().VFPool().Enable(ctx, req) - if err != nil { - return err - } - } - if enable && !configOk { - return fmt.Errorf("you must provide configuration for this resource, after enabling it") - } - if !enable { - req := vfpool.DisableRequest{ - VFPoolID: vfPoolID, - } - _, err := c.CloudBroker().VFPool().Disable(ctx, req) - if err != nil { - return err - } + var err error + + if enable { + _, err = c.CloudBroker().VFPool().Enable(ctx, vfpool.EnableRequest{VFPoolID: vfPoolID}) + } else { + _, err = c.CloudBroker().VFPool().Disable(ctx, vfpool.DisableRequest{VFPoolID: vfPoolID}) } - log.Debugf("utilityVFPoolEnabled: enable=%v vfPool ID %d after completing its resource configuration", enable, vfPoolID) - - return nil + return err } func utilityVFPoolUpdate(ctx context.Context, d *schema.ResourceData, m interface{}, vfPoolID uint64) error { + hasConfig := len(d.Get("config").(*schema.Set).List()) > 0 + if d.Get("enable").(bool) && !hasConfig { + return fmt.Errorf("enable requires config to be set") + } + c := m.(*controller.ControllerCfg) vfPool, err := utilityVFpoolCheckPresence(ctx, d, m) @@ -190,7 +179,7 @@ func utilityVFPoolUpdate(ctx context.Context, d *schema.ResourceData, m interfac } log.Debugf("utilityVFPoolUpdate: update vfPool with ID: %d, complete with params=%v", vfPoolID, req) - if len(d.Get("config").(*schema.Set).List()) > 0 && d.Get("enable").(bool) { + if hasConfig && d.Get("enable").(bool) { reqEnable := vfpool.EnableRequest{ VFPoolID: vfPoolID, } @@ -201,8 +190,6 @@ func utilityVFPoolUpdate(ctx context.Context, d *schema.ResourceData, m interfac return err } log.Debugf("utilityVFPoolUpdate: enable vfPool with ID: %d, complete", vfPoolID) - } else { - return (fmt.Errorf("the vfPool is not enabled after update, you must provide configuration for this resource, after enabling it")) } return nil diff --git a/samples/cloudapi/kvmvm/resource_kvmvm/main.tf b/samples/cloudapi/kvmvm/resource_kvmvm/main.tf index b8152064..6d88ed3c 100644 --- a/samples/cloudapi/kvmvm/resource_kvmvm/main.tf +++ b/samples/cloudapi/kvmvm/resource_kvmvm/main.tf @@ -112,6 +112,18 @@ resource "decort_kvmvm" "comp" { #используется при создании #without_boot_disk = true + #создание без образа ОС + #опциональный параметр + #тип - булев + #используется при создании + #create_blank = false + + #id образа CD-ROM для загрузки + #опциональный параметр + #тип - целое число + #используется при создании и обновлении + #alt_boot_id = 1 + #необходимость выравнивать ВМ по NUMA #опциональный параметр #возможные значения - "none, "strict", "loose" @@ -160,11 +172,6 @@ resource "decort_kvmvm" "comp" { #тип - целое число #size = 5 - #тип диска - #опциональный параметр - #тип - строка - #disk_type = "D" - #id сепа #опциональный параметр #тип - целое число diff --git a/samples/cloudbroker/kvmvm/resource_kvmvm/main.tf b/samples/cloudbroker/kvmvm/resource_kvmvm/main.tf index 23065e9e..161b345e 100644 --- a/samples/cloudbroker/kvmvm/resource_kvmvm/main.tf +++ b/samples/cloudbroker/kvmvm/resource_kvmvm/main.tf @@ -82,6 +82,12 @@ resource "decort_cb_kvmvm" "comp" { #используется при создании #without_boot_disk = true + #создание без образа ОС + #опциональный параметр + #тип - булев + #используется при создании + #create_blank = false + #размер загрузочного диска #опциональный параметр #тип - целое число @@ -121,7 +127,7 @@ resource "decort_cb_kvmvm" "comp" { #id образа CD-ROM для загрузки #опциональный параметр #тип - целое число - #используется при обновлении, при повторном старте вм + #используется при создании и обновлении #alt_boot_id = 1 #необходимость выравнивать ВМ по NUMA @@ -166,11 +172,6 @@ resource "decort_cb_kvmvm" "comp" { #тип - целое число #storage_policy_id = 1 - #тип диска - #опциональный параметр - #тип - строка - #disk_type = "D" - #опциональный параметр #тип - целое число #sep_id = 1