Compare commits

..

2 Commits

Author SHA1 Message Date
db8d13d403 4.11.3 2026-06-15 13:37:04 +03:00
af79f6ab3e 4.11.2 2026-04-23 12:46:24 +03:00
43 changed files with 2469 additions and 1717 deletions

View File

@@ -1,38 +1,38 @@
## Version 4.11.1 ## Version 4.11.3
### Добавлено ### Добавлено
#### disks
| Идентификатор<br>задачи | Описание |
| --- | --- |
| BATF-1216 | Вычисляемое поле `blk_discard` в resource `resource_disk` в cloudapi/disks |
#### kvmvm #### kvmvm
| Идентификатор<br>задачи | Описание | | Идентификатор<br>задачи | Описание |
| --- | --- | | --- | --- |
| BATF-1216 | Вычисляемое поле `blk_discard` в resource `resource_kvmvm` в cloudapi/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
| Идентификатор<br>задачи | Описание |
| --- | --- |
| BATF-1276 | Тип поля `disk_type` с опционального на вычисляемый в resource `decort_kvmvm` в cloudapi/kvmvm и в resource `decort_cb_kvmvm` в cloudbroker/kvmvm |
### Исправлено ### Исправлено
#### disks #### flipgroup
| Идентификатор<br>задачи | Описание | | Идентификатор<br>задачи | Описание |
| --- | --- | | --- | --- |
| BATF-1186 | Тип поля `cache` с опционального на вычисляемый в resources `decort_disk` в cloudapi/disks | | BATF-1283 | Установка поля `desc` с платформы в ресурсе `decort_cb_flipgroup` в cloudbroker/flipgroup |
#### kvmvm #### kvmvm
| Идентификатор<br>задачи | Описание | | Идентификатор<br>задачи | Описание |
| --- | --- | | --- | --- |
| BATF-1220 | Ошибки применения новой конфигурации после импортирования в resource `decort_kvmvm` в cloudapi/kvmvm и в resource `decort_cb_kvmvm` в cloudbroker/kvmvm | | BATF-1276 | Ошибка при старте ВМ с указанием поля `alt_boot_id` в resource `decort_cb_kvmvm` в cloudbroker/kvmvm |
#### rg #### trunk
| Идентификатор<br>задачи | Описание | | Идентификатор<br>задачи | Описание |
| --- | --- | | --- | --- |
| BATF-1214 | Оптимизировано создание ресурных групп с указанными полем `def_net_type` в `decort_resgroup` в cloudapi/rg и в `decort_cb_rg` в cloudbroker/rg| | BATF-1285 | Установка полей `account_ids`, `ovs_bridge`, `native_vlan_id`, `trunk_tags` с платформы в ресурсе `decort_cb_trunk ` в cloudbroker/trunk |
| BATF-1219 | Отображение полей `updated_by` и `updated_time` в datasource `decort_rg_list_computes` в cloudapi/rg |
#### zone #### vfpool
| Идентификатор<br>задачи | Описание | | Идентификатор<br>задачи | Описание |
| --- | --- | | --- | --- |
| BATF-1192 | Ошибка отображения в datasource `decort_zone` в cloudapi/zone | | 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 |

View File

@@ -7,7 +7,7 @@ ZIPDIR = ./zip
BINARY=${NAME} BINARY=${NAME}
WORKPATH= ./examples/terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAMESPACE}/${VERSION}/${OS_ARCH} WORKPATH= ./examples/terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAMESPACE}/${VERSION}/${OS_ARCH}
MAINPATH = ./cmd/decort/ MAINPATH = ./cmd/decort/
VERSION=4.11.1 VERSION=4.11.3
OS_ARCH=$(shell go env GOHOSTOS)_$(shell go env GOHOSTARCH) OS_ARCH=$(shell go env GOHOSTOS)_$(shell go env GOHOSTARCH)
FILES = ${BINARY}_${VERSION}_darwin_amd64\ FILES = ${BINARY}_${VERSION}_darwin_amd64\

View File

@@ -17,6 +17,7 @@ description: |-
### Required ### Required
- `authenticator` (String) Authentication mode to use when connecting to DECORT cloud API. Should be one of 'decs3o', 'legacy', 'jwt' or 'bvs'. - `authenticator` (String) Authentication mode to use when connecting to DECORT cloud API. Should be one of 'decs3o', 'legacy', 'jwt' or 'bvs'.
- `controller_url` (String) URL of DECORT Cloud controller to use. API calls will be directed to this URL.
### Optional ### Optional
@@ -25,7 +26,6 @@ description: |-
- `app_secret` (String) Application secret to access DECORT cloud API in 'decs3o' and 'bvs' authentication mode. - `app_secret` (String) Application secret to access DECORT cloud API in 'decs3o' and 'bvs' authentication mode.
- `bvs_password` (String) User password for DECORT cloud API operations in 'bvs' authentication mode. - `bvs_password` (String) User password for DECORT cloud API operations in 'bvs' authentication mode.
- `bvs_user` (String) User name for DECORT cloud API operations in 'bvs' authentication mode. - `bvs_user` (String) User name for DECORT cloud API operations in 'bvs' authentication mode.
- `controller_url` (String) URL of DECORT Cloud controller to use. API calls will be directed to this URL.
- `domain` (String) User password for DECORT cloud API operations in 'bvs' authentication mode. - `domain` (String) User password for DECORT cloud API operations in 'bvs' authentication mode.
- `jwt` (String) JWT to access DECORT cloud API in 'jwt' authentication mode. - `jwt` (String) JWT to access DECORT cloud API in 'jwt' authentication mode.
- `oauth2_url` (String) OAuth2 application URL in 'decs3o' and 'bvs' authentication mode. - `oauth2_url` (String) OAuth2 application URL in 'decs3o' and 'bvs' authentication mode.

View File

@@ -38,6 +38,7 @@ description: |-
- `chipset` (String) Type of the emulated system. - `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. - `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. - `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) - `custom_fields` (String)
- `description` (String) Optional text description of this compute instance. - `description` (String) Optional text description of this compute instance.
- `detach_disks` (Boolean) - `detach_disks` (Boolean)
@@ -186,8 +187,8 @@ Optional:
- `blk_discard` (Boolean) - `blk_discard` (Boolean)
- `cache` (String) Setting the disk caching mode - `cache` (String) Setting the disk caching mode
- `desc` (String) Optional description - `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 - `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) - `node_ids` (Set of Number)
- `permanently` (Boolean) Disk deletion status - `permanently` (Boolean) Disk deletion status
- `pool` (String) Pool name; by default will be chosen automatically - `pool` (String) Pool name; by default will be chosen automatically
@@ -201,6 +202,7 @@ Read-Only:
- `delete_time` (Number) - `delete_time` (Number)
- `devicename` (String) - `devicename` (String)
- `disk_id` (Number) Disk ID - `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) - `present_to` (Map of Number)
- `shareable` (Boolean) - `shareable` (Boolean)
- `size_max` (Number) - `size_max` (Number)
@@ -208,6 +210,26 @@ Read-Only:
- `to_clean` (Boolean) - `to_clean` (Boolean)
- `update_time` (Number) - `update_time` (Number)
<a id="nestedblock--disks--iotune"></a>
### Nested Schema for `disks.iotune`
Optional:
- `read_bytes_sec` (Number)
- `read_bytes_sec_max` (Number)
- `read_iops_sec` (Number)
- `read_iops_sec_max` (Number)
- `size_iops_sec` (Number)
- `total_bytes_sec` (Number)
- `total_bytes_sec_max` (Number)
- `total_iops_sec` (Number)
- `total_iops_sec_max` (Number)
- `write_bytes_sec` (Number)
- `write_bytes_sec_max` (Number)
- `write_iops_sec` (Number)
- `write_iops_sec_max` (Number)
<a id="nestedblock--libvirt_settings"></a> <a id="nestedblock--libvirt_settings"></a>
### Nested Schema for `libvirt_settings` ### Nested Schema for `libvirt_settings`

View File

@@ -27,6 +27,7 @@ description: |-
- `affinity_label` (String) Set affinity label for compute - `affinity_label` (String) Set affinity label for compute
- `affinity_rules` (Block List) (see [below for nested schema](#nestedblock--affinity_rules)) - `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)) - `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 - `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. - `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. - `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. - `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. - `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) - `custom_fields` (String)
- `description` (String) Optional text description of this compute instance. - `description` (String) Optional text description of this compute instance.
- `detach_disks` (Boolean) - `detach_disks` (Boolean)
@@ -177,8 +179,8 @@ Required:
Optional: Optional:
- `desc` (String) Optional description - `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 - `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 - `permanently` (Boolean) Disk deletion status
- `pool` (String) Pool name; by default will be chosen automatically - `pool` (String) Pool name; by default will be chosen automatically
- `sep_id` (Number) Storage endpoint provider ID; by default the same with boot disk - `sep_id` (Number) Storage endpoint provider ID; by default the same with boot disk
@@ -193,6 +195,7 @@ Read-Only:
- `deleted_time` (Number) - `deleted_time` (Number)
- `devicename` (String) - `devicename` (String)
- `disk_id` (Number) Disk ID - `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) - `present_to` (Map of Number)
- `shareable` (Boolean) - `shareable` (Boolean)
- `size_max` (Number) - `size_max` (Number)
@@ -200,6 +203,26 @@ Read-Only:
- `to_clean` (Boolean) - `to_clean` (Boolean)
- `updated_time` (Number) - `updated_time` (Number)
<a id="nestedblock--disks--iotune"></a>
### Nested Schema for `disks.iotune`
Optional:
- `read_bytes_sec` (Number)
- `read_bytes_sec_max` (Number)
- `read_iops_sec` (Number)
- `read_iops_sec_max` (Number)
- `size_iops_sec` (Number)
- `total_bytes_sec` (Number)
- `total_bytes_sec_max` (Number)
- `total_iops_sec` (Number)
- `total_iops_sec_max` (Number)
- `write_bytes_sec` (Number)
- `write_bytes_sec_max` (Number)
- `write_iops_sec` (Number)
- `write_iops_sec_max` (Number)
<a id="nestedblock--network"></a> <a id="nestedblock--network"></a>
### Nested Schema for `network` ### Nested Schema for `network`
@@ -311,6 +334,7 @@ Read-Only:
- `disk_name` (String) - `disk_name` (String)
- `disk_type` (String) - `disk_type` (String)
- `image_id` (Number) - `image_id` (Number)
- `iotune` (List of Object) (see [below for nested schema](#nestedobjatt--boot_disk--iotune))
- `permanently` (Boolean) - `permanently` (Boolean)
- `pool` (String) - `pool` (String)
- `present_to` (Map of Number) - `present_to` (Map of Number)
@@ -323,6 +347,26 @@ Read-Only:
- `to_clean` (Boolean) - `to_clean` (Boolean)
- `updated_time` (Number) - `updated_time` (Number)
<a id="nestedobjatt--boot_disk--iotune"></a>
### Nested Schema for `boot_disk.iotune`
Read-Only:
- `read_bytes_sec` (Number)
- `read_bytes_sec_max` (Number)
- `read_iops_sec` (Number)
- `read_iops_sec_max` (Number)
- `size_iops_sec` (Number)
- `total_bytes_sec` (Number)
- `total_bytes_sec_max` (Number)
- `total_iops_sec` (Number)
- `total_iops_sec_max` (Number)
- `write_bytes_sec` (Number)
- `write_bytes_sec_max` (Number)
- `write_iops_sec` (Number)
- `write_iops_sec_max` (Number)
<a id="nestedatt--interfaces"></a> <a id="nestedatt--interfaces"></a>
### Nested Schema for `interfaces` ### Nested Schema for `interfaces`

2
go.mod
View File

@@ -9,7 +9,7 @@ require (
github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1
github.com/sirupsen/logrus v1.9.0 github.com/sirupsen/logrus v1.9.0
golang.org/x/net v0.44.0 golang.org/x/net v0.44.0
repository.basistech.ru/BASIS/decort-golang-sdk v1.13.8 repository.basistech.ru/BASIS/decort-golang-sdk v1.13.10
) )
require ( require (

4
go.sum
View File

@@ -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.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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
repository.basistech.ru/BASIS/decort-golang-sdk v1.13.8 h1:Uc+GBfbEg1dQPMuFfqNhKZmMO19N7OvdCNHIFnLLkp0= repository.basistech.ru/BASIS/decort-golang-sdk v1.13.10 h1:aRKyTH3/NSrpCLyLuTwCMtzOBoQ+hQ5EC4emQSnya5k=
repository.basistech.ru/BASIS/decort-golang-sdk v1.13.8/go.mod h1:S/f7GxwWcE88eFpORV+I9xqEf8zDW5srQHpG2XQCLZM= repository.basistech.ru/BASIS/decort-golang-sdk v1.13.10/go.mod h1:S/f7GxwWcE88eFpORV+I9xqEf8zDW5srQHpG2XQCLZM=

View File

@@ -335,6 +335,7 @@ func flattenComputeDisksDemo(disksList compute.ListComputeDisks, disksBlocks, ex
"permanently": pernamentlyValue, "permanently": pernamentlyValue,
"cache": disk.Cache, "cache": disk.Cache,
"blk_discard": disk.BLKDiscard, "blk_discard": disk.BLKDiscard,
"iotune": flattenIotune(disk.IOTune),
} }
res = append(res, temp) res = append(res, temp)
indexDataDisks++ indexDataDisks++

View File

@@ -71,6 +71,7 @@ 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)) return diag.Errorf("resourceComputeCreate: can't create Compute because rgID %d is not allowed or does not exist", d.Get("rg_id").(int))
} }
if !d.Get("create_blank").(bool) {
hasImage, err := existImageId(ctx, d, m) hasImage, err := existImageId(ctx, d, m)
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
@@ -79,6 +80,7 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
if !hasImage { 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)) 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 { if zoneID, ok := d.GetOk("zone_id"); ok {
createReqX86.ZoneID = uint64(zoneID.(int)) createReqX86.ZoneID = uint64(zoneID.(int))
@@ -294,7 +296,32 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
} }
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86") 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 { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
} }
@@ -390,6 +417,12 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
} }
} }
if _, ok := d.GetOk("disks"); ok {
if err := utilityComputeCreateIOTune(ctx, d, m); err != nil {
warnings.Add(err)
}
}
if !cleanup { if !cleanup {
if enabled, ok := d.GetOk("enabled"); ok { if enabled, ok := d.GetOk("enabled"); ok {
@@ -452,6 +485,9 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
if start, ok := d.GetOk("started"); ok { if start, ok := d.GetOk("started"); ok {
if start.(bool) { if start.(bool) {
req := compute.StartRequest{ComputeID: computeId} 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) log.Debugf("resourceComputeCreate: starting Compute ID %d after completing its resource configuration", computeId)
if _, err := c.CloudAPI().Compute().Start(ctx, req); err != nil { if _, err := c.CloudAPI().Compute().Start(ctx, req); err != nil {
warnings.Add(err) warnings.Add(err)
@@ -763,6 +799,7 @@ 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)) return diag.Errorf("resourceComputeUpdate: can't update Compute because rgID %d not allowed or does not exist", d.Get("rg_id").(int))
} }
if !d.Get("create_blank").(bool) {
hasImage, err := existImageId(ctx, d, m) hasImage, err := existImageId(ctx, d, m)
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
@@ -771,6 +808,11 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
if !hasImage { if !hasImage {
return diag.Errorf("resourceComputeUpdate: can't update Compute because imageID %d not allowed or does not exist", d.Get("image_id").(int)) return diag.Errorf("resourceComputeUpdate: can't update Compute because imageID %d not allowed or does not exist", d.Get("image_id").(int))
} }
}
if err != nil {
return diag.FromErr(err)
}
if d.HasChange("zone_id") { if d.HasChange("zone_id") {
if err := utilityComputeUpdateZoneID(ctx, d, m); err != nil { if err := utilityComputeUpdateZoneID(ctx, d, m); err != nil {
@@ -857,6 +899,9 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
if start, ok := d.GetOk("started"); ok { if start, ok := d.GetOk("started"); ok {
if start.(bool) { if start.(bool) {
req := compute.StartRequest{ComputeID: computeRec.ID} 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 { if _, err := c.CloudAPI().Compute().Start(ctx, req); err != nil {
return diag.FromErr(err) return diag.FromErr(err)
@@ -1099,7 +1144,11 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
// If used to be STARTED, we need to start it after update // If used to be STARTED, we need to start it after update
if isStopRequired { 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) return diag.FromErr(err)
} }
} }
@@ -1124,6 +1173,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
resizedDisks := make([]interface{}, 0) resizedDisks := make([]interface{}, 0)
renamedDisks := make([]interface{}, 0) renamedDisks := make([]interface{}, 0)
changeStoragePolicyDisks := make([]interface{}, 0) changeStoragePolicyDisks := make([]interface{}, 0)
iotuneUpdatedDisks := make([]interface{}, 0)
oldDisks, newDisks := d.GetChange("disks") oldDisks, newDisks := d.GetChange("disks")
oldConv := oldDisks.([]interface{}) oldConv := oldDisks.([]interface{})
@@ -1164,6 +1214,9 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
if isChangeStoragePolicy(oldConv, el) { if isChangeStoragePolicy(oldConv, el) {
changeStoragePolicyDisks = append(changeStoragePolicyDisks, el) changeStoragePolicyDisks = append(changeStoragePolicyDisks, el)
} }
if isChangeIOTuneDisk(oldConv, el) {
iotuneUpdatedDisks = append(iotuneUpdatedDisks, el)
}
} }
if len(deletedDisks) > 0 { if len(deletedDisks) > 0 {
@@ -1204,9 +1257,6 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
if diskConv["sep_id"].(int) != 0 { if diskConv["sep_id"].(int) != 0 {
req.SepID = uint64(diskConv["sep_id"].(int)) req.SepID = uint64(diskConv["sep_id"].(int))
} }
if diskConv["disk_type"].(string) != "" {
req.DiskType = diskConv["disk_type"].(string)
}
if diskConv["pool"].(string) != "" { if diskConv["pool"].(string) != "" {
req.Pool = diskConv["pool"].(string) req.Pool = diskConv["pool"].(string)
} }
@@ -1216,10 +1266,33 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
if diskConv["image_id"].(int) != 0 { if diskConv["image_id"].(int) != 0 {
req.ImageID = uint64(diskConv["image_id"].(int)) req.ImageID = uint64(diskConv["image_id"].(int))
} }
_, err := c.CloudAPI().Compute().DiskAdd(ctx, req) diskID, err := c.CloudAPI().Compute().DiskAdd(ctx, req)
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
} }
if iotuneRaw, ok := diskConv["iotune"].([]interface{}); ok && len(iotuneRaw) > 0 {
iotuneMap := iotuneRaw[0].(map[string]interface{})
limitReq := disks.LimitIORequest{
DiskID: diskID,
ReadBytesSec: uint64(iotuneMap["read_bytes_sec"].(int)),
ReadBytesSecMax: uint64(iotuneMap["read_bytes_sec_max"].(int)),
ReadIOPSSec: uint64(iotuneMap["read_iops_sec"].(int)),
ReadIOPSSecMax: uint64(iotuneMap["read_iops_sec_max"].(int)),
SizeIOPSSec: uint64(iotuneMap["size_iops_sec"].(int)),
TotalBytesSec: uint64(iotuneMap["total_bytes_sec"].(int)),
TotalBytesSecMax: uint64(iotuneMap["total_bytes_sec_max"].(int)),
TotalIOPSSec: uint64(iotuneMap["total_iops_sec"].(int)),
TotalIOPSSecMax: uint64(iotuneMap["total_iops_sec_max"].(int)),
WriteBytesSec: uint64(iotuneMap["write_bytes_sec"].(int)),
WriteBytesSecMax: uint64(iotuneMap["write_bytes_sec_max"].(int)),
WriteIOPSSec: uint64(iotuneMap["write_iops_sec"].(int)),
WriteIOPSSecMax: uint64(iotuneMap["write_iops_sec_max"].(int)),
}
_, err = c.CloudAPI().Disks().LimitIO(ctx, limitReq)
if err != nil {
return diag.FromErr(err)
}
}
} }
} }
@@ -1273,6 +1346,44 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
} }
} }
} }
if len(iotuneUpdatedDisks) > 0 {
for _, disk := range iotuneUpdatedDisks {
diskConv := disk.(map[string]interface{})
if diskConv["disk_type"].(string) == "B" {
continue
}
diskID := uint64(diskConv["disk_id"].(int))
if diskID == 0 {
continue
}
iotuneRaw, ok := diskConv["iotune"].([]interface{})
if !ok || len(iotuneRaw) == 0 {
continue
}
iotuneMap := iotuneRaw[0].(map[string]interface{})
req := disks.LimitIORequest{
DiskID: diskID,
ReadBytesSec: uint64(iotuneMap["read_bytes_sec"].(int)),
ReadBytesSecMax: uint64(iotuneMap["read_bytes_sec_max"].(int)),
ReadIOPSSec: uint64(iotuneMap["read_iops_sec"].(int)),
ReadIOPSSecMax: uint64(iotuneMap["read_iops_sec_max"].(int)),
SizeIOPSSec: uint64(iotuneMap["size_iops_sec"].(int)),
TotalBytesSec: uint64(iotuneMap["total_bytes_sec"].(int)),
TotalBytesSecMax: uint64(iotuneMap["total_bytes_sec_max"].(int)),
TotalIOPSSec: uint64(iotuneMap["total_iops_sec"].(int)),
TotalIOPSSecMax: uint64(iotuneMap["total_iops_sec_max"].(int)),
WriteBytesSec: uint64(iotuneMap["write_bytes_sec"].(int)),
WriteBytesSecMax: uint64(iotuneMap["write_bytes_sec_max"].(int)),
WriteIOPSSec: uint64(iotuneMap["write_iops_sec"].(int)),
WriteIOPSSecMax: uint64(iotuneMap["write_iops_sec_max"].(int)),
}
_, err := c.CloudAPI().Disks().LimitIO(ctx, req)
if err != nil {
return diag.FromErr(err)
}
}
}
} }
if d.HasChange("affinity_label") { if d.HasChange("affinity_label") {
@@ -1776,6 +1887,9 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
req := compute.StartRequest{ req := compute.StartRequest{
ComputeID: computeRec.ID, ComputeID: computeRec.ID,
} }
if altBootID, ok := d.Get("alt_boot_id").(int); ok {
req.AltBootID = uint64(altBootID)
}
if !isStopRequired { if !isStopRequired {
if _, err := c.CloudAPI().Compute().Start(ctx, req); err != nil { if _, err := c.CloudAPI().Compute().Start(ctx, req); err != nil {
return diag.FromErr(err) return diag.FromErr(err)
@@ -1862,6 +1976,40 @@ func isChangeStoragePolicy(els []interface{}, el interface{}) bool {
return false return false
} }
func isChangeIOTuneDisk(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) {
continue
}
oldIOTune := elOldConv["iotune"].([]interface{})
newIOTune := elConv["iotune"].([]interface{})
if len(oldIOTune) == 0 && len(newIOTune) == 0 {
return false
}
if len(oldIOTune) == 0 || len(newIOTune) == 0 {
return true
}
oldMap := oldIOTune[0].(map[string]interface{})
newMap := newIOTune[0].(map[string]interface{})
return oldMap["read_bytes_sec"].(int) != newMap["read_bytes_sec"].(int) ||
oldMap["read_bytes_sec_max"].(int) != newMap["read_bytes_sec_max"].(int) ||
oldMap["read_iops_sec"].(int) != newMap["read_iops_sec"].(int) ||
oldMap["read_iops_sec_max"].(int) != newMap["read_iops_sec_max"].(int) ||
oldMap["size_iops_sec"].(int) != newMap["size_iops_sec"].(int) ||
oldMap["total_bytes_sec"].(int) != newMap["total_bytes_sec"].(int) ||
oldMap["total_bytes_sec_max"].(int) != newMap["total_bytes_sec_max"].(int) ||
oldMap["total_iops_sec"].(int) != newMap["total_iops_sec"].(int) ||
oldMap["total_iops_sec_max"].(int) != newMap["total_iops_sec_max"].(int) ||
oldMap["write_bytes_sec"].(int) != newMap["write_bytes_sec"].(int) ||
oldMap["write_bytes_sec_max"].(int) != newMap["write_bytes_sec_max"].(int) ||
oldMap["write_iops_sec"].(int) != newMap["write_iops_sec"].(int) ||
oldMap["write_iops_sec_max"].(int) != newMap["write_iops_sec_max"].(int)
}
return false
}
func isContainsDisk(els []interface{}, el interface{}) bool { func isContainsDisk(els []interface{}, el interface{}) bool {
for _, elOld := range els { for _, elOld := range els {
elOldConv := elOld.(map[string]interface{}) elOldConv := elOld.(map[string]interface{})
@@ -1940,8 +2088,6 @@ func disksSubresourceSchemaMake() map[string]*schema.Schema {
"disk_type": { "disk_type": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, 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'", Description: "The type of disk in terms of its role in compute: 'B=Boot, D=Data'",
}, },
"pool": { "pool": {
@@ -1967,6 +2113,81 @@ func disksSubresourceSchemaMake() map[string]*schema.Schema {
Optional: true, Optional: true,
Description: "Disk deletion status", Description: "Disk deletion status",
}, },
"iotune": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"read_bytes_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"read_bytes_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"read_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"read_iops_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"size_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_bytes_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_bytes_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_iops_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_bytes_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_bytes_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_iops_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
},
},
},
"disk_id": { "disk_id": {
Type: schema.TypeInt, Type: schema.TypeInt,
Computed: true, Computed: true,
@@ -2173,6 +2394,12 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema {
Default: false, 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.", 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": { "boot_disk_size": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
@@ -2427,6 +2654,11 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema {
Default: false, Default: false,
Description: "Flag for resize compute", Description: "Flag for resize compute",
}, },
"alt_boot_id": {
Type: schema.TypeInt,
Optional: true,
Description: "ID of CD-ROM live image to boot",
},
"started": { "started": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,

View File

@@ -43,6 +43,7 @@ import (
"github.com/hashicorp/go-cty/cty" "github.com/hashicorp/go-cty/cty"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -298,7 +299,13 @@ func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData
if needStart { if needStart {
computeId, _ := strconv.ParseUint(d.Id(), 10, 64) 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 apiErrCount += numErr
lastSavedError = err lastSavedError = err
} }
@@ -461,9 +468,12 @@ func utilityComputeStop(ctx context.Context, computeID uint64, m interface{}) er
return nil 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) c := m.(*controller.ControllerCfg)
startReq := compute.StartRequest{ComputeID: computeID} startReq := compute.StartRequest{ComputeID: computeID}
if altBootID > 0 {
startReq.AltBootID = altBootID
}
log.Debugf("utilityComputeNetworksConfigure: starting compute %d", computeID) log.Debugf("utilityComputeNetworksConfigure: starting compute %d", computeID)
_, err := c.CloudAPI().Compute().Start(ctx, startReq) _, err := c.CloudAPI().Compute().Start(ctx, startReq)
@@ -628,3 +638,84 @@ func enabledNetwork(rawNetworkConfig cty.Value, netID uint64, netType string) bo
return false return false
} }
func getComputeDiskIDsAPI(disksList compute.ListComputeDisks, disksBlocks, extraDisks []interface{}, bootDiskId uint64) []interface{} {
res := make([]interface{}, 0)
if len(disksBlocks) == 0 {
return res
}
sort.Slice(disksList, func(i, j int) bool {
return disksList[i].ID < disksList[j].ID
})
for _, disk := range disksList {
if disk.ID == bootDiskId || findInExtraDisks(uint(disk.ID), extraDisks) {
continue
}
res = append(res, disk.ID)
}
return res
}
func utilityComputeCreateIOTune(ctx context.Context, d *schema.ResourceData, m interface{}) error {
c := m.(*controller.ControllerCfg)
diskList := d.Get("disks").([]interface{})
iotuneArr := make([]interface{}, 0, len(diskList))
hasAny := false
for _, elem := range diskList {
diskVal := elem.(map[string]interface{})
iotune := diskVal["iotune"].([]interface{})
iotuneArr = append(iotuneArr, iotune)
if len(iotune) > 0 {
hasAny = true
}
}
if !hasAny {
return nil
}
computeRec, err := utilityComputeCheckPresence(ctx, d, m)
if err != nil {
return err
}
bootDisk := findBootDisk(computeRec.Disks)
computeDisksIDs := getComputeDiskIDsAPI(computeRec.Disks, diskList, d.Get("extra_disks").(*schema.Set).List(), bootDisk.ID)
for i, diskID := range computeDisksIDs {
if i >= len(iotuneArr) {
continue
}
iotune, ok := iotuneArr[i].([]interface{})
if !ok || len(iotune) == 0 {
continue
}
iotuneMap := iotune[0].(map[string]interface{})
req := disks.LimitIORequest{
DiskID: diskID.(uint64),
ReadBytesSec: uint64(iotuneMap["read_bytes_sec"].(int)),
ReadBytesSecMax: uint64(iotuneMap["read_bytes_sec_max"].(int)),
ReadIOPSSec: uint64(iotuneMap["read_iops_sec"].(int)),
ReadIOPSSecMax: uint64(iotuneMap["read_iops_sec_max"].(int)),
SizeIOPSSec: uint64(iotuneMap["size_iops_sec"].(int)),
TotalBytesSec: uint64(iotuneMap["total_bytes_sec"].(int)),
TotalBytesSecMax: uint64(iotuneMap["total_bytes_sec_max"].(int)),
TotalIOPSSec: uint64(iotuneMap["total_iops_sec"].(int)),
TotalIOPSSecMax: uint64(iotuneMap["total_iops_sec_max"].(int)),
WriteBytesSec: uint64(iotuneMap["write_bytes_sec"].(int)),
WriteBytesSecMax: uint64(iotuneMap["write_bytes_sec_max"].(int)),
WriteIOPSSec: uint64(iotuneMap["write_iops_sec"].(int)),
WriteIOPSSecMax: uint64(iotuneMap["write_iops_sec_max"].(int)),
}
_, err := c.CloudAPI().Disks().LimitIO(ctx, req)
if err != nil {
return err
}
}
return nil
}

View File

@@ -68,6 +68,34 @@ func flattenFlipgroup(d *schema.ResourceData, flip *flipgroup.RecordFLIPGroup) {
d.Set("updated_time", flip.UpdatedTime) 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("status", flip.Status)
d.Set("updated_by", flip.UpdatedBy)
d.Set("updated_time", flip.UpdatedTime)
}
func flattenFlipgroupsList(fg *flipgroup.ListFLIPGroups) []map[string]interface{} { func flattenFlipgroupsList(fg *flipgroup.ListFLIPGroups) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(fg.Data)) res := make([]map[string]interface{}, 0, len(fg.Data))
for _, flip := range fg.Data { for _, flip := range fg.Data {

View File

@@ -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.") 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", log.Debugf("resourceFlipgroupRead: after flattenFlipgroup: flipgroup_id %s, name %s",
d.Id(), d.Get("name").(string)) d.Id(), d.Get("name").(string))

View File

@@ -289,6 +289,7 @@ func flattenComputeDisks(disksList compute.ListDisks, disksBlocks, extraDisks []
"update_time": disk.UpdatedTime, "update_time": disk.UpdatedTime,
"cache": disk.Cache, "cache": disk.Cache,
"blk_discard": disk.BLKDiscard, "blk_discard": disk.BLKDiscard,
"iotune": flattenIOTune(disk.IOTune),
} }
res = append(res, temp) res = append(res, temp)
indexDataDisks++ indexDataDisks++

View File

@@ -17,9 +17,11 @@ func checkParamsExistence(ctx context.Context, d *schema.ResourceData, c *contro
errs = append(errs, err) errs = append(errs, err)
} }
if !d.Get("create_blank").(bool) {
if err := ic.ExistImage(ctx, uint64(d.Get("image_id").(int)), c); err != nil { if err := ic.ExistImage(ctx, uint64(d.Get("image_id").(int)), c); err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
}
if netErrs := existNetworks(ctx, d, c); errs != nil { if netErrs := existNetworks(ctx, d, c); errs != nil {
errs = append(errs, netErrs...) errs = append(errs, netErrs...)

View File

@@ -251,7 +251,32 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
} }
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86") 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 { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
} }
@@ -448,6 +473,9 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
if nodeID, ok := d.GetOk("node_id"); ok { if nodeID, ok := d.GetOk("node_id"); ok {
req.NodeID = uint64(nodeID.(int)) req.NodeID = uint64(nodeID.(int))
} }
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) log.Debugf("resourceComputeCreate: starting Compute ID %d after completing its resource configuration", computeId)
if _, err := c.CloudBroker().Compute().Start(ctx, req); err != nil { if _, err := c.CloudBroker().Compute().Start(ctx, req); err != nil {
warnings.Add(err) warnings.Add(err)
@@ -677,6 +705,9 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
if err != nil { if err != nil {
warnings.Add(err) warnings.Add(err)
} }
if err := utilityComputeCreateIOTune(ctx, d, m); err != nil {
warnings.Add(err)
}
} }
if readOnly, ok := d.GetOk("read_only"); ok { if readOnly, ok := d.GetOk("read_only"); ok {

View File

@@ -3409,6 +3409,12 @@ func resourceComputeSchemaMake() map[string]*schema.Schema {
Optional: true, Optional: true,
Default: false, Default: false,
}, },
"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": { "boot_disk_size": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
@@ -3759,8 +3765,6 @@ func resourceComputeSchemaMake() map[string]*schema.Schema {
"disk_type": { "disk_type": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, 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'", Description: "The type of disk in terms of its role in compute: 'B=Boot, D=Data'",
}, },
"pool": { "pool": {
@@ -3793,6 +3797,81 @@ func resourceComputeSchemaMake() map[string]*schema.Schema {
Optional: true, Optional: true,
Description: "Disk deletion status", Description: "Disk deletion status",
}, },
"iotune": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"read_bytes_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"read_bytes_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"read_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"read_iops_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"size_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_bytes_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_bytes_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"total_iops_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_bytes_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_bytes_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_iops_sec": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"write_iops_sec_max": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
},
},
},
"disk_id": { "disk_id": {
Type: schema.TypeInt, Type: schema.TypeInt,
Computed: true, Computed: true,

View File

@@ -209,7 +209,11 @@ func utilityComputeResize(ctx context.Context, d *schema.ResourceData, m interfa
} }
if isStopRequired { 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 return err
} }
} }
@@ -262,6 +266,7 @@ func utilityComputeUpdateDisks(ctx context.Context, d *schema.ResourceData, m in
changeStoragePolicyDisks := make([]interface{}, 0) changeStoragePolicyDisks := make([]interface{}, 0)
cacheUpdatedDisks := make([]interface{}, 0) cacheUpdatedDisks := make([]interface{}, 0)
blkDiscardUpdatedDisks := make([]interface{}, 0) blkDiscardUpdatedDisks := make([]interface{}, 0)
iotuneUpdatedDisks := make([]interface{}, 0)
migratedDisks := make([]interface{}, 0) migratedDisks := make([]interface{}, 0)
presentNewDisks := make([]interface{}, 0) presentNewDisks := make([]interface{}, 0)
presentOldDisks := make([]interface{}, 0) presentOldDisks := make([]interface{}, 0)
@@ -320,6 +325,10 @@ func utilityComputeUpdateDisks(ctx context.Context, d *schema.ResourceData, m in
if isChangeBLKDiscardDisk(oldConv, el) { if isChangeBLKDiscardDisk(oldConv, el) {
blkDiscardUpdatedDisks = append(blkDiscardUpdatedDisks, el) blkDiscardUpdatedDisks = append(blkDiscardUpdatedDisks, el)
} }
if isChangeIOTuneDisk(oldConv, el) {
iotuneUpdatedDisks = append(iotuneUpdatedDisks, el)
}
} }
if len(deletedDisks) > 0 { if len(deletedDisks) > 0 {
@@ -357,9 +366,6 @@ func utilityComputeUpdateDisks(ctx context.Context, d *schema.ResourceData, m in
if diskConv["sep_id"].(int) != 0 { if diskConv["sep_id"].(int) != 0 {
req.SepID = uint64(diskConv["sep_id"].(int)) req.SepID = uint64(diskConv["sep_id"].(int))
} }
if diskConv["disk_type"].(string) != "" {
req.DiskType = diskConv["disk_type"].(string)
}
if diskConv["pool"].(string) != "" { if diskConv["pool"].(string) != "" {
req.Pool = diskConv["pool"].(string) req.Pool = diskConv["pool"].(string)
} }
@@ -393,10 +399,31 @@ func utilityComputeUpdateDisks(ctx context.Context, d *schema.ResourceData, m in
} }
} }
} }
if iotuneRaw, ok := diskConv["iotune"].([]interface{}); ok && len(iotuneRaw) > 0 {
iotuneMap := iotuneRaw[0].(map[string]interface{})
limitReq := disks.LimitIORequest{
DiskID: diskID,
ReadBytesSec: uint64(iotuneMap["read_bytes_sec"].(int)),
ReadBytesSecMax: uint64(iotuneMap["read_bytes_sec_max"].(int)),
ReadIOPSSec: uint64(iotuneMap["read_iops_sec"].(int)),
ReadIOPSSecMax: uint64(iotuneMap["read_iops_sec_max"].(int)),
SizeIOPSSec: uint64(iotuneMap["size_iops_sec"].(int)),
TotalBytesSec: uint64(iotuneMap["total_bytes_sec"].(int)),
TotalBytesSecMax: uint64(iotuneMap["total_bytes_sec_max"].(int)),
TotalIOPSSec: uint64(iotuneMap["total_iops_sec"].(int)),
TotalIOPSSecMax: uint64(iotuneMap["total_iops_sec_max"].(int)),
WriteBytesSec: uint64(iotuneMap["write_bytes_sec"].(int)),
WriteBytesSecMax: uint64(iotuneMap["write_bytes_sec_max"].(int)),
WriteIOPSSec: uint64(iotuneMap["write_iops_sec"].(int)),
WriteIOPSSecMax: uint64(iotuneMap["write_iops_sec_max"].(int)),
}
_, err := c.CloudBroker().Disks().LimitIO(ctx, limitReq)
if err != nil { if err != nil {
return err return err
} }
} }
}
} }
if len(resizedDisks) > 0 { if len(resizedDisks) > 0 {
@@ -495,6 +522,44 @@ func utilityComputeUpdateDisks(ctx context.Context, d *schema.ResourceData, m in
} }
} }
if len(iotuneUpdatedDisks) > 0 {
for _, disk := range iotuneUpdatedDisks {
diskConv := disk.(map[string]interface{})
if diskConv["disk_type"].(string) == "B" {
continue
}
diskID := uint64(diskConv["disk_id"].(int))
if diskID == 0 {
continue
}
iotuneRaw, ok := diskConv["iotune"].([]interface{})
if !ok || len(iotuneRaw) == 0 {
continue
}
iotuneMap := iotuneRaw[0].(map[string]interface{})
req := disks.LimitIORequest{
DiskID: diskID,
ReadBytesSec: uint64(iotuneMap["read_bytes_sec"].(int)),
ReadBytesSecMax: uint64(iotuneMap["read_bytes_sec_max"].(int)),
ReadIOPSSec: uint64(iotuneMap["read_iops_sec"].(int)),
ReadIOPSSecMax: uint64(iotuneMap["read_iops_sec_max"].(int)),
SizeIOPSSec: uint64(iotuneMap["size_iops_sec"].(int)),
TotalBytesSec: uint64(iotuneMap["total_bytes_sec"].(int)),
TotalBytesSecMax: uint64(iotuneMap["total_bytes_sec_max"].(int)),
TotalIOPSSec: uint64(iotuneMap["total_iops_sec"].(int)),
TotalIOPSSecMax: uint64(iotuneMap["total_iops_sec_max"].(int)),
WriteBytesSec: uint64(iotuneMap["write_bytes_sec"].(int)),
WriteBytesSecMax: uint64(iotuneMap["write_bytes_sec_max"].(int)),
WriteIOPSSec: uint64(iotuneMap["write_iops_sec"].(int)),
WriteIOPSSecMax: uint64(iotuneMap["write_iops_sec_max"].(int)),
}
_, err := c.CloudBroker().Disks().LimitIO(ctx, req)
if err != nil {
return err
}
}
}
if len(migratedDisks) > 0 { if len(migratedDisks) > 0 {
if err := utilityComputeMigrateDisks(ctx, d, m, migratedDisks, oldConv); err != nil { if err := utilityComputeMigrateDisks(ctx, d, m, migratedDisks, oldConv); err != nil {
return err return err
@@ -917,7 +982,13 @@ func utilityComputeNetworksConfigure(ctx context.Context, d *schema.ResourceData
if needStart { if needStart {
computeId, _ := strconv.ParseUint(d.Id(), 10, 64) 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, altBootID, computeId, m); err != nil {
apiErrCount += numErr apiErrCount += numErr
lastSavedError = err lastSavedError = err
} }
@@ -1244,7 +1315,11 @@ func utilityComputeUpdate(ctx context.Context, d *schema.ResourceData, m interfa
// If used to be STARTED, we need to start it after update // If used to be STARTED, we need to start it after update
if isStopRequired { 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 return err
} }
} }
@@ -1715,6 +1790,9 @@ func utilityComputeRollback(ctx context.Context, d *schema.ResourceData, m inter
} }
startReq := compute.StartRequest{ComputeID: computeId} 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) log.Debugf("utilityComputeRollback: starting compute %d", computeId)
@@ -1972,10 +2050,14 @@ func utilityComputeStop(ctx context.Context, d *schema.ResourceData, m interface
return nil 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) c := m.(*controller.ControllerCfg)
startReq := compute.StartRequest{ComputeID: computeID} startReq := compute.StartRequest{ComputeID: computeID}
if altBootID > 0 {
startReq.AltBootID = altBootID
}
log.Debugf("utilityComputeStart: starting compute %d", computeID) log.Debugf("utilityComputeStart: starting compute %d", computeID)
_, err := c.CloudBroker().Compute().Start(ctx, startReq) _, err := c.CloudBroker().Compute().Start(ctx, startReq)
if err != nil { if err != nil {
@@ -2077,6 +2159,100 @@ func isChangeBLKDiscardDisk(els []interface{}, el interface{}) bool {
return false return false
} }
func isChangeIOTuneDisk(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) {
continue
}
oldIOTune := elOldConv["iotune"].([]interface{})
newIOTune := elConv["iotune"].([]interface{})
if len(oldIOTune) == 0 && len(newIOTune) == 0 {
return false
}
if len(oldIOTune) == 0 || len(newIOTune) == 0 {
return true
}
oldMap := oldIOTune[0].(map[string]interface{})
newMap := newIOTune[0].(map[string]interface{})
return oldMap["read_bytes_sec"].(int) != newMap["read_bytes_sec"].(int) ||
oldMap["read_bytes_sec_max"].(int) != newMap["read_bytes_sec_max"].(int) ||
oldMap["read_iops_sec"].(int) != newMap["read_iops_sec"].(int) ||
oldMap["read_iops_sec_max"].(int) != newMap["read_iops_sec_max"].(int) ||
oldMap["size_iops_sec"].(int) != newMap["size_iops_sec"].(int) ||
oldMap["total_bytes_sec"].(int) != newMap["total_bytes_sec"].(int) ||
oldMap["total_bytes_sec_max"].(int) != newMap["total_bytes_sec_max"].(int) ||
oldMap["total_iops_sec"].(int) != newMap["total_iops_sec"].(int) ||
oldMap["total_iops_sec_max"].(int) != newMap["total_iops_sec_max"].(int) ||
oldMap["write_bytes_sec"].(int) != newMap["write_bytes_sec"].(int) ||
oldMap["write_bytes_sec_max"].(int) != newMap["write_bytes_sec_max"].(int) ||
oldMap["write_iops_sec"].(int) != newMap["write_iops_sec"].(int) ||
oldMap["write_iops_sec_max"].(int) != newMap["write_iops_sec_max"].(int)
}
return false
}
func utilityComputeCreateIOTune(ctx context.Context, d *schema.ResourceData, m interface{}) error {
c := m.(*controller.ControllerCfg)
diskList := d.Get("disks").([]interface{})
iotuneArr := make([]interface{}, 0, len(diskList))
hasAny := false
for _, elem := range diskList {
diskVal := elem.(map[string]interface{})
iotune := diskVal["iotune"].([]interface{})
iotuneArr = append(iotuneArr, iotune)
if len(iotune) > 0 {
hasAny = true
}
}
if !hasAny {
return nil
}
computeRec, err := utilityComputeCheckPresence(ctx, d, m)
if err != nil {
return err
}
bootDisk := findBootDisk(computeRec.Disks)
computeDisksIDs := getComputeDiskIDs(computeRec.Disks, diskList, d.Get("extra_disks").(*schema.Set).List(), bootDisk.ID)
for i, diskID := range computeDisksIDs {
if i >= len(iotuneArr) {
continue
}
iotune, ok := iotuneArr[i].([]interface{})
if !ok || len(iotune) == 0 {
continue
}
iotuneMap := iotune[0].(map[string]interface{})
req := disks.LimitIORequest{
DiskID: diskID.(uint64),
ReadBytesSec: uint64(iotuneMap["read_bytes_sec"].(int)),
ReadBytesSecMax: uint64(iotuneMap["read_bytes_sec_max"].(int)),
ReadIOPSSec: uint64(iotuneMap["read_iops_sec"].(int)),
ReadIOPSSecMax: uint64(iotuneMap["read_iops_sec_max"].(int)),
SizeIOPSSec: uint64(iotuneMap["size_iops_sec"].(int)),
TotalBytesSec: uint64(iotuneMap["total_bytes_sec"].(int)),
TotalBytesSecMax: uint64(iotuneMap["total_bytes_sec_max"].(int)),
TotalIOPSSec: uint64(iotuneMap["total_iops_sec"].(int)),
TotalIOPSSecMax: uint64(iotuneMap["total_iops_sec_max"].(int)),
WriteBytesSec: uint64(iotuneMap["write_bytes_sec"].(int)),
WriteBytesSecMax: uint64(iotuneMap["write_bytes_sec_max"].(int)),
WriteIOPSSec: uint64(iotuneMap["write_iops_sec"].(int)),
WriteIOPSSecMax: uint64(iotuneMap["write_iops_sec_max"].(int)),
}
_, err := c.CloudBroker().Disks().LimitIO(ctx, req)
if err != nil {
return err
}
}
return nil
}
func isChangeStoragePolicy(els []interface{}, el interface{}) bool { func isChangeStoragePolicy(els []interface{}, el interface{}) bool {
for _, elOld := range els { for _, elOld := range els {
elOldConv := elOld.(map[string]interface{}) elOldConv := elOld.(map[string]interface{})

View File

@@ -15,11 +15,11 @@ func flattenTrunkResource(d *schema.ResourceData, details *trunk.ItemTrunk) {
d.Set("name", details.Name) d.Set("name", details.Name)
d.Set("mac", details.MAC) d.Set("mac", details.MAC)
d.Set("description", details.Description) d.Set("description", details.Description)
d.Set("accountIds", details.AccountIDs) d.Set("account_ids", details.AccountIDs)
d.Set("ovsBridge", details.OVSBridge) d.Set("ovs_bridge", details.OVSBridge)
d.Set("nativeVlanId", details.NativeVLANID) d.Set("native_vlan_id", details.NativeVLANID)
d.Set("status", details.Status) 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_at", details.CreatedAt)
d.Set("created_by", details.CreatedBy) d.Set("created_by", details.CreatedBy)
d.Set("updated_at", details.UpdatedAt) d.Set("updated_at", details.UpdatedAt)

View File

@@ -33,6 +33,7 @@ package vfpool
import ( import (
"context" "context"
"fmt"
"strconv" "strconv"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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") 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 { if configOk {
configArray := config.(*schema.Set).List() configArray := config.(*schema.Set).List()
req.Config = make([]vfpool.Config, 0, len(configArray)) req.Config = make([]vfpool.Config, 0, len(configArray))
@@ -117,11 +124,9 @@ func resourceVFPoolCreate(ctx context.Context, d *schema.ResourceData, m interfa
warnings := dc.Warnings{} warnings := dc.Warnings{}
if enable, ok := d.GetOk("enable"); ok { if err := utilityVFPoolEnabled(ctx, m, enableVal, vfPoolID); err != nil {
if err := utilityVFPoolEnabled(ctx, m, enable.(bool), vfPoolID, configOk); err != nil {
warnings.Add(err) warnings.Add(err)
} }
}
log.Debugf("resourceVFPoolCreate: create VFPool with ID: %d, complete", vfPoolID) log.Debugf("resourceVFPoolCreate: create VFPool with ID: %d, complete", vfPoolID)
return append(resourceVFPoolRead(ctx, d, m), warnings.Get()...) return append(resourceVFPoolRead(ctx, d, m), warnings.Get()...)
@@ -147,20 +152,12 @@ func resourceVFPoolUpdate(ctx context.Context, d *schema.ResourceData, m interfa
log.Debugf("resourceVFPoolUpdate: called VFPool with id %d", vfPoolID) log.Debugf("resourceVFPoolUpdate: called VFPool with id %d", vfPoolID)
_, ok := d.GetOk("config") if d.HasChanges("name", "description", "account_access", "rg_access", "config", "enable") {
if d.HasChanges("name,", "description", "account_access", "rg_access,", "config") {
if err := utilityVFPoolUpdate(ctx, d, m, vfPoolID); err != nil { if err := utilityVFPoolUpdate(ctx, d, m, vfPoolID); err != nil {
return diag.FromErr(err) 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) log.Debugf("resourceVFPoolUpdate: update VFPool with id %d, complete", vfPoolID)
return resourceVFPoolRead(ctx, d, m) return resourceVFPoolRead(ctx, d, m)

View File

@@ -64,37 +64,26 @@ func utilityVFpoolCheckPresence(ctx context.Context, d *schema.ResourceData, m i
return vfpoolData, nil 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) c := m.(*controller.ControllerCfg)
if enable && configOk { var err error
req := vfpool.EnableRequest{
VFPoolID: vfPoolID, if enable {
} _, err = c.CloudBroker().VFPool().Enable(ctx, vfpool.EnableRequest{VFPoolID: vfPoolID})
_, err := c.CloudBroker().VFPool().Enable(ctx, req) } else {
if err != nil { _, err = c.CloudBroker().VFPool().Disable(ctx, vfpool.DisableRequest{VFPoolID: vfPoolID})
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
}
} }
log.Debugf("utilityVFPoolEnabled: enable=%v vfPool ID %d after completing its resource configuration", enable, vfPoolID) return err
return nil
} }
func utilityVFPoolUpdate(ctx context.Context, d *schema.ResourceData, m interface{}, vfPoolID uint64) error { 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) c := m.(*controller.ControllerCfg)
vfPool, err := utilityVFpoolCheckPresence(ctx, d, m) 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) 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{ reqEnable := vfpool.EnableRequest{
VFPoolID: vfPoolID, VFPoolID: vfPoolID,
} }
@@ -201,8 +190,6 @@ func utilityVFPoolUpdate(ctx context.Context, d *schema.ResourceData, m interfac
return err return err
} }
log.Debugf("utilityVFPoolUpdate: enable vfPool with ID: %d, complete", vfPoolID) 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 return nil

View File

@@ -37,3 +37,4 @@ func DataSourceAccessGroupList() *schema.Resource {
Schema: dataSourceAccessGroupListSchemaMake(), Schema: dataSourceAccessGroupListSchemaMake(),
} }
} }

View File

@@ -49,3 +49,4 @@ func utilityAccessGroupListCheckPresence(ctx context.Context, d *schema.Resource
return accessGroupList, nil return accessGroupList, nil
} }

View File

@@ -37,3 +37,4 @@ func DataSourceDefaultSecurityPolicyList() *schema.Resource {
Schema: dataSourceDefaultSecurityPolicyListSchemaMake(), Schema: dataSourceDefaultSecurityPolicyListSchemaMake(),
} }
} }

View File

@@ -366,3 +366,4 @@ func dataSourceDefaultSecurityPolicyListSchemaMake() map[string]*schema.Schema {
return res return res
} }

View File

@@ -37,3 +37,4 @@ func utilityDefaultSecurityPolicyListCheckPresence(ctx context.Context, d *schem
return defaultSecurityPolicyList, nil return defaultSecurityPolicyList, nil
} }

View File

@@ -105,6 +105,12 @@ resource "decort_kvmvm" "comp" {
#используется при создании и обновлении #используется при создании и обновлении
#image_id = 111 #image_id = 111
#создание без образа ОС
#опциональный параметр
#тип - булев
#используется при создании
#create_blank = false
#создание без загрузочного диска в остановленном состоянии #создание без загрузочного диска в остановленном состоянии
#опциональный параметр #опциональный параметр
#если значение равно True, параметры image_id, boot_disk_size, sep_id, pool игнорируются #если значение равно True, параметры image_id, boot_disk_size, sep_id, pool игнорируются
@@ -120,6 +126,12 @@ resource "decort_kvmvm" "comp" {
#используется при создании и обновлении #используется при создании и обновлении
#numa_affinity = "loose" #numa_affinity = "loose"
#id образа CD-ROM для загрузки
#опциональный параметр
#тип - целое число
#используется при создании и обновлении
#alt_boot_id = 1
#необходимость запускать ВМ на выделенных CPU ядрах #необходимость запускать ВМ на выделенных CPU ядрах
#опциональный параметр #опциональный параметр
#по умолчанию - false #по умолчанию - false
@@ -189,6 +201,25 @@ resource "decort_kvmvm" "comp" {
#опциональный параметр #опциональный параметр
#тип - булев #тип - булев
#permanently = false #permanently = false
#блок для управления IO-лимитами диска
#опциональный параметр
#тип - блок
#iotune {
#read_bytes_sec = 0
#read_bytes_sec_max = 0
#read_iops_sec = 0
#read_iops_sec_max = 0
#size_iops_sec = 0
#total_bytes_sec = 0
#total_bytes_sec_max = 0
#total_iops_sec = 3000
#total_iops_sec_max = 0
#write_bytes_sec = 0
#write_bytes_sec_max = 0
#write_iops_sec = 0
#write_iops_sec_max = 0
#}
#} #}
#правила affinity #правила affinity

View File

@@ -83,6 +83,12 @@ resource "decort_cb_kvmvm" "comp" {
#используется при создании #используется при создании
#without_boot_disk = true #without_boot_disk = true
#создание без образа ОС
#опциональный параметр
#тип - булев
#используется при создании
#create_blank = false
#размер загрузочного диска #размер загрузочного диска
#опциональный параметр #опциональный параметр
#тип - целое число #тип - целое число
@@ -130,7 +136,7 @@ resource "decort_cb_kvmvm" "comp" {
#id образа CD-ROM для загрузки #id образа CD-ROM для загрузки
#опциональный параметр #опциональный параметр
#тип - целое число #тип - целое число
#используется при обновлении, при повторном старте вм #используется при создании и обновлении
#alt_boot_id = 1 #alt_boot_id = 1
#необходимость выравнивать ВМ по NUMA #необходимость выравнивать ВМ по NUMA
@@ -229,6 +235,25 @@ resource "decort_cb_kvmvm" "comp" {
#тип - булев #тип - булев
#по умолчанию - false #по умолчанию - false
#blk_discard = false #blk_discard = false
#блок для управления IO-лимитами диска
#опциональный параметр
#тип - блок
#iotune {
#read_bytes_sec = 0
#read_bytes_sec_max = 0
#read_iops_sec = 0
#read_iops_sec_max = 0
#size_iops_sec = 0
#total_bytes_sec = 0
#total_bytes_sec_max = 0
#total_iops_sec = 3000
#total_iops_sec_max = 0
#write_bytes_sec = 0
#write_bytes_sec_max = 0
#write_iops_sec = 0
#write_iops_sec_max = 0
#}
#} #}
#правила affinity #правила affinity