main 4.8.0
parent de8857b1d5
commit dc39a6412e

3
.gitignore vendored

@ -4,4 +4,5 @@ url_scrapping/
terraform-provider-decort*
.vscode/
.DS_Store
vendor/
.idea/

@ -1,16 +1,54 @@
## Version 4.7.3
## Version 4.8.0
### Добавлено
#### extnet
| Идентификатор<br>задачи | Описание |
| --- | --- |
| BATF-656 | Вычисляемое поле `account_id` в блоке `reservations` в resource `decort_cb_extnet` и data sources `decort_extnet, decort_cb_extnet` в cloudapi/extnet и cloudbroker/extnet |
| BATF-658 | Data sources `decort_extnet_reserved_ip_list, decort_cb_extnet_reserved_ip_list` в cloudapi/extnet и cloudbroker/extnet |
| BATF-658 | Опциональный блок `reserved_ip`в resource `decort_cb_extnet` в cloudbroker/extnet |
#### image
| Идентификатор<br>задачи | Описание |
| --- | --- |
| BATF-667 | Вычисляемое поле `snapshot_id` в resources `decort_cb_image, decort_cb_image_from_blank_compute, decort_cb_image_from_platform_disk, decort_cb_virtual_image, decort_cb_cdrom_image` и data sources `decort_cb_image, decort_cb_image_list` в cloudbroker/image |
#### grid
| Идентификатор<br>задачи | Описание |
| --- | --- |
| BATF-669 | Обязательно поле `file_path` в data source `decort_cb_grid_post_diagnosis` в cloudbroker/grid |
#### kvmvm
| Идентификатор<br>задачи | Описание |
| --- | --- |
| BATF-648 | Обязательные поля `net_type, net_id` в опциональный блок `libvirt_settings` в resource `decort_cb_kvmvm` в cloudbroker/kvmvm |
| BATF-648 | Опциональное поле `mtu` в опциональный блок `network` в resources `decort_cb_kvmvm, decort_kvmvm` в cloudbroker/kvmvm и cloudapi/kvmvm |
| BATF-656 | Вычисляемое поле `vnc_password` в resources `decort_kvmvm, decort_cb_kvmvm` и data sources `decort_kvmvm, decort_cb_kvmvm` в cloudapi/kvmvm и cloudbroker/kvmvm |
| BATF-656 | Опциональное поле `cd_image_id`в data_source `decort_cb_kvmvm_list` в cloudbroker/kvmvm |
| BATF-666 | Опциональное поле `auto_start_w_node`в resources `decort_kvmvm, decort_cb_kvmvm` в cloudapi/kvmvm и cloudbroker/kvmvm |
| BATF-666 | Вычисляемое поле `auto_start_w_node`в data_sources `decort_kvmvm, decort_kvmvm_list, decort_kvmvm_list_deleted, decort_cb_kvmvm, decort_cb_kvmvm_list, decort_cb_kvmvm_list_deleted ` в cloudapi/kvmvm и cloudbroker/kvmvm |
#### node
| Идентификатор<br>задачи | Описание |
| --- | --- |
| BATF-663 | Вычисляемый блок `net_addr` в data source `decort_cb_node` в cloudbroker/node |
#### vins
| Идентификатор<br>задачи | Описание |
| --- | --- |
| BATF-656 | Вычисляемое поле `vnc_password` в блоке `vnf_dev` в resources `decort_vins, decort_cb_vins` и data sources `decort_vins, decort_cb_vins` в cloudapi/vins и cloudbroker/vins |
| BATF-656 | Вычисляемое поле `account_id` в блоке `reservations` в resource `decort_vins` и data source `decort_vins` в cloudapi/vins |
### Удалено
#### kvmvm
#### grid
| Идентификатор<br>задачи | Описание |
| --- | --- |
| BATF-669 | Data source `decort_cb_grid_post_diagnosis` в cloudbroker/grid |
| BATF-669 | Вычисляемое поле `diagnosis` в data source `decort_cb_grid_get_diagnosis` в cloudbroker/grid |
#### vins
| Идентификатор<br>задачи | Описание |
| --- | --- |
| BATF-648 | Обязательное поле `mac` в опциональном блок `libvirt_settings` в resource `decort_cb_kvmvm` в cloudbroker/kvmvm |
| BATF-656 | Вычисляемые поля `client_type, description, domain_name, hostname` в блоке `reservations` в resources `decort_vins, decort_cb_vins` и data sources `decort_vins, decort_cb_vins` в cloudapi/vins и cloudbroker/vins |
| BATF-656 | Опциональное поле `compute_ids` в resources `decort_vins_static_route, decort_cb_vins_static_route` в cloudapi/vins и cloudbroker/vins |

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

@ -6,6 +6,7 @@ Terraform provider для платформы Digital Energy Cloud Orchestration
| Версия DECORT API | Версия провайдера Terraform |
| ------ | ------ |
| 4.2.0 | 4.8.x |
| 4.1.0 | 4.7.x |
| 4.0.0 | 4.6.x |
| 3.8.9 | 4.5.x |

@ -93,6 +93,7 @@ Read-Only:
Read-Only:
- `account_id` (Number)
- `client_type` (String)
- `desc` (String)
- `domain_name` (String)

@ -0,0 +1,61 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_cb_extnet_reserved_ip_list Data Source - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_cb_extnet_reserved_ip_list (Data Source)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `account_id` (Number)
### Optional
- `extnet_id` (Number)
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- `id` (String) The ID of this resource.
- `items` (List of Object) (see [below for nested schema](#nestedatt--items))
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- `default` (String)
- `read` (String)
<a id="nestedatt--items"></a>
### Nested Schema for `items`
Read-Only:
- `extnet_id` (Number)
- `reservations` (List of Object) (see [below for nested schema](#nestedobjatt--items--reservations))
<a id="nestedobjatt--items--reservations"></a>
### Nested Schema for `items.reservations`
Read-Only:
- `account_id` (Number)
- `client_type` (String)
- `domain_name` (String)
- `hostname` (String)
- `ip` (String)
- `mac` (String)
- `type` (String)
- `vm_id` (Number)

@ -17,6 +17,7 @@ description: |-
### Required
- `file_path` (String)
- `gid` (Number)
### Optional
@ -25,7 +26,6 @@ description: |-
### Read-Only
- `diagnosis` (String)
- `id` (String) The ID of this resource.
<a id="nestedblock--timeouts"></a>

@ -1,37 +0,0 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_cb_grid_post_diagnosis Data Source - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_cb_grid_post_diagnosis (Data Source)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `gid` (Number)
### Optional
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- `diagnosis` (String)
- `id` (String) The ID of this resource.
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- `default` (String)
- `read` (String)

@ -59,6 +59,7 @@ description: |-
- `rescuecd` (Boolean)
- `sep_id` (Number) storage endpoint provider ID
- `size` (Number) image size
- `snapshot_id` (String) snapshot id
- `status` (String) status
- `tech_status` (String) tech atatus
- `unc_path` (String) unc path

@ -89,6 +89,7 @@ Read-Only:
- `sep_id` (Number)
- `shared_with` (List of Number)
- `size` (Number)
- `snapshot_id` (String)
- `status` (String)
- `tech_status` (String)
- `unc_path` (String)

@ -33,6 +33,7 @@ description: |-
- `affinity_weight` (Number)
- `anti_affinity_rules` (List of Object) (see [below for nested schema](#nestedatt--anti_affinity_rules))
- `arch` (String)
- `auto_start_w_node` (Boolean)
- `boot_disk_id` (Number)
- `boot_disk_size` (Number)
- `boot_order` (List of String)
@ -100,6 +101,7 @@ description: |-
- `vgpus` (List of Number)
- `virtual_image_id` (Number)
- `virtual_image_name` (String)
- `vnc_password` (String)
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`

@ -19,6 +19,7 @@ description: |-
- `account_id` (Number) Find by AccountID
- `by_id` (Number) Find by ID
- `cd_image_id` (Number) Find by CD image ID
- `extnet_id` (Number) Find by Extnet ID
- `extnet_name` (String) Find by Extnet name
- `ignore_k8s` (Boolean) If set to true, ignores any VMs associated with any k8s cluster
@ -64,6 +65,7 @@ Read-Only:
- `affinity_weight` (Number)
- `anti_affinity_rules` (List of Object) (see [below for nested schema](#nestedobjatt--items--anti_affinity_rules))
- `arch` (String)
- `auto_start_w_node` (Boolean)
- `boot_order` (List of String)
- `bootdisk_size` (Number)
- `cd_image_id` (Number)

@ -60,6 +60,7 @@ Read-Only:
- `affinity_weight` (Number)
- `anti_affinity_rules` (List of Object) (see [below for nested schema](#nestedobjatt--items--anti_affinity_rules))
- `arch` (String)
- `auto_start_w_node` (Boolean)
- `boot_order` (List of String)
- `bootdisk_size` (Number)
- `cd_image_id` (Number)

@ -34,6 +34,7 @@ description: |-
- `isolated_cpus` (List of String)
- `name` (String)
- `need_reboot` (Boolean)
- `net_addr` (List of Object) (see [below for nested schema](#nestedatt--net_addr))
- `nic_info` (List of Object) (see [below for nested schema](#nestedatt--nic_info))
- `numa_topology` (List of Object) (see [below for nested schema](#nestedatt--numa_topology))
- `reserved_cpus` (List of String)
@ -109,6 +110,15 @@ Read-Only:
- `phys_count` (Number)
<a id="nestedatt--net_addr"></a>
### Nested Schema for `net_addr`
Read-Only:
- `ip` (List of String)
- `name` (String)
<a id="nestedatt--nic_info"></a>
### Nested Schema for `nic_info`

@ -101,6 +101,7 @@ Read-Only:
- `tech_status` (String)
- `type` (String)
- `vins` (List of Number)
- `vnc_password` (String)
<a id="nestedobjatt--vnf_dev--config"></a>
### Nested Schema for `vnf_dev.config`

@ -90,6 +90,7 @@ Read-Only:
Read-Only:
- `account_id` (Number)
- `client_type` (String)
- `desc` (String)
- `domainname` (String)

@ -0,0 +1,61 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_extnet_reserved_ip_list Data Source - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_extnet_reserved_ip_list (Data Source)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `account_id` (Number)
### Optional
- `extnet_id` (Number)
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- `id` (String) The ID of this resource.
- `items` (List of Object) (see [below for nested schema](#nestedatt--items))
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- `default` (String)
- `read` (String)
<a id="nestedatt--items"></a>
### Nested Schema for `items`
Read-Only:
- `extnet_id` (Number)
- `reservations` (List of Object) (see [below for nested schema](#nestedobjatt--items--reservations))
<a id="nestedobjatt--items--reservations"></a>
### Nested Schema for `items.reservations`
Read-Only:
- `account_id` (Number)
- `client_type` (String)
- `domain_name` (String)
- `hostname` (String)
- `ip` (String)
- `mac` (String)
- `type` (String)
- `vm_id` (Number)

@ -33,6 +33,7 @@ description: |-
- `affinity_weight` (Number)
- `anti_affinity_rules` (List of Object) (see [below for nested schema](#nestedatt--anti_affinity_rules))
- `arch` (String)
- `auto_start_w_node` (Boolean)
- `boot_order` (List of String)
- `bootdisk_size` (Number)
- `cd_image_id` (Number)
@ -94,6 +95,7 @@ description: |-
- `vgpus` (List of Number)
- `virtual_image_id` (Number)
- `virtual_image_name` (String)
- `vnc_password` (String)
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`

@ -62,6 +62,7 @@ Read-Only:
- `affinity_weight` (Number)
- `anti_affinity_rules` (List of Object) (see [below for nested schema](#nestedobjatt--items--anti_affinity_rules))
- `arch` (String)
- `auto_start_w_node` (Boolean)
- `boot_order` (List of String)
- `bootdisk_size` (Number)
- `cd_image_id` (Number)

@ -60,6 +60,7 @@ Read-Only:
- `affinity_weight` (Number)
- `anti_affinity_rules` (List of Object) (see [below for nested schema](#nestedobjatt--items--anti_affinity_rules))
- `arch` (String)
- `auto_start_w_node` (Boolean)
- `boot_order` (List of String)
- `bootdisk_size` (Number)
- `cd_image_id` (Number)

@ -108,6 +108,7 @@ Read-Only:
- `tech_status` (String)
- `type` (String)
- `vins` (List of Number)
- `vnc_password` (String)
- `vnf_id` (Number)
- `vnf_name` (String)
@ -248,10 +249,7 @@ Read-Only:
Read-Only:
- `client_type` (String)
- `desc` (String)
- `domainname` (String)
- `hostname` (String)
- `account_id` (Number)
- `ip` (String)
- `mac` (String)
- `type` (String)

@ -62,6 +62,7 @@ description: |-
- `res_name` (String)
- `rescuecd` (Boolean)
- `size` (Number) image size
- `snapshot_id` (String) snapshot id
- `status` (String) status
- `tech_status` (String) tech atatus
- `unc_path` (String) unc path

@ -37,6 +37,7 @@ description: |-
- `ntp` (List of String) List of NTP addresses
- `ovs_bridge` (String) OpenvSwith bridge name for ExtNet connection
- `pre_reservations_num` (Number) Number of pre created reservations
- `reserved_ip` (Block Set) (see [below for nested schema](#nestedblock--reserved_ip))
- `restart` (Boolean) restart extnet vnf device
- `set_default` (Boolean) Set current extnet as default (can not be undone)
- `shared_with` (Set of Number)
@ -88,6 +89,19 @@ Required:
- `ip_start` (String)
<a id="nestedblock--reserved_ip"></a>
### Nested Schema for `reserved_ip`
Required:
- `account_id` (Number)
Optional:
- `ip_count` (Number)
- `ips` (Set of String)
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
@ -119,6 +133,7 @@ Read-Only:
Read-Only:
- `account_id` (Number)
- `client_type` (String)
- `desc` (String)
- `domain_name` (String)

@ -67,6 +67,7 @@ description: |-
- `res_name` (String)
- `rescuecd` (Boolean)
- `size` (Number) image size
- `snapshot_id` (String) snapshot id
- `status` (String) status
- `tech_status` (String) tech atatus
- `unc_path` (String) unc path

@ -64,6 +64,7 @@ description: |-
- `res_name` (String)
- `rescuecd` (Boolean)
- `size` (Number)
- `snapshot_id` (String) snapshot id
- `status` (String)
- `tech_status` (String)
- `unc_path` (String)

@ -64,6 +64,7 @@ description: |-
- `res_name` (String)
- `rescuecd` (Boolean)
- `size` (Number)
- `snapshot_id` (String) snapshot id
- `status` (String)
- `tech_status` (String)
- `unc_path` (String)

@ -30,6 +30,7 @@ description: |-
- `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` (Boolean) Flag for redeploy compute
- `auto_start_w_node` (Boolean)
- `boot_disk_size` (Number) This compute instance boot disk size in GB. Make sure it is large enough to accomodate selected OS image.
- `cd` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--cd))
- `chipset` (String) Type of the emulated system.
@ -128,6 +129,7 @@ description: |-
- `vgpus` (List of Number)
- `virtual_image_id` (Number)
- `virtual_image_name` (String)
- `vnc_password` (String)
<a id="nestedblock--affinity_rules"></a>
### Nested Schema for `affinity_rules`

@ -167,6 +167,7 @@ Read-Only:
- `tech_status` (String)
- `type` (String)
- `vins` (List of Number)
- `vnc_password` (String)
<a id="nestedobjatt--vnf_dev--config"></a>
### Nested Schema for `vnf_dev.config`

@ -24,11 +24,11 @@ description: |-
### Optional
- `compute_ids` (List of Number)
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- `compute_ids` (List of Number)
- `guid` (String)
- `id` (String) The ID of this resource.
- `route_id` (Number) Unique ID of the static route

@ -61,6 +61,7 @@ description: |-
- `rescuecd` (Boolean)
- `sep_id` (Number) storage endpoint provider ID
- `size` (Number) image size
- `snapshot_id` (String) snapshot id
- `status` (String) status
- `tech_status` (String) tech atatus
- `unc_path` (String) unc path

@ -29,6 +29,7 @@ description: |-
- `affinity_rules` (Block List) (see [below for nested schema](#nestedblock--affinity_rules))
- `anti_affinity_rules` (Block List) (see [below for nested schema](#nestedblock--anti_affinity_rules))
- `auto_start` (Boolean) Flag for redeploy compute
- `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.
- `cd` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--cd))
- `chipset` (String) Type of the emulated system.
@ -121,6 +122,7 @@ description: |-
- `vgpus` (List of Number)
- `virtual_image_id` (Number)
- `virtual_image_name` (String)
- `vnc_password` (String)
<a id="nestedblock--affinity_rules"></a>
### Nested Schema for `affinity_rules`

@ -163,6 +163,7 @@ Read-Only:
- `tech_status` (String)
- `type` (String)
- `vins` (List of Number)
- `vnc_password` (String)
- `vnf_id` (Number)
- `vnf_name` (String)
@ -303,10 +304,7 @@ Read-Only:
Read-Only:
- `client_type` (String)
- `desc` (String)
- `domainname` (String)
- `hostname` (String)
- `account_id` (Number)
- `ip` (String)
- `mac` (String)
- `type` (String)

@ -24,12 +24,12 @@ description: |-
### Optional
- `compute_ids` (List of Number)
- `route_id` (Number)
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- `compute_ids` (List of Number)
- `guid` (String)
- `id` (String) The ID of this resource.

@ -8,7 +8,7 @@ require (
github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0
github.com/sirupsen/logrus v1.9.0
golang.org/x/net v0.23.0
repository.basistech.ru/BASIS/decort-golang-sdk v1.9.2
repository.basistech.ru/BASIS/decort-golang-sdk v1.10.0
)
require (

@ -137,6 +137,7 @@ func newDataSourcesMap() map[string]*schema.Resource {
"decort_extnet_computes_list": extnet.DataSourceExtnetComputesList(),
"decort_extnet": extnet.DataSourceExtnet(),
"decort_extnet_default": extnet.DataSourceExtnetDefault(),
"decort_extnet_reserved_ip_list": extnet.DataSourceExtnetReservedIp(),
"decort_locations_list": locations.DataSourceLocationsList(),
"decort_location_url": locations.DataSourceLocationUrl(),
"decort_image_list": image.DataSourceImageList(),
@ -180,6 +181,7 @@ func newDataSourcesMap() map[string]*schema.Resource {
"decort_cb_extnet": cb_extnet.DataSourceExtnetCB(),
"decort_cb_extnet_list": cb_extnet.DataSourceExtnetListCB(),
"decort_cb_extnet_default": cb_extnet.DataSourceExtnetDefaultCB(),
"decort_cb_extnet_reserved_ip_list": cb_extnet.DataSourceExtnetReservedIp(),
"decort_cb_extnet_static_route_list": cb_extnet.DataSourceStaticRouteList(),
"decort_cb_extnet_static_route": cb_extnet.DataSourceStaticRoute(),
"decort_cb_image": cb_image.DataSourceImage(),
@ -187,7 +189,6 @@ func newDataSourcesMap() map[string]*schema.Resource {
"decort_cb_grid_get_status": cb_grid.DataSourceGridGetStatus(),
"decort_cb_grid_post_status": cb_grid.DataSourceGridPostStatus(),
"decort_cb_grid_get_diagnosis": cb_grid.DataSourceGridGetDiagnosis(),
"decort_cb_grid_post_diagnosis": cb_grid.DataSourceGridPostDiagnosis(),
"decort_cb_grid_get_settings": cb_grid.DataSourceGridGetSettings(),
"decort_cb_grid_list": cb_grid.DataSourceGridList(),
"decort_cb_grid_list_emails": cb_grid.DataSourceGridListEmails(),

@ -204,6 +204,10 @@ func dataSourceExtnetSchemaMake() map[string]*schema.Schema {
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Computed: true,
},
"client_type": {
Type: schema.TypeString,
Computed: true,

@ -0,0 +1,137 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Kasim Baybikov, <kmbaybikov@basistech.ru>
Tim Tkachev, <tvtkachev@basistech.ru>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/
package extnet
import (
"context"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
)
func dataSourceExtnetReservedIpRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
reservedList, err := utilityExtnetReservedIpCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(id.String())
d.Set("items", flattenExtnetReservedIp(reservedList))
return nil
}
func dataSourceExtnetReservedIpSchemaMake() map[string]*schema.Schema {
res := map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Required: true,
},
"extnet_id": {
Type: schema.TypeInt,
Optional: true,
},
"items": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"extnet_id": {
Type: schema.TypeInt,
Computed: true,
},
"reservations": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Computed: true,
},
"client_type": {
Type: schema.TypeString,
Computed: true,
},
"domain_name": {
Type: schema.TypeString,
Computed: true,
},
"hostname": {
Type: schema.TypeString,
Computed: true,
},
"ip": {
Type: schema.TypeString,
Computed: true,
},
"mac": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
"vm_id": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
},
},
},
}
return res
}
func DataSourceExtnetReservedIp() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
ReadContext: dataSourceExtnetReservedIpRead,
Timeouts: &schema.ResourceTimeout{
Read: &constants.Timeout30s,
Default: &constants.Timeout60s,
},
Schema: dataSourceExtnetReservedIpSchemaMake(),
}
}

@ -54,6 +54,7 @@ func flattenExtnetReservations(ers extnet.ListReservations) []map[string]interfa
res := make([]map[string]interface{}, 0, len(ers))
for _, er := range ers {
temp := map[string]interface{}{
"account_id": er.AccountID,
"client_type": er.ClientType,
"domainname": er.DomainName,
"hostname": er.Hostname,
@ -135,3 +136,29 @@ func flattenExtnetList(el *extnet.ListExtNets) []map[string]interface{} {
}
return res
}
func flattenExtnetReservedIp(el []extnet.RecordReservedIP) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(el))
for _, e := range el {
reservations := make([]map[string]interface{}, 0, len(e.Reservations))
for _, r := range e.Reservations {
temp := map[string]interface{}{
"account_id": r.AccountID,
"client_type": r.ClientType,
"domain_name": r.DomainName,
"hostname": r.Hostname,
"ip": r.IP,
"mac": r.Mac,
"type": r.Type,
"vm_id": r.VMID,
}
reservations = append(reservations, temp)
}
item := map[string]interface{}{
"extnet_id": e.ExtnetID,
"reservations": reservations,
}
res = append(res, item)
}
return res
}

@ -0,0 +1,61 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Kasim Baybikov, <kmbaybikov@basistech.ru>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/
package extnet
import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/extnet"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
)
func utilityExtnetReservedIpCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) ([]extnet.RecordReservedIP, error) {
c := m.(*controller.ControllerCfg)
req := extnet.GetReservedIP{
AccountID: uint64(d.Get("account_id").(int)),
}
if extNetID, ok := d.GetOk("extnet_id"); ok {
req.ExtNetID = uint64(extNetID.(int))
}
log.Debugf("utilityExtnetReservedIpCheckPresence")
res, err := c.CloudAPI().ExtNet().GetReservedIP(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}

@ -703,6 +703,10 @@ func dataSourceComputeSchemaMake() map[string]*schema.Schema {
Type: schema.TypeString,
Computed: true,
},
"auto_start_w_node": {
Type: schema.TypeBool,
Computed: true,
},
"chipset": {
Type: schema.TypeString,
Computed: true,
@ -950,6 +954,10 @@ func dataSourceComputeSchemaMake() map[string]*schema.Schema {
Type: schema.TypeString,
Computed: true,
},
"vnc_password": {
Type: schema.TypeString,
Computed: true,
},
"vgpus": {
Type: schema.TypeList,
Computed: true,

@ -121,6 +121,10 @@ func itemComputeSchemaMake() map[string]*schema.Schema {
Type: schema.TypeString,
Computed: true,
},
"auto_start_w_node": {
Type: schema.TypeBool,
Computed: true,
},
"boot_order": {
Type: schema.TypeList,
Computed: true,

@ -183,6 +183,7 @@ func flattenComputeList(computes *compute.ListComputes) []map[string]interface{}
"affinity_weight": compute.AffinityWeight,
"anti_affinity_rules": flattenListRules(compute.AntiAffinityRules),
"arch": compute.Architecture,
"auto_start_w_node": compute.AutoStart,
"boot_order": compute.BootOrder,
"bootdisk_size": compute.BootDiskSize,
"chipset": compute.Chipset,
@ -362,6 +363,7 @@ func flattenCompute(d *schema.ResourceData, computeRec compute.RecordCompute, pc
d.Set("account_name", computeRec.AccountName)
d.Set("affinity_weight", computeRec.AffinityWeight)
d.Set("arch", computeRec.Architecture)
d.Set("auto_start_w_node", computeRec.AutoStart)
d.Set("boot_order", computeRec.BootOrder)
// we intentionally use the SizeMax field, do not change it until the BootDiskSize field is fixed on the platform
d.Set("boot_disk_size", bootDisk.SizeMax)
@ -429,6 +431,7 @@ func flattenCompute(d *schema.ResourceData, computeRec compute.RecordCompute, pc
d.Set("updated_by", computeRec.UpdatedBy)
d.Set("updated_time", computeRec.UpdatedTime)
d.Set("user_managed", computeRec.UserManaged)
d.Set("vnc_password", computeRec.VNCPassword)
d.Set("vgpus", computeRec.VGPUs)
d.Set("virtual_image_id", computeRec.VirtualImageID)
d.Set("virtual_image_name", computeRec.VirtualImageName)
@ -613,6 +616,7 @@ func flattenDataCompute(d *schema.ResourceData, computeRec compute.RecordCompute
d.Set("affinity_rules", flattenAffinityRules(computeRec.AffinityRules))
d.Set("affinity_weight", computeRec.AffinityWeight)
d.Set("anti_affinity_rules", flattenListRules(computeRec.AntiAffinityRules))
d.Set("auto_start_w_node", computeRec.AutoStart)
d.Set("arch", computeRec.Architecture)
d.Set("chipset", computeRec.Chipset)
d.Set("boot_order", computeRec.BootOrder)
@ -672,6 +676,7 @@ func flattenDataCompute(d *schema.ResourceData, computeRec compute.RecordCompute
d.Set("updated_time", computeRec.UpdatedTime)
d.Set("user_managed", computeRec.UserManaged)
d.Set("userdata", string(userdata))
d.Set("vnc_password", computeRec.VNCPassword)
d.Set("vgpus", computeRec.VGPUs)
d.Set("virtual_image_id", computeRec.VirtualImageID)
d.Set("virtual_image_name", computeRec.VirtualImageName)

@ -491,12 +491,26 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
req := compute.PinToStackRequest{
ComputeID: computeId,
}
req.AutoStart = d.Get("auto_start_w_node").(bool)
_, err := c.CloudAPI().Compute().PinToStack(ctx, req)
if err != nil {
warnings.Add(err)
}
}
if !d.Get("pin_to_stack").(bool) && d.Get("auto_start_w_node").(bool) {
req := compute.UpdateRequest{
ComputeID: computeId,
AutoStart: d.Get("auto_start_w_node").(bool),
CPUPin: d.Get("cpu_pin").(bool),
HPBacked: d.Get("hp_backed").(bool),
}
_, err := c.CloudAPI().Compute().Update(ctx, req)
if err != nil {
warnings.Add(err)
}
}
if d.Get("pause").(bool) {
req := compute.PauseRequest{
ComputeID: computeId,
@ -619,7 +633,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
}
if !hasRG {
return diag.Errorf("resourceComputeUpdate: can't update Compute bacause 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))
}
hasImage, err := existImageId(ctx, d, m)
@ -628,7 +642,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
}
if !hasImage {
return diag.Errorf("resourceComputeUpdate: can't update Compute bacause 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 disks, ok := d.GetOk("disks"); ok {
@ -862,7 +876,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
}
}
if d.HasChanges("description", "name", "numa_affinity", "cpu_pin", "hp_backed") {
if d.HasChanges("description", "name", "numa_affinity", "cpu_pin", "hp_backed", "chipset", "auto_start_w_node") {
req := compute.UpdateRequest{
ComputeID: computeRec.ID,
}
@ -876,21 +890,17 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
if d.HasChange("numa_affinity") {
req.NumaAffinity = d.Get("numa_affinity").(string)
}
if d.HasChange("cpu_pin") {
req.CPUPin = d.Get("cpu_pin").(bool)
}
if d.HasChange("hp_backed") {
req.HPBacked = d.Get("hp_backed").(bool)
}
if d.HasChange("chipset") {
req.Chipset = d.Get("chipset").(string)
}
req.CPUPin = d.Get("cpu_pin").(bool)
req.HPBacked = d.Get("hp_backed").(bool)
req.AutoStart = d.Get("auto_start_w_node").(bool)
// Note bene: numa_affinity, cpu_pin and hp_backed are not allowed to be changed for compute in STARTED tech status.
// If STARTED, we need to stop it before update
var isStopRequired bool
if d.HasChanges("numa_affinity", "cpu_pin", "hp_backed") && d.Get("started").(bool) {
if d.HasChanges("numa_affinity", "cpu_pin", "hp_backed", "chipset") && d.Get("started").(bool) {
isStopRequired = true
}
if isStopRequired {
@ -1481,7 +1491,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
req := compute.PinToStackRequest{
ComputeID: computeRec.ID,
}
req.AutoStart = d.Get("auto_start_w_node").(bool)
_, err := c.CloudAPI().Compute().PinToStack(ctx, req)
if err != nil {
return diag.FromErr(err)
@ -2123,6 +2133,12 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema {
Optional: true,
Default: false,
},
"auto_start_w_node": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
Description: "Flag for start compute after node exits from MAINTENANCE state",
},
"auto_start": {
Type: schema.TypeBool,
Optional: true,
@ -2411,6 +2427,10 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema {
Type: schema.TypeBool,
Computed: true,
},
"vnc_password": {
Type: schema.TypeString,
Computed: true,
},
"vgpus": {
Type: schema.TypeList,
Computed: true,
@ -2444,11 +2464,14 @@ func ResourceCompute() *schema.Resource {
},
CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, i interface{}) error {
if diff.HasChanges() || diff.HasChanges("network", "affinity_rules", "anti_affinity_rules",
if diff.HasChanges() || diff.HasChanges("chipset", "pin_to_stack", "auto_start_w_node", "network", "affinity_rules", "anti_affinity_rules",
"disks", "extra_disks", "tags", "port_forwarding", "user_access", "snapshot", "pci_devices") {
diff.SetNewComputed("updated_time")
diff.SetNewComputed("updated_by")
}
if diff.HasChanges("pin_to_stack") {
diff.SetNewComputed("pinned")
}
return nil
},

@ -347,6 +347,10 @@ func vnfDevSchemaMake() map[string]*schema.Schema {
Type: schema.TypeString,
Computed: true,
},
"vnc_password": {
Type: schema.TypeString,
Computed: true,
},
"vins": {
Type: schema.TypeList,
Computed: true,
@ -372,20 +376,8 @@ func vinsComputeSchemaMake() map[string]*schema.Schema {
func reservationSchemaMake() map[string]*schema.Schema {
return map[string]*schema.Schema{
"client_type": {
Type: schema.TypeString,
Computed: true,
},
"desc": {
Type: schema.TypeString,
Computed: true,
},
"domainname": {
Type: schema.TypeString,
Computed: true,
},
"hostname": {
Type: schema.TypeString,
"account_id": {
Type: schema.TypeInt,
Computed: true,
},
"ip": {

@ -151,6 +151,7 @@ func flattenVNFDev(vnfDev vins.RecordVNFDev) []map[string]interface{} {
"status": vnfDev.Status,
"tech_status": vnfDev.TechStatus,
"type": vnfDev.Type,
"vnc_password": vnfDev.VNCPassword,
"vins": vnfDev.VINS,
}
@ -176,14 +177,11 @@ func flattenReservations(reservations vins.ListReservations) []map[string]interf
res := make([]map[string]interface{}, 0, len(reservations))
for _, reservation := range reservations {
temp := map[string]interface{}{
"client_type": reservation.ClientType,
"desc": reservation.Description,
"domainname": reservation.DomainName,
"hostname": reservation.Hostname,
"ip": reservation.IP,
"mac": reservation.MAC,
"type": reservation.Type,
"vm_id": reservation.VMID,
"account_id": reservation.AccountID,
"ip": reservation.IP,
"mac": reservation.MAC,
"type": reservation.Type,
"vm_id": reservation.VMID,
}
res = append(res, temp)
}

@ -1,277 +1,194 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Kasim Baybikov, <kmbaybikov@basistech.ru>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/
package vins
import (
"context"
"fmt"
"strconv"
"strings"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/vins"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/dc"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func resourceStaticRouteCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := m.(*controller.ControllerCfg)
if _, ok := d.GetOk("vins_id"); ok {
haveVinsID, err := existVinsID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveVinsID {
return diag.Errorf("resourceStaticRouteCreate: can't create Static Route because Vins ID %d is not allowed or does not exist", d.Get("vins_id").(int))
}
}
req := vins.StaticRouteAddRequest{
VINSID: uint64(d.Get("vins_id").(int)),
Destination: d.Get("destination").(string),
Netmask: d.Get("netmask").(string),
Gateway: d.Get("gateway").(string),
}
if computesIDS, ok := d.GetOk("compute_ids"); ok {
ids := computesIDS.([]interface{})
res := make([]uint64, 10)
for _, id := range ids {
computeId := uint64(id.(int))
res = append(res, computeId)
}
req.ComputeIds = res
}
_, err := c.CloudAPI().VINS().StaticRouteAdd(ctx, req)
if err != nil {
return diag.FromErr(err)
}
staticRouteData, err := getStaticRouteData(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
d.SetId(fmt.Sprintf("%d#%d", req.VINSID, staticRouteData.ID))
return resourceStaticRouteRead(ctx, d, m)
}
func resourceStaticRouteRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
warnings := dc.Warnings{}
staticRouteData, err := utilityDataStaticRouteCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
flattenStaticRouteData(d, staticRouteData)
return warnings.Get()
}
func resourceStaticRouteUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := m.(*controller.ControllerCfg)
warnings := dc.Warnings{}
if _, ok := d.GetOk("vins_id"); ok {
haveVinsID, err := existVinsID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveVinsID {
return diag.Errorf("resourceVinsUpdate: can't update Static Route because VinsID %d is not allowed or does not exist", d.Get("vins_id").(int))
}
}
staticRouteData, err := utilityDataStaticRouteCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
if d.HasChange("compute_ids") {
deletedIds := make([]uint64, 0)
addedIds := make([]uint64, 0)
oldComputeIds, newComputeIds := d.GetChange("compute_ids")
oldComputeIdsSlice := oldComputeIds.([]interface{})
newComputeIdsSlice := newComputeIds.([]interface{})
for _, el := range oldComputeIdsSlice {
if !isContainsIds(newComputeIdsSlice, el) {
convertedEl := uint64(el.(int))
deletedIds = append(deletedIds, convertedEl)
}
}
for _, el := range newComputeIdsSlice {
if !isContainsIds(oldComputeIdsSlice, el) {
convertedEl := uint64(el.(int))
addedIds = append(addedIds, convertedEl)
}
}
if len(deletedIds) > 0 {
req := vins.StaticRouteAccessRevokeRequest{
VINSID: uint64(d.Get("vins_id").(int)),
RouteId: staticRouteData.ID,
ComputeIds: deletedIds,
}
_, err := c.CloudAPI().VINS().StaticRouteAccessRevoke(ctx, req)
if err != nil {
warnings.Add(err)
}
}
if len(addedIds) > 0 {
req := vins.StaticRouteAccessGrantRequest{
VINSID: uint64(d.Get("vins_id").(int)),
RouteId: staticRouteData.ID,
ComputeIds: addedIds,
}
_, err := c.CloudAPI().VINS().StaticRouteAccessGrant(ctx, req)
if err != nil {
warnings.Add(err)
}
}
}
return append(warnings.Get(), resourceStaticRouteRead(ctx, d, m)...)
}
func resourceStaticRouteDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := m.(*controller.ControllerCfg)
arr := strings.Split(d.Id(), "#")
if len(arr) != 2 {
return diag.FromErr(fmt.Errorf("broken state id"))
}
vinsId, _ := strconv.ParseUint(arr[0], 10, 64)
routeId, _ := strconv.ParseUint(arr[1], 10, 64)
req := vins.StaticRouteDelRequest{
VINSID: vinsId,
RouteId: routeId,
}
_, err := c.CloudAPI().VINS().StaticRouteDel(ctx, req)
if err != nil {
return diag.FromErr(err)
}
d.SetId("")
return nil
}
func resourceStaticRouteSchemaMake() map[string]*schema.Schema {
rets := dataSourceStaticRouteSchemaMake()
rets["route_id"] = &schema.Schema{
Type: schema.TypeInt,
Computed: true,
Optional: true,
}
rets["compute_ids"] = &schema.Schema{
Type: schema.TypeList,
Optional: true,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
}
rets["destination"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
}
rets["gateway"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
}
rets["netmask"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
}
return rets
}
func isContainsIds(els []interface{}, el interface{}) bool {
convEl := el.(int)
for _, elOld := range els {
if convEl == elOld.(int) {
return true
}
}
return false
}
func ResourceStaticRoute() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
CreateContext: resourceStaticRouteCreate,
ReadContext: resourceStaticRouteRead,
UpdateContext: resourceStaticRouteUpdate,
DeleteContext: resourceStaticRouteDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Timeouts: &schema.ResourceTimeout{
Create: &constants.Timeout20m,
Read: &constants.Timeout600s,
Update: &constants.Timeout20m,
Delete: &constants.Timeout600s,
Default: &constants.Timeout600s,
},
Schema: resourceStaticRouteSchemaMake(),
}
}
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Kasim Baybikov, <kmbaybikov@basistech.ru>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/
package vins
import (
"context"
"fmt"
"strconv"
"strings"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/vins"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/dc"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func resourceStaticRouteCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := m.(*controller.ControllerCfg)
if _, ok := d.GetOk("vins_id"); ok {
haveVinsID, err := existVinsID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveVinsID {
return diag.Errorf("resourceStaticRouteCreate: can't create Static Route because Vins ID %d is not allowed or does not exist", d.Get("vins_id").(int))
}
}
req := vins.StaticRouteAddRequest{
VINSID: uint64(d.Get("vins_id").(int)),
Destination: d.Get("destination").(string),
Netmask: d.Get("netmask").(string),
Gateway: d.Get("gateway").(string),
}
_, err := c.CloudAPI().VINS().StaticRouteAdd(ctx, req)
if err != nil {
return diag.FromErr(err)
}
staticRouteData, err := getStaticRouteData(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
d.SetId(fmt.Sprintf("%d#%d", req.VINSID, staticRouteData.ID))
return resourceStaticRouteRead(ctx, d, m)
}
func resourceStaticRouteRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
warnings := dc.Warnings{}
staticRouteData, err := utilityDataStaticRouteCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
flattenStaticRouteData(d, staticRouteData)
return warnings.Get()
}
func resourceStaticRouteUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
return nil
}
func resourceStaticRouteDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := m.(*controller.ControllerCfg)
arr := strings.Split(d.Id(), "#")
if len(arr) != 2 {
return diag.FromErr(fmt.Errorf("broken state id"))
}
vinsId, _ := strconv.ParseUint(arr[0], 10, 64)
routeId, _ := strconv.ParseUint(arr[1], 10, 64)
req := vins.StaticRouteDelRequest{
VINSID: vinsId,
RouteId: routeId,
}
_, err := c.CloudAPI().VINS().StaticRouteDel(ctx, req)
if err != nil {
return diag.FromErr(err)
}
d.SetId("")
return nil
}
func resourceStaticRouteSchemaMake() map[string]*schema.Schema {
rets := dataSourceStaticRouteSchemaMake()
rets["route_id"] = &schema.Schema{
Type: schema.TypeInt,
Computed: true,
Optional: true,
}
rets["compute_ids"] = &schema.Schema{
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
}
rets["destination"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
}
rets["gateway"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
}
rets["netmask"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
}
return rets
}
func isContainsIds(els []interface{}, el interface{}) bool {
convEl := el.(int)
for _, elOld := range els {
if convEl == elOld.(int) {
return true
}
}
return false
}
func ResourceStaticRoute() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
CreateContext: resourceStaticRouteCreate,
ReadContext: resourceStaticRouteRead,
UpdateContext: resourceStaticRouteUpdate,
DeleteContext: resourceStaticRouteDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Timeouts: &schema.ResourceTimeout{
Create: &constants.Timeout20m,
Read: &constants.Timeout600s,
Update: &constants.Timeout20m,
Delete: &constants.Timeout600s,
Default: &constants.Timeout600s,
},
Schema: resourceStaticRouteSchemaMake(),
}
}

@ -0,0 +1,71 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Kasim Baybikov, <kmbaybikov@basistech.ru>
Tim Tkachev, <tvtkachev@basistech.ru>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/
package extnet
import (
"context"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
)
func dataSourceExtnetReservedIpRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
reservedList, err := utilityExtnetReservedIpCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(id.String())
d.Set("items", flattenExtnetReservedIp(reservedList))
return nil
}
func DataSourceExtnetReservedIp() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
ReadContext: dataSourceExtnetReservedIpRead,
Timeouts: &schema.ResourceTimeout{
Read: &constants.Timeout30s,
Default: &constants.Timeout60s,
},
Schema: dataSourceExtnetReservedIpSchemaMake(),
}
}

@ -133,7 +133,6 @@ func flattenRecordExtnetResource(d *schema.ResourceData, recNet *extnet.RecordEx
d.Set("routes", flattenStaticRouteList(staticRouteList))
}
func flattenExtnetExcluded(ers extnet.ListReservations) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, er := range ers {
@ -157,6 +156,7 @@ func flattenExtnetReservations(ers extnet.ListReservations) []map[string]interfa
res := make([]map[string]interface{}, 0)
for _, er := range ers {
temp := map[string]interface{}{
"account_id": er.AccountID,
"client_type": er.ClientType,
"domain_name": er.DomainName,
"hostname": er.Hostname,
@ -217,4 +217,30 @@ func flattenStaticRouteData(d *schema.ResourceData, route *extnet.ItemRoutes) {
d.Set("netmask", route.Netmask)
d.Set("compute_ids", route.ComputeIds)
d.Set("route_id", route.ID)
}
}
func flattenExtnetReservedIp(el []extnet.RecordReservedIP) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(el))
for _, e := range el {
reservations := make([]map[string]interface{}, 0, len(e.Reservations))
for _, r := range e.Reservations {
temp := map[string]interface{}{
"account_id": r.AccountID,
"client_type": r.ClientType,
"domain_name": r.DomainName,
"hostname": r.Hostname,
"ip": r.IP,
"mac": r.Mac,
"type": r.Type,
"vm_id": r.VMID,
}
reservations = append(reservations, temp)
}
item := map[string]interface{}{
"extnet_id": e.ExtnetID,
"reservations": reservations,
}
res = append(res, item)
}
return res
}

@ -54,6 +54,9 @@ func resourceExtnetCreate(ctx context.Context, d *schema.ResourceData, m interfa
if err := ic.ExistGID(ctx, uint64(d.Get("gid").(int)), c); err != nil {
return diag.FromErr(err)
}
if err := checkReserveIp(ctx, d, c); err != nil {
return diag.FromErr(err)
}
req := extnet.CreateRequest{
Name: d.Get("name").(string),
@ -191,6 +194,34 @@ func resourceExtnetCreate(ctx context.Context, d *schema.ResourceData, m interfa
}
}
// for reserve IP extnet must be enabled
if d.Get("reserved_ip").(*schema.Set).Len() > 0 {
for _, reservedIP := range d.Get("reserved_ip").(*schema.Set).List() {
reservedIPMap := reservedIP.(map[string]interface{})
req := extnet.AddReserveIPRequest{
AccountID: uint64(reservedIPMap["account_id"].(int)),
ExtNetID: netID,
}
if ipCount, ok := reservedIPMap["ip_count"]; ok {
req.IPCount = uint64(ipCount.(int))
}
if reservedIPMap["ips"].(*schema.Set).Len() > 0 {
ips := reservedIPMap["ips"].(*schema.Set).List()
for i, ip := range ips {
if i >= int(req.IPCount) {
break
}
req.IPs = append(req.IPs, ip.(string))
}
}
_, err := c.CloudBroker().ExtNet().AddReserveIP(ctx, req)
if err != nil {
w.Add(err)
}
}
}
return resourceExtnetRead(ctx, d, m)
}
@ -215,6 +246,10 @@ func resourceExtnetUpdate(ctx context.Context, d *schema.ResourceData, m interfa
log.Debugf("cloudbroker: resourceExtnetUpdate called with id %s", d.Id())
c := m.(*controller.ControllerCfg)
if err := checkReserveIp(ctx, d, c); err != nil {
return diag.FromErr(err)
}
recNet, err := utilityExtnetCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
@ -267,6 +302,12 @@ func resourceExtnetUpdate(ctx context.Context, d *schema.ResourceData, m interfa
}
}
if d.HasChange("reserved_ip") {
if err := reservedIPsUpdate(ctx, d, c, recNet); err != nil {
return diag.FromErr(err)
}
}
if d.HasChange("shared_with") {
if err := handleSharedWithUpdate(ctx, d, c); err != nil {
return diag.FromErr(err)
@ -330,6 +371,8 @@ func ResourceExtnetCB() *schema.Resource {
Default: &constants.Timeout300s,
},
CustomizeDiff: validateReserveIPs,
Schema: resourceExtnetSchemaMake(),
}
}

@ -1,6 +1,9 @@
package extnet
import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
func dataSourceExtnetDefaultSchemaMake() map[string]*schema.Schema {
return map[string]*schema.Schema{
@ -474,6 +477,10 @@ func dataSourceExtnetSchemaMake() map[string]*schema.Schema {
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Computed: true,
},
"client_type": {
Type: schema.TypeString,
Computed: true,
@ -728,6 +735,30 @@ func resourceExtnetSchemaMake() map[string]*schema.Schema {
Type: schema.TypeInt,
},
},
"reserved_ip": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Required: true,
},
"ip_count": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(1, 255),
},
"ips": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
"ckey": {
Type: schema.TypeString,
Computed: true,
@ -868,6 +899,10 @@ func resourceExtnetSchemaMake() map[string]*schema.Schema {
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Computed: true,
},
"client_type": {
Type: schema.TypeString,
Computed: true,
@ -905,3 +940,69 @@ func resourceExtnetSchemaMake() map[string]*schema.Schema {
},
}
}
func dataSourceExtnetReservedIpSchemaMake() map[string]*schema.Schema {
res := map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Required: true,
},
"extnet_id": {
Type: schema.TypeInt,
Optional: true,
},
"items": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"extnet_id": {
Type: schema.TypeInt,
Computed: true,
},
"reservations": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Computed: true,
},
"client_type": {
Type: schema.TypeString,
Computed: true,
},
"domain_name": {
Type: schema.TypeString,
Computed: true,
},
"hostname": {
Type: schema.TypeString,
Computed: true,
},
"ip": {
Type: schema.TypeString,
Computed: true,
},
"mac": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
"vm_id": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
},
},
},
}
return res
}

@ -0,0 +1,61 @@
/*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Kasim Baybikov, <kmbaybikov@basistech.ru>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it
builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/
package extnet
import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/extnet"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
)
func utilityExtnetReservedIpCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) ([]extnet.RecordReservedIP, error) {
c := m.(*controller.ControllerCfg)
req := extnet.GetReservedIP{
AccountID: uint64(d.Get("account_id").(int)),
}
if extNetID, ok := d.GetOk("extnet_id"); ok {
req.ExtNetID = uint64(extNetID.(int))
}
log.Debugf("utilityExtnetReservedIpCheckPresence")
res, err := c.CloudBroker().ExtNet().GetReservedIP(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}

@ -35,6 +35,8 @@ package extnet
import (
"context"
"errors"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
@ -341,3 +343,255 @@ func handleMigrateUpdate(ctx context.Context, d *schema.ResourceData, c *control
return nil
}
func checkReserveIp(ctx context.Context, d *schema.ResourceData, c *controller.ControllerCfg) error {
var err error
if d.Get("reserved_ip").(*schema.Set).Len() > 0 {
reservedIPList := d.Get("reserved_ip").(*schema.Set).List()
accountMap := make(map[int]struct{}, len(reservedIPList))
for _, reservedIP := range reservedIPList {
reservedIPMap := reservedIP.(map[string]interface{})
accountId := reservedIPMap["account_id"].(int)
if _, ok := accountMap[accountId]; ok {
err = errors.Join(err, fmt.Errorf("checkReserveIp: you must have only one block with id %d", accountId))
}
accountMap[accountId] = struct{}{}
_, okCount := reservedIPMap["ip_count"]
if !okCount && reservedIPMap["ips"].(*schema.Set).Len() == 0 {
err = errors.Join(err, fmt.Errorf("checkReserveIp: either ip_count or set of ips must be specified"))
}
existErr := ic.ExistAccount(ctx, uint64(accountId), c)
if existErr != nil {
err = errors.Join(err, existErr)
}
}
}
return err
}
func reservedIPsUpdate(ctx context.Context, d *schema.ResourceData, c *controller.ControllerCfg, recNet *extnet.RecordExtNet) error {
addSet, delSet, err := differenceIPReserved(ctx, d, c)
if err != nil {
return err
}
if len(delSet) > 0 {
for _, del := range delSet {
delMap := del.(map[string]interface{})
log.Debugf("reservedIPsUpdate: removing reserved IPs for account %d", delMap["account_id"].(int))
req := extnet.DelReserveIPRequest{
AccountID: uint64(delMap["account_id"].(int)),
ExtNetID: recNet.ID,
}
if ipCount, ok := delMap["ip_count"]; ok {
req.IPCount = uint64(ipCount.(int))
}
if delIPs, ok := delMap["ips"]; ok {
ips := delIPs.(*schema.Set).List()
for _, ip := range ips {
req.IPs = append(req.IPs, ip.(string))
}
}
_, err := c.CloudBroker().ExtNet().DelReserveIP(ctx, req)
if err != nil {
return err
}
}
}
if len(addSet) > 0 {
for _, add := range addSet {
addMap := add.(map[string]interface{})
log.Debugf("reservedIPsUpdate: add reserved IPs for account %d", addMap["account_id"].(int))
req := extnet.AddReserveIPRequest{
AccountID: uint64(addMap["account_id"].(int)),
ExtNetID: recNet.ID,
}
if ipCount, ok := addMap["ip_count"]; ok {
req.IPCount = uint64(ipCount.(int))
}
if addIPs, ok := addMap["ips"]; ok {
ips := addIPs.(*schema.Set).List()
for _, ip := range ips {
req.IPs = append(req.IPs, ip.(string))
}
}
_, err := c.CloudBroker().ExtNet().AddReserveIP(ctx, req)
if err != nil {
return err
}
}
}
return nil
}
func differenceIPReserved(ctx context.Context, d *schema.ResourceData, c *controller.ControllerCfg) (addList, delList []interface{}, errs error) {
addList = make([]interface{}, 0)
delList = make([]interface{}, 0)
oldSet, newSet := d.GetChange("reserved_ip")
oldList := oldSet.(*schema.Set).List()
newList := newSet.(*schema.Set).List()
for _, oldReservedIP := range oldList {
oldMap := oldReservedIP.(map[string]interface{})
found := false
for _, newReservedIP := range newList {
newMap := newReservedIP.(map[string]interface{})
if newMap["account_id"] == oldMap["account_id"] && newMap["ip_count"] == oldMap["ip_count"] && newMap["ips"] == oldMap["ips"] {
found = true
break
}
if newMap["account_id"] == oldMap["account_id"] {
add := make(map[string]interface{}, 0)
del := make(map[string]interface{}, 0)
delSet := oldMap["ips"].(*schema.Set).Difference(newMap["ips"].(*schema.Set))
addSet := newMap["ips"].(*schema.Set).Difference(oldMap["ips"].(*schema.Set))
if delSet.Len() > 0 {
del["account_id"] = oldMap["account_id"].(int)
del["ips"] = delSet
if oldMap["ip_count"].(int)-newMap["ip_count"].(int) >= delSet.Len() {
del["ip_count"] = oldMap["ip_count"].(int) - newMap["ip_count"].(int)
} else {
del["ip_count"] = delSet.Len()
newMap["ip_count"] = newMap["ip_count"].(int) + delSet.Len()
}
} else if newMap["ip_count"].(int) < oldMap["ip_count"].(int) {
del["account_id"] = oldMap["account_id"].(int)
del["ip_count"] = oldMap["ip_count"].(int) - newMap["ip_count"].(int)
}
if addSet.Len() > 0 {
add["account_id"] = oldMap["account_id"].(int)
add["ips"] = addSet
add["ip_count"] = newMap["ip_count"].(int) - oldMap["ip_count"].(int)
if add["ip_count"].(int) < 0 {
add["ip_count"] = 0
}
if add["ip_count"].(int)-addSet.Len() < 0 {
del["account_id"] = oldMap["account_id"].(int)
if _, ok := del["ip_count"]; ok {
del["ip_count"] = del["ip_count"].(int) + addSet.Len()
} else {
del["ip_count"] = addSet.Len()
}
}
} else if newMap["ip_count"].(int)-oldMap["ip_count"].(int) > 0 {
add["account_id"] = oldMap["account_id"].(int)
add["ip_count"] = newMap["ip_count"].(int) - oldMap["ip_count"].(int)
}
if _, ok := add["account_id"]; ok {
addList = append(addList, add)
}
if _, ok := del["account_id"]; ok {
ipsLen := 0
if _, ok := del["ips"]; ok {
ipsLen = del["ips"].(*schema.Set).Len()
}
freeCount := del["ip_count"].(int) - ipsLen
if freeCount > 0 {
req := extnet.GetReservedIP{
AccountID: uint64(del["account_id"].(int)),
ExtNetID: uint64(d.Get("extnet_id").(int)),
}
resIpsList, err := c.CloudBroker().ExtNet().GetReservedIP(ctx, req)
if err != nil {
errs = errors.Join(errs, err)
}
freeIPs := getFreeIps(resIpsList[0].Reservations, newMap["ips"], del["ips"])
if _, ok := del["ips"]; !ok {
del["ips"] = schema.NewSet(schema.HashString, []interface{}{})
}
for i := 0; i < freeCount; i++ {
del["ips"].(*schema.Set).Add(freeIPs[i])
}
}
delList = append(delList, del)
}
found = true
break
}
}
if found {
continue
}
delList = append(delList, oldReservedIP)
}
for _, newReservedIP := range newList {
newMap := newReservedIP.(map[string]interface{})
found := false
for _, oldReservedIP := range oldList {
oldMap := oldReservedIP.(map[string]interface{})
if newMap["account_id"] == oldMap["account_id"] {
found = true
break
}
}
if found {
continue
}
addList = append(addList, newReservedIP)
}
if errs != nil {
d.Set("reserved_ip", oldSet)
}
return
}
// getFreeIps returns array IPs which can be deleted
func getFreeIps(reserved []extnet.Reservations, newIps, delIps interface{}) []string {
newIpsList := make([]interface{}, 0)
delIpsList := make([]interface{}, 0)
if newIps != nil {
newIpsList = newIps.(*schema.Set).List()
}
if delIps != nil {
delIpsList = delIps.(*schema.Set).List()
}
newIpsMap := make(map[string]struct{}, len(newIpsList))
delIpsMap := make(map[string]struct{}, len(delIpsList))
freeIPs := make([]string, 0)
for _, ip := range newIpsList {
newIpsMap[ip.(string)] = struct{}{}
}
for _, ip := range delIpsList {
delIpsMap[ip.(string)] = struct{}{}
}
for _, item := range reserved {
if _, ok := newIpsMap[item.IP]; ok {
continue
}
if _, ok := delIpsMap[item.IP]; ok {
continue
}
freeIPs = append(freeIPs, item.IP)
}
return freeIPs
}
func validateReserveIPs(ctx context.Context, d *schema.ResourceDiff, m interface{}) error {
list := d.Get("reserved_ip").(*schema.Set).List()
var errs error
for _, reservedIP := range list {
reservedIPMap := reservedIP.(map[string]interface{})
var countIP, ipsLen int
if _, ok := reservedIPMap["ip_count"]; ok {
countIP = reservedIPMap["ip_count"].(int)
}
if _, ok := reservedIPMap["ips"]; ok {
ipsLen = reservedIPMap["ips"].(*schema.Set).Len()
}
if ipsLen > countIP {
errs = errors.Join(errs, fmt.Errorf("for the reserved_ip block with account_id %d the count parameter must be greater than or equal to len the ips array", reservedIPMap["account_id"].(int)))
}
}
return errs
}

@ -34,61 +34,59 @@ package grid
import (
"context"
"strconv"
"os"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
)
func dataSourceGridGetDiagnosisRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
diagnosis, err := utilityGridGetDiagnosisCheckPresence(ctx, d, m)
filePath := "diagnosis.tar.gz"
if userPath, ok := d.GetOk("file_path"); ok {
filePath = userPath.(string)
}
log.Debugf("dataSourceGridGetDiagnosisRead: create file with name: %s", filePath)
file, err := os.Create(filePath)
defer file.Close()
if err != nil {
d.SetId("")
d.SetId("") // ensure ID is empty in this case
return diag.FromErr(err)
}
d.SetId(strconv.Itoa(d.Get("gid").(int)))
d.Set("diagnosis", diagnosis)
return nil
}
func DataSourceGridGetDiagnosis() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
ReadContext: dataSourceGridGetDiagnosisRead,
Timeouts: &schema.ResourceTimeout{
Read: &constants.Timeout30s,
Default: &constants.Timeout60s,
},
Schema: dataSourceGridGetDiagnosisSchemaMake(),
diagnosis, err := utilityGridGetDiagnosisCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
func dataSourceGridPostDiagnosisRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
diagnosis, err := utilityGridPostDiagnosisCheckPresence(ctx, d, m)
log.Debugf("dataSourceGridGetDiagnosisRead: write data to file with name: %s", filePath)
_, err = file.WriteString(diagnosis)
if err != nil {
d.SetId("")
d.SetId("") // ensure ID is empty in this case
return diag.FromErr(err)
}
d.SetId(strconv.Itoa(d.Get("gid").(int)))
d.Set("diagnosis", diagnosis)
id := uuid.New()
d.SetId(id.String())
return nil
}
func DataSourceGridPostDiagnosis() *schema.Resource {
func DataSourceGridGetDiagnosis() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
ReadContext: dataSourceGridPostDiagnosisRead,
ReadContext: dataSourceGridGetDiagnosisRead,
Timeouts: &schema.ResourceTimeout{
Read: &constants.Timeout30s,
Default: &constants.Timeout60s,
},
Schema: dataSourceGridPostDiagnosisSchemaMake(),
Schema: dataSourceGridGetDiagnosisSchemaMake(),
}
}

@ -586,23 +586,10 @@ func dataSourceGridGetDiagnosisSchemaMake() map[string]*schema.Schema {
Type: schema.TypeInt,
Required: true,
},
"diagnosis": {
"file_path": {
Type: schema.TypeString,
Computed: true,
},
}
}
func dataSourceGridPostDiagnosisSchemaMake() map[string]*schema.Schema {
return map[string]*schema.Schema{
"gid": {
Type: schema.TypeInt,
Required: true,
},
"diagnosis": {
Type: schema.TypeString,
Computed: true,
},
}
}

@ -62,23 +62,3 @@ func utilityGridGetDiagnosisCheckPresence(ctx context.Context, d *schema.Resourc
return gridGetDiagnosis, nil
}
func utilityGridPostDiagnosisCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (string, error) {
c := m.(*controller.ControllerCfg)
req := grid.GetDiagnosisRequest{}
if d.Id() != "" {
id, _ := strconv.ParseUint(d.Id(), 10, 64)
req.GID = id
} else {
req.GID = uint64(d.Get("gid").(int))
}
log.Debugf("utilityGridPostDiagnosisCheckPresence: load grid post diagnosis")
gridPostDiagnosis, err := c.CloudBroker().Grid().GetDiagnosis(ctx, req)
if err != nil {
return "", err
}
return gridPostDiagnosis, nil
}

@ -48,6 +48,7 @@ func flattenImage(d *schema.ResourceData, img *image.RecordImage) {
d.Set("sep_id", img.SEPID)
d.Set("shared_with", img.SharedWith)
d.Set("size", img.Size)
d.Set("snapshot_id", img.SnapshotID)
d.Set("status", img.Status)
d.Set("tech_status", img.TechStatus)
d.Set("image_type", img.Type)
@ -92,47 +93,48 @@ func flattenImageList(il *image.ListImages) []map[string]interface{} {
cdPresentedTo, _ := json.Marshal(item.CdPresentedTo)
temp := map[string]interface{}{
"image_id": item.ID,
"unc_path": item.UNCPath,
"account_id": item.AccountID,
"acl": flattenAcl(item.ACL),
"architecture": item.Architecture,
"boot_type": item.BootType,
"bootable": item.Bootable,
"computeci_id": item.ComputeCIID,
"cd_presented_to": string(cdPresentedTo),
"deleted_time": item.DeletedTime,
"desc": item.Description,
"drivers": item.Drivers,
"enabled": item.Enabled,
"gid": item.GID,
"guid": item.GUID,
"history": flattenHistory(item.History),
"hot_resize": item.HotResize,
"last_modified": item.LastModified,
"link_to": item.LinkTo,
"milestones": item.Milestones,
"name": item.Name,
"image_id": item.ID,
"unc_path": item.UNCPath,
"account_id": item.AccountID,
"acl": flattenAcl(item.ACL),
"architecture": item.Architecture,
"boot_type": item.BootType,
"bootable": item.Bootable,
"computeci_id": item.ComputeCIID,
"cd_presented_to": string(cdPresentedTo),
"deleted_time": item.DeletedTime,
"desc": item.Description,
"drivers": item.Drivers,
"enabled": item.Enabled,
"gid": item.GID,
"guid": item.GUID,
"history": flattenHistory(item.History),
"hot_resize": item.HotResize,
"last_modified": item.LastModified,
"link_to": item.LinkTo,
"milestones": item.Milestones,
"name": item.Name,
"network_interface_naming": item.NetworkInterfaceNaming,
"password": item.Password,
"pool_name": item.Pool,
"present_to": item.PresentTo,
"provider_name": item.ProviderName,
"purge_attempts": item.PurgeAttempts,
"reference_id": item.ReferenceID,
"res_id": item.ResID,
"res_name": item.ResName,
"rescuecd": item.RescueCD,
"sep_id": item.SEPID,
"shared_with": item.SharedWith,
"size": item.Size,
"status": item.Status,
"tech_status": item.TechStatus,
"image_type": item.Type,
"url": item.URL,
"username": item.Username,
"version": item.Version,
"virtual": item.Virtual,
"password": item.Password,
"pool_name": item.Pool,
"present_to": item.PresentTo,
"provider_name": item.ProviderName,
"purge_attempts": item.PurgeAttempts,
"reference_id": item.ReferenceID,
"res_id": item.ResID,
"res_name": item.ResName,
"rescuecd": item.RescueCD,
"sep_id": item.SEPID,
"shared_with": item.SharedWith,
"size": item.Size,
"snapshot_id": item.SnapshotID,
"status": item.Status,
"tech_status": item.TechStatus,
"image_type": item.Type,
"url": item.URL,
"username": item.Username,
"version": item.Version,
"virtual": item.Virtual,
}
res = append(res, temp)
}

@ -622,6 +622,11 @@ func dataSourceImageListSchemaMake() map[string]*schema.Schema {
Computed: true,
Description: "image size",
},
"snapshot_id": {
Type: schema.TypeString,
Computed: true,
Description: "snapshot id",
},
"status": {
Type: schema.TypeString,
Computed: true,
@ -875,6 +880,11 @@ func dataSourceImageSchemaMake() map[string]*schema.Schema {
Computed: true,
Description: "image size",
},
"snapshot_id": {
Type: schema.TypeString,
Computed: true,
Description: "snapshot id",
},
"status": {
Type: schema.TypeString,
Computed: true,
@ -1124,6 +1134,11 @@ func resourceCDROMImageSchemaMake() map[string]*schema.Schema {
Type: schema.TypeInt,
},
},
"snapshot_id": {
Type: schema.TypeString,
Computed: true,
Description: "snapshot id",
},
"status": {
Type: schema.TypeString,
Computed: true,
@ -1415,6 +1430,11 @@ func resourceImageSchemaMake() map[string]*schema.Schema {
Type: schema.TypeInt,
},
},
"snapshot_id": {
Type: schema.TypeString,
Computed: true,
Description: "snapshot id",
},
"status": {
Type: schema.TypeString,
Computed: true,
@ -1689,6 +1709,11 @@ func resourceVirtualImageSchemaMake() map[string]*schema.Schema {
Computed: true,
Description: "image size",
},
"snapshot_id": {
Type: schema.TypeString,
Computed: true,
Description: "snapshot id",
},
"status": {
Type: schema.TypeString,
Computed: true,
@ -1967,6 +1992,11 @@ func resourceImageFromBlankComputeSchemaMake() map[string]*schema.Schema {
Type: schema.TypeInt,
Computed: true,
},
"snapshot_id": {
Type: schema.TypeString,
Computed: true,
Description: "snapshot id",
},
"status": {
Type: schema.TypeString,
Computed: true,
@ -2241,6 +2271,11 @@ func resourceImageFromPlatformDiskSchemaMake() map[string]*schema.Schema {
Type: schema.TypeInt,
Computed: true,
},
"snapshot_id": {
Type: schema.TypeString,
Computed: true,
Description: "snapshot id",
},
"status": {
Type: schema.TypeString,
Computed: true,

@ -34,6 +34,7 @@ func flattenCompute(d *schema.ResourceData, computeRec *compute.RecordCompute, p
d.Set("affinity_rules", flattenAffinityRules(computeRec.AffinityRules))
d.Set("anti_affinity_rules", flattenAffinityRules(computeRec.AntiAffinityRules))
d.Set("arch", computeRec.Arch)
d.Set("auto_start_w_node", computeRec.AutoStart)
d.Set("boot_order", computeRec.BootOrder)
d.Set("boot_disk_id", bootDisk.ID)
// we intentionally use the SizeMax field, do not change it until the BootDiskSize field is fixed on the platform
@ -92,6 +93,7 @@ func flattenCompute(d *schema.ResourceData, computeRec *compute.RecordCompute, p
d.Set("updated_time", computeRec.UpdatedTime)
d.Set("user_data", string(userData))
d.Set("user_managed", computeRec.UserManaged)
d.Set("vnc_password", computeRec.VNCPassword)
d.Set("vgpus", computeRec.VGPUs)
d.Set("virtual_image_id", computeRec.VirtualImageID)
d.Set("virtual_image_name", computeRec.VirtualImageName)
@ -294,6 +296,7 @@ func flattenComputeList(computes *compute.ListComputes) []map[string]interface{}
"affinity_weight": computeItem.AffinityWeight,
"anti_affinity_rules": flattenListRules(computeItem.AntiAffinityRules),
"arch": computeItem.Arch,
"auto_start_w_node": computeItem.AutoStart,
"chipset": computeItem.Chipset,
"cd_image_id": computeItem.CdImageId,
"boot_order": computeItem.BootOrder,
@ -613,6 +616,7 @@ func flattenDataCompute(d *schema.ResourceData, compFacts *compute.RecordCompute
d.Set("affinity_weight", compFacts.AffinityWeight)
d.Set("anti_affinity_rules", flattenAffinityRules(compFacts.AntiAffinityRules))
d.Set("arch", compFacts.Arch)
d.Set("auto_start_w_node", compFacts.AutoStart)
d.Set("boot_order", compFacts.BootOrder)
d.Set("chipset", compFacts.Chipset)
d.Set("cd_image_id", compFacts.CdImageId)
@ -671,6 +675,7 @@ func flattenDataCompute(d *schema.ResourceData, compFacts *compute.RecordCompute
d.Set("updated_time", compFacts.UpdatedTime)
d.Set("user_data", string(userData))
d.Set("user_managed", compFacts.UserManaged)
d.Set("vnc_password", compFacts.VNCPassword)
d.Set("vgpus", compFacts.VGPUs)
d.Set("virtual_image_id", compFacts.VirtualImageID)
d.Set("virtual_image_name", compFacts.VirtualImageName)

@ -484,12 +484,29 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
req.Force = force
}
if autoStart, ok := d.Get("auto_start_w_node").(bool); ok {
req.AutoStart = autoStart
}
_, err := c.CloudBroker().Compute().PinToStack(ctx, req)
if err != nil {
warnings.Add(err)
}
}
if !d.Get("pin_to_stack").(bool) && d.Get("auto_start_w_node").(bool) {
req := compute.UpdateRequest{
ComputeID: computeId,
AutoStart: d.Get("auto_start_w_node").(bool),
CPUPin: d.Get("cpu_pin").(bool),
HPBacked: d.Get("hp_backed").(bool),
}
_, err := c.CloudBroker().Compute().Update(ctx, req)
if err != nil {
warnings.Add(err)
}
}
if d.Get("pause").(bool) {
req := compute.PauseRequest{
ComputeID: computeId,
@ -686,7 +703,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
}
}
if d.HasChanges("description", "name", "numa_affinity", "cpu_pin", "hp_backed") {
if d.HasChanges("description", "name", "numa_affinity", "cpu_pin", "hp_backed", "chipset", "auto_start_w_node") {
if err := utilityComputeUpdate(ctx, d, m); err != nil {
return diag.FromErr(err)
}
@ -839,11 +856,14 @@ func ResourceCompute() *schema.Resource {
SchemaVersion: 1,
CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, i interface{}) error {
if diff.HasChanges() || diff.HasChanges("libvirt_settings", "network", "affinity_rules", "anti_affinity_rules",
if diff.HasChanges() || diff.HasChanges("chipset", "pin_to_stack", "auto_start_w_node", "libvirt_settings", "network", "affinity_rules", "anti_affinity_rules",
"disks", "extra_disks", "tags", "port_forwarding", "user_access", "snapshot", "pci_devices") {
diff.SetNewComputed("updated_time")
diff.SetNewComputed("updated_by")
}
if diff.HasChanges("pin_to_stack") {
diff.SetNewComputed("pinned")
}
return nil
},

@ -134,6 +134,10 @@ func dataSourceComputeSchemaMake() map[string]*schema.Schema {
Type: schema.TypeString,
Computed: true,
},
"auto_start_w_node": {
Type: schema.TypeBool,
Computed: true,
},
"boot_order": {
Type: schema.TypeList,
Computed: true,
@ -902,6 +906,10 @@ func dataSourceComputeSchemaMake() map[string]*schema.Schema {
Type: schema.TypeBool,
Computed: true,
},
"vnc_password": {
Type: schema.TypeString,
Computed: true,
},
"vgpus": {
Type: schema.TypeList,
Computed: true,
@ -990,6 +998,11 @@ func dataSourceComputeListSchemaMake() map[string]*schema.Schema {
Optional: true,
Description: "Find by image ID",
},
"cd_image_id": {
Type: schema.TypeInt,
Optional: true,
Description: "Find by CD image ID",
},
"extnet_name": {
Type: schema.TypeString,
Optional: true,
@ -1145,6 +1158,10 @@ func dataSourceComputeListSchemaMake() map[string]*schema.Schema {
Type: schema.TypeString,
Computed: true,
},
"auto_start_w_node": {
Type: schema.TypeBool,
Computed: true,
},
"boot_order": {
Type: schema.TypeList,
Computed: true,
@ -1802,6 +1819,10 @@ func dataSourceComputeListDeletedSchemaMake() map[string]*schema.Schema {
Type: schema.TypeString,
Computed: true,
},
"auto_start_w_node": {
Type: schema.TypeBool,
Computed: true,
},
"boot_order": {
Type: schema.TypeList,
Computed: true,
@ -3375,6 +3396,11 @@ func resourceComputeSchemaMake() map[string]*schema.Schema {
Optional: true,
Default: false,
},
"auto_start_w_node": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},
"target_stack_id": {
Type: schema.TypeInt,
Optional: true,
@ -3906,6 +3932,10 @@ func resourceComputeSchemaMake() map[string]*schema.Schema {
Type: schema.TypeBool,
Computed: true,
},
"vnc_password": {
Type: schema.TypeString,
Computed: true,
},
"vgpus": {
Type: schema.TypeList,
Computed: true,

@ -852,21 +852,17 @@ func utilityComputeUpdate(ctx context.Context, d *schema.ResourceData, m interfa
if d.HasChange("numa_affinity") {
req.NumaAffinity = d.Get("numa_affinity").(string)
}
if d.HasChange("cpu_pin") {
req.CPUPin = d.Get("cpu_pin").(bool)
}
if d.HasChange("hp_backed") {
req.HPBacked = d.Get("hp_backed").(bool)
}
if d.HasChange("chipset") {
req.Chipset = d.Get("chipset").(string)
}
req.CPUPin = d.Get("cpu_pin").(bool)
req.HPBacked = d.Get("hp_backed").(bool)
req.AutoStart = d.Get("auto_start_w_node").(bool)
// Note bene: numa_affinity, cpu_pin and hp_backed are not allowed to be changed for compute in STARTED tech status.
// If STARTED, we need to stop it before update
var isStopRequired bool
if d.HasChanges("numa_affinity", "cpu_pin", "hp_backed") && d.Get("started").(bool) {
if d.HasChanges("numa_affinity", "cpu_pin", "hp_backed", "chipset") && d.Get("started").(bool) {
isStopRequired = true
}
if isStopRequired {
@ -1434,6 +1430,11 @@ func utilityComputePinToStack(ctx context.Context, d *schema.ResourceData, m int
if force, ok := d.Get("force_pin").(bool); ok {
req.Force = force
}
if autoStart, ok := d.Get("auto_start_w_node").(bool); ok {
req.AutoStart = autoStart
}
_, err := c.CloudBroker().Compute().PinToStack(ctx, req)
if err != nil {
return err

@ -75,6 +75,9 @@ func utilityDataComputeListCheckPresence(ctx context.Context, d *schema.Resource
if imageID, ok := d.GetOk("image_id"); ok {
req.ImageID = imageID.(uint64)
}
if cdImageID, ok := d.GetOk("cd_image_id"); ok {
req.CDImageID = cdImageID.(uint64)
}
if extNetName, ok := d.GetOk("extnet_name"); ok {
req.ExtNetName = extNetName.(string)
}

@ -51,6 +51,7 @@ func flattenNode(d *schema.ResourceData, item *node.RecordNode) {
d.Set("isolated_cpus", flattenNodeItem(item.IsolatedCpus))
d.Set("name", item.Name)
d.Set("need_reboot", item.NeedReboot)
d.Set("net_addr", flattenGetNetAddr(item.NetAddr))
d.Set("nic_info", flattenNicInfo(item.NicInfo))
d.Set("numa_topology", flattenNumaTopology(item.NumaTopology))
d.Set("reserved_cpus", flattenNodeItem(item.ReservedCPUs))
@ -205,9 +206,9 @@ func flattenVFList(vfList []interface{}) []map[string]interface{} {
return res
}
func flattenNetAddr(adresses node.ListNetAddr) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(adresses))
for _, item := range adresses {
func flattenNetAddr(addresses node.ListNetAddr) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(addresses))
for _, item := range addresses {
temp := map[string]interface{}{
"cidr": item.CIDR,
"index": item.Index,
@ -221,6 +222,16 @@ func flattenNetAddr(adresses node.ListNetAddr) []map[string]interface{} {
return res
}
func flattenGetNetAddr(address node.NetAddr) []map[string]interface{} {
res := make([]map[string]interface{}, 1)
temp := map[string]interface{}{
"ip": address.IP,
"name": address.Name,
}
res[0] = temp
return res
}
func flattenCpuInfo(info node.CpuInfo) []map[string]interface{} {
res := make([]map[string]interface{}, 1)
temp := map[string]interface{}{

@ -131,6 +131,25 @@ func dataSourceNodeSchemaMake() map[string]*schema.Schema {
Type: schema.TypeBool,
Computed: true,
},
"net_addr": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"ip": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"name": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"nic_info": {
Type: schema.TypeList,
Computed: true,

@ -150,6 +150,7 @@ func flattenVinsVNFDev(vd vins.VNFDev) []map[string]interface{} {
"status": vd.Status,
"tech_status": vd.TechStatus,
"type": vd.Type,
"vnc_password": vd.VNCPassword,
"vins": vd.VINS,
}
res = append(res, temp)
@ -371,14 +372,12 @@ func flattenVinsListReservations(li vins.ListReservations) []map[string]interfac
res := make([]map[string]interface{}, 0, len(li))
for _, v := range li {
temp := map[string]interface{}{
"client_type": v.ClientType,
"description": v.Description,
"domain_name": v.DomainName,
"host_name": v.Hostname,
"ip": v.IP,
"mac": v.MAC,
"type": v.Type,
"vm_id": v.VMID,
//TODO
//"account_id": v.AccountID,
"ip": v.IP,
"mac": v.MAC,
"type": v.Type,
"vm_id": v.VMID,
}
res = append(res, temp)
}

@ -38,14 +38,12 @@ import (
"strconv"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/vins"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/dc"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func resourceStaticRouteCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -64,19 +62,6 @@ func resourceStaticRouteCreate(ctx context.Context, d *schema.ResourceData, m in
Gateway: d.Get("gateway").(string),
}
if computesIDS, ok := d.GetOk("compute_ids"); ok {
ids := computesIDS.([]interface{})
res := make([]uint64, 10)
for _, id := range ids {
computeId := uint64(id.(int))
res = append(res, computeId)
}
req.ComputeIds = res
}
_, err := c.CloudBroker().VINS().StaticRouteAdd(ctx, req)
if err != nil {
d.SetId("")
@ -108,30 +93,7 @@ func resourceStaticRouteRead(ctx context.Context, d *schema.ResourceData, m inte
}
func resourceStaticRouteUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceStaticRouteUpdate: called for static route id %s", d.Id())
c := m.(*controller.ControllerCfg)
if diags := checkParamsExistenceStaticRoute(ctx, d, c); diags != nil {
return diags
}
staticRouteData, err := utilityDataStaticRouteCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
warnings := dc.Warnings{}
if d.HasChange("compute_ids") {
if errs := resourceStaticRouteChangeComputeIds(ctx, d, m, staticRouteData); len(errs) != 0 {
for _, err := range errs {
warnings.Add(err)
}
}
}
return append(warnings.Get(), resourceStaticRouteRead(ctx, d, m)...)
return nil
}
func resourceStaticRouteDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -158,61 +120,6 @@ func resourceStaticRouteDelete(ctx context.Context, d *schema.ResourceData, m in
return nil
}
func resourceStaticRouteChangeComputeIds(ctx context.Context, d *schema.ResourceData, m interface{}, staticRouteData *vins.ItemRoutes) []error {
c := m.(*controller.ControllerCfg)
var errs []error
vinsId := uint64(d.Get("vins_id").(int))
deletedIds := make([]uint64, 0)
addedIds := make([]uint64, 0)
oldComputeIds, newComputeIds := d.GetChange("compute_ids")
oldComputeIdsSlice := oldComputeIds.([]interface{})
newComputeIdsSlice := newComputeIds.([]interface{})
for _, el := range oldComputeIdsSlice {
if !isContainsIds(newComputeIdsSlice, el) {
convertedEl := uint64(el.(int))
deletedIds = append(deletedIds, convertedEl)
}
}
for _, el := range newComputeIdsSlice {
if !isContainsIds(oldComputeIdsSlice, el) {
convertedEl := uint64(el.(int))
addedIds = append(addedIds, convertedEl)
}
}
if len(deletedIds) > 0 {
req := vins.StaticRouteAccessRevokeRequest{
VINSID: vinsId,
RouteId: staticRouteData.ID,
ComputeIds: deletedIds,
}
if _, err := c.CloudBroker().VINS().StaticRouteAccessRevoke(ctx, req); err != nil {
errs = append(errs, err)
}
}
if len(addedIds) > 0 {
req := vins.StaticRouteAccessGrantRequest{
VINSID: vinsId,
RouteId: staticRouteData.ID,
ComputeIds: addedIds,
}
if _, err := c.CloudBroker().VINS().StaticRouteAccessGrant(ctx, req); err != nil {
errs = append(errs, err)
}
}
return errs
}
func isContainsIds(els []interface{}, el interface{}) bool {
convEl := el.(int)
for _, elOld := range els {

@ -341,6 +341,10 @@ func dataSourceVinsSchemaMake() map[string]*schema.Schema {
Computed: true,
Description: "type",
},
"vnc_password": {
Type: schema.TypeString,
Computed: true,
},
"vins": {
Type: schema.TypeList,
Computed: true,
@ -2509,6 +2513,10 @@ func resourceVinsSchemaMake() map[string]*schema.Schema {
Computed: true,
Description: "type",
},
"vnc_password": {
Type: schema.TypeString,
Computed: true,
},
"vins": {
Type: schema.TypeList,
Computed: true,
@ -3389,7 +3397,6 @@ func resourceStaticRouteSchemaMake() map[string]*schema.Schema {
"compute_ids": {
Type: schema.TypeList,
Computed: true,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
},

@ -43,6 +43,7 @@
- extnet_computes_list
- extnet_default
- extnet_list
- extnet_reserved_ip_list
- flipgroup
- flipgroup_list
- image
@ -157,6 +158,7 @@
- cb_extnet
- cb_extnet_default
- cb_extnet_list
- cb_extnet_reserved_ip_list
- cb_extnet_static_route
- cb_extnet_static_route_list
- cb_flipgroup
@ -169,7 +171,6 @@
- cb_grid_list
- cb_grid_list_consumption
- cb_grid_list_emails
- cb_grid_post_diagnosis
- cb_grid_post_status
- cb_image
- cb_image_list

@ -1,6 +1,6 @@
/*
Пример использования
Получение снимка платформы с дополнительной диагностической информацией, такой как журналы и т.д.
Получение информации о зарезервированных IP адресах или пуле адресов
*/
#Расскомментируйте этот код,
@ -26,14 +26,18 @@ provider "decort" {
allow_unverified_ssl = true
}
data "decort_cb_grid_post_diagnosis" "grid" {
#id grid для получения информации
#обязательный параметр
data "decort_extnet_reserved_ip_list" "ex_reserved_ip" {
#идентификатор аккаунта, для которого зарезервированны ресурсы
#обязательный параметр
#тип - целое число
gid = 215
account_id = 1111
#идентификатор сети
#опциональный параметр
#тип - целое число
#extnet_id = 1111
}
output "test" {
value = data.decort_cb_grid_post_diagnosis.grid
value = data.decort_extnet_reserved_ip_list.ex_reserved_ip
}

@ -396,6 +396,11 @@ resource "decort_kvmvm" "comp" {
#тип - булев
pin_to_stack = true
#флаг для старта компьюта при рестарте ноды
#опциональный параметр
#тип - булев
auto_start_w_node = true
#флаг доступности компьюта для проведения с ним операций
#опциональный параметр
#тип - булев

@ -52,12 +52,6 @@ resource "decort_vins_static_route" "sr" {
#обязательный параметр
#тип - строка
gateway = "192.168.201.40"
#список виртуальных машин, которым будет предоставлен доступ к роуту
#опциональный параметр
#тип - массив целых чисел
compute_ids = [111, 222]
}
output "sr" {

@ -0,0 +1,43 @@
/*
Пример использования
Получение информации о зарезервированных IP адресах или пуле адресов
*/
#Расскомментируйте этот код,
#и внесите необходимые правки в версию и путь,
#чтобы работать с установленным вручную (не через hashicorp provider registry) провайдером
/*
terraform {
required_providers {
decort = {
source = "basis/decort/decort"
version = "<VERSION>"
}
}
}
*/
provider "decort" {
authenticator = "decs3o"
#controller_url = <DECORT_CONTROLLER_URL>
controller_url = "https://ds1.digitalenergy.online"
#oauth2_url = <DECORT_SSO_URL>
oauth2_url = "https://sso.digitalenergy.online"
allow_unverified_ssl = true
}
data "decort_cb_extnet_reserved_ip_list" "ex_reserved_ip" {
#идентификатор аккаунта, для которого зарезервированны ресурсы
#обязательный параметр
#тип - целое число
account_id = 1111
#идентификатор сети
#опциональный параметр
#тип - целое число
#extnet_id = 1111
}
output "test" {
value = data.decort_cb_extnet_reserved_ip_list.ex_reserved_ip
}

@ -168,6 +168,26 @@ resource "decort_cb_extnet" "new_extnet" {
#e_rate = 0
}
#список зарезервированных IP или пула адресов
#опциональный параметр
#тип - блок
reserved_ip {
#идентификатор аккаунта, для которого резервируются ресурсы
#обязательный параметр
#тип - целое число
account_id = 11111
#количество резервируемых IP
#опциональный параметр
#тип - целое число
ip_count = 15
#список резервируемых IP
#опциональный параметр
#тип - массив строк
ips = ["192.168.10.10", "192.168.10.20"]
}
#ID stack на который происходит миграция
#опциональный параметр
#тип - целое число

@ -32,6 +32,10 @@ data "decort_cb_grid_get_diagnosis" "grid" {
#тип - целое число
gid = 215
#путь, где будет создан архив, если не указан, создается в директории с main.tf с именем "diagnosis.tar.gz"
#обязательный параметр
#тип - строка
file_path = "abcdefg.tar.gz"
}
output "test" {

@ -66,6 +66,21 @@ data "decort_cb_kvmvm_list" "compute_list" {
#тип - строка
#ip_address = "test"
#фильтр по stack id
#опциональный параметр
#тип - целое число
#stack_id = 123
#фильтр по image id
#опциональный параметр
#тип - целое число
#image_id = 123
#фильтр по cd image id
#опциональный параметр
#тип - целое число
#cd_image_id = 123
#фильтр по имени extnet
#опциональный параметр
#тип - строка

@ -409,6 +409,11 @@ resource "decort_cb_kvmvm" "comp" {
#тип - булев
#pin_to_stack = true
#флаг для старта компьюта при рестарте ноды
#опциональный параметр
#тип - булев
#auto_start_w_node = true
#id stack для добавления компьюта на этот стэк
#опциональный параметр
#тип - целое число

@ -51,12 +51,6 @@ resource "decort_cb_vins_static_route" "sr" {
#обязательный параметр
#тип - строка
gateway = "192.168.201.40"
#список виртуальных машин, которым будет предоставлен доступ к роуту
#опциональный параметр
#тип - массив целых чисел
#compute_ids = [111,222]
}
output "sr" {

@ -0,0 +1,7 @@
DECORT Terraform Provider версии 4.8.x позволяет управлять облачными ресурсами на платформе Digital Energy Cloud Orchestration Technology (DECORT) версии 4.2.x и выше посредством Terraform.
С помощью данного провайдера можно организовать программное управление вычислительными ресурсами (_compute_), ресурсными группами, сетевыми и дисковыми ресурсами, образами дисков, кластером, а также другими параметрами облачной платформы DECORT.
Если вы хорошо знакомы с инструментом Terraform и хотите максимально быстро начать использовать платформу DECORT в своих Terraform-проектах, то можете сразу перейти к разделу [Пример работы](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/02.-Пример-работы.md), где приведён подробно откомментированный пример работы с основными видами ресурсов платформы. Если у вас всё же возникнут вопросы по облачной платформе DECORT и порядку авторизации в ней, то обратитесь к главе [«Обзор облачной платформы DECORT»](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT.md). Также может оказаться полезной глава [«Инициализация Terraform провайдера DECORT»](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/04.02-Инициализация-Terraform-провайдера-DECORT.md).
Если вы только начинаете использовать инструмент Terraform и облачную платформу DECORT, то рекомендуем вам начать с главы [«Обзор облачной платформы DECORT»](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT.md), после чего изучить главы [«_Data source_ функции Terraform провайдера DECORT»](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/06.-Data-source-функции-Terraform-провайдера-DECORT.md) и [«_Resource_ функции Terraform провайдера DECORT»](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/07.-Resource-функции-Terraform-провайдера-DECORT.md). Примеры, приведенные в этих разделах, помогут вам быстро освоить базовые приёмы работы с инструментом Terraform и провайдером DECORT.

@ -0,0 +1,92 @@
Данный раздел предназначен для тех, кто хорошо знаком с инструментом Terraform, а также имеет представление об основных понятиях и способах авторизации в облачной платформе DECORT.
Ниже приведён подробно откомментированный пример, показывающий, как создать виртуальный сервер (aka _compute_ на базе системы виртуализации KVM x86) в облачной платформе DECORT с помощью соответствующего Terraform провайдера. Сервер будет создан в новой ресурсной группе, к нему будет подключён один предварительно созданный диск, у сервера будет прямое сетевое подключение во внешнюю сеть.
Идентификатор образа операционной системы, на базе которого должен быть создан виртуальный сервер, считывается из облачной платформы с помощью _data source_ функции `decort_image`.
Далее мы с помощью _resource_ функции `decort_resgroup` создаём новую ресурсную группу, в которую будет помещён этот виртуальный сервер. В качестве альтернативы, для получения информации об уже имеющейся ресурсной группе можно использовать _data source_ функцию с таким же названием.
Затем с помощью _resource_ функции `decort_disk` создаётся диск, который будет подключён к виртуальному серверу в качестве дополнительного. Помимо этого дополнительного диска у сервера будет также и загрузочный диск, на который в процессе создания сервера клонируется выбранный образ операционной системы.
Виртуальный сервер - в данном примере на базе системы виртуализации KVM x86 - создаётся посредством _resource_ функции `decort_kvmvm`.
Только авторизованные в контроллере облачной платформы пользователи могут управлять облачными ресурсами. Подробнее о способах авторизации см. [Обзор облачной платформы DECORT](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT.md).
```terraform
# 1. Initialize DECORT plugin and connection to DECORT cloud controller
# NOTE: in this example credentials are expected to come from
# DECORT_APP_ID and DECORT_APP_SECRET environmental variables - set them
# in the shell before calling terraform.
# Alternatively you may define plugin parameters app_id and app_secret in
# the TF file, however, this may not be secure if you plan to share this TF
# file with others.
provider "decort" {
authenticator = "decs3o"
controller_url = "<<DECORT_CONTROLLER_URL>>" # specify correct DECORT controller URL, e.g. "https://ds1.digitalenergy.online"
oauth2_url = "<<DECORT_OAUTH2_URL>>" # specify corresponding DECORT OAUTH2 URL, e.g. "https://sso.digitalenergy.online"
app_id = "<<DECORT_APP_ID>>" # application secret to access DECORT cloud API in 'decs3o' and 'bvs' authentication mode, e.g. "ewqfrvea7s890avw804389qwguf234h0otfi3w4eiu"
app_secret = "<<DECORT_APP_SECRET>>" # application ID to access DECORT cloud API in 'decs3o' and 'bvs' authentication mode, e.g. "ewqfrvea7s890avw804389qwguf234h0otfi3w4eiu"
# allow_unverified_ssl = true
}
# 2. Load account to use - new VM will belong to this account
data "decort_account" "my_account" {
account_id = <ACCOUNT_ID> # Specify account ID
}
# 3. Load OS image to use for VM deployment
data "decort_image" "os_image" {
image_id = <OS_IMAGE_ID> # Specify OS image id, e.g. 1234. You can get accessible image id from data source "decort_image_list"
}
# 4. Create new Resource Group in the selected account, new VM will be created in this RG
resource "decort_resgroup" "my_rg" {
name = "NewRgByTF"
account_id = data.decort_account.my_account.account_id
gid = <GRID_ID> # Grid (platform) ID
# if you want to set resource quota on this Resource Group, uncomment
# the following code fragment
# quota {
# cpu = 8 # CPU limit
# ram = 8912 # RAM limit in MB
# disk = 96 # disk volume limit in GB
#}
}
# 5. Create extra disk, which will be attached to the new VM.
# This step is optional - if you do not want extra disks on your VM, skip it
# and comment out extra_disks parameter when creating VM below.
resource "decort_disk" "extra_disk" {
disk_name = "extra-disk-for-vm"
account_id = data.decort_account.my_account.account_id
gid = <GRID_ID> # Grid (platform) ID
size_max = 5 # disk size in GB
type = "D" # disk type, always use "D" for extra disks
sep_id = data.decort_image.os_image.sep_id # use the same SEP ID as the OS image
pool = "<<DATA_POOL_NAME>>" # consult your DECORT platform admin for configured storage pool names
}
# 6. Create virtual machine (a compute of type KVM VM x86 in this example)
# Now that we have all necessary components at hand, we may create a virtual machine.
# This VM will be based on the previsouly obtained OS image, located in the specified
# Resource Group, directly connected to an external network, have a boot disk of
# specified size and one extra disk attached.
resource "decort_kvmvm" "my_new_vm" {
name = "tf-managed-vm"
driver = "KVM_X86" # Compute virtualization driver
rg_id = decort_resgroup.my_rg.id
cpu = 1 # CPU count
ram = 1024 # RAM size in MB, must be even number, ideally a power of 2
boot_disk_size = 10 # Boot disk size in GB
image_id = data.decort_image.os_image.image_id
description = "Test KVM VM Compute managed by Terraform"
extra_disks = [ decort_disk.extra_disk.id ]
network {
net_type = "EXTNET"
net_id = <<EXT_NET_ID>> # specify external network ID to use, consult your DECORT platform admin for correct IDs
# ip_address = "<<SOME VALID AND FREE IP ADDRESS>>" # you may optionally request a specific IP address
}
}
```

@ -0,0 +1,31 @@
## Основные понятия
Ниже перечислены основные понятия с указанием соответствующих им аргументов в Terraform провайдере DECORT.
1. **Контроллер облачной платформы DECORT** управляющее приложение, которое обеспечивает авторизацию пользователей и оркестрацию облачных ресурсов.
- Адрес контроллера задается в обязательном аргументе `controller_url` на стадии инициализации Terraform провайдера DECORT. Например, `controller_url= "https://ds1.digitalenergy.online"`
2. **Авторизационный провайдер** приложение, работающее по протоколу Oauth2, предназначенное для выпуска и валидации токенов доступа к контроллеру облачной платформы в соответствующих режимах авторизации. Все действия в платформе должны выполняться авторизованными пользователями, и авторизационное приложение позволяет получить токен доступа, действующий некоторое ограниченное время, наличие которого подтверждает успешную авторизацию.
- Адрес авторизационного провайдера задается в аргументе`oauth2_url` на стадии инициализации Terraform провайдера DECORT. Например `oauth2_url= "https://sso.digitalenergy.online"`
3. **Подписчик** (_account_) сущность, которая используется для группирования облачных ресурсов по принадлежности к определенному клиенту для целей учета потребления и биллинга.
- Имя подписчика задается аргументом `account_name` при вызове _resource_ или _data_ функций провайдера. Альтернативной является задание численного идентификатора подписчика в аргументе `account_id`.
4. **Пользователь** (_user_) пользователь облачной инфраструктуры, представленный учетной записью. Чтобы получить возможность управлять облачными ресурсами (например, создавать виртуальные серверы или дискт) пользователь должен быть ассоциирован с одним или несколькими подписчиками и иметь соответствующие права, определяемые ролевой моделью, принятой в облачной платформе DECORT. Для доступа к платформе пользователь должен авторизоваться одним из способов, описанных ниже в разделе «Способы авторизации».
5. **Ресурсная группа** (_resource group_) способ группирования вычислительных ресурсов (например, виртуальных серверов по функциональному признаку или принадлежности к одному и тому же проекту). Ресурсную группу можно рассматривать как небольшой персональный дата-центр, в котором размещаются один или несколько серверов и виртуальных сетевых сегментов. Ресурсная группа идентифицируется по комбинации параметров `account` и `name`. Обратите внимание, что имя имя ресурсной группы уникально только в рамках одного и того же `account`.
6. **Вычислительный ресурс** (_compute_) - универсальная абстракция пользовательского сервера в платформе DECORT. Благодаря использованию такой абстракции можно, например, создать одну виртуальную машину на базе KVM Intel x86, а другую - на базе KVM IBM Power, а потом управлять ими - изменять количество CPU/RAM, подключать/отключать диски и т.п. - одинаковым образом, не задумываясь об их архитектурных различиях. В то же время, так как типизация ресурсов в Terraform не поддерживает наследование, различные типы вычислительных ресурсов, доступных на платформе DECORT и абстрагируемых через понятие унифицированный _compute_, в Terraform представлены разными типами (напр., свой тип для виртуальных серверов на базе KVM и свой тип для перспективных x86-совместимых bare metal серверов).
7. **Ресурс хранения** (_disk_) - универсальная абстракция дискового ресурса в платформе DECORT. Платформа поддерживает различные типы систем хранения данных, но при этом управление созданными на разных системах хранения дисками осуществляется посредством унифицированного набора действий, например, "подключить диск к _compute_", "увеличить размер диска", "сделать мгновенный снимок диска", "настроить параметры быстродействия диска".
8. **Виртуальный сервер** экземпляр _compute_, в основе технической реализации которого лежит виртуальная машина, работающая в облаке DECORT и доступна по сети. Виртуальный сервер характеризуется количеством выделенных ему CPU (аргумент`cpu`), объемом ОЗУ (`ram`), размером загрузочного диска (`boot_disk size`). При создании виртуального сервера на загрузочный диск устанавливается образ операционной системы, заданный в аргументе `image_id`. Помимо загрузочного диска к виртуальному серверу можно подключить несколько дисков для хранения прикладных данных, список которых задается аргументами `extra_disks`. Виртуальный сервер идентифицируется по комбинации аргументов `name` (имя сервера) и `rgid` (идентификатор ресурсной группы). Обратите внимание, что имя виртуального сервера `name` уникально только в рамках одной и той же ресурсной группы.
9. **Виртуальный сетевой сегмент** (_Virtual Network Segment_ или _ViNS_) - сетевой сегмент и обеспечивающая его функционирование виртуальная инфраструктура, которые пользователь может создавать для своих нужд на уровне ресурсной группы или подписчика (_account_). ViNS можно создать полностью изолированным от внешних сетей (см. ниже _External Network_) или с подключением во внешнюю сеть. Внутри ViNS работает DHCP-сервис, обеспечивающий управление IP адресами экземпляров _compute_, подключённых в этот ViNS.
10. **Внешняя сеть** (_External Network_) - сетевой сегмент, через который платформа DECORT взаимодействует с внешними по отношению к ней сетевыми ресурсами. Например, в случае с публичным облаком на базе DECORT в качестве внешней сети выступает сеть Интернет. В отличие от ViNS платформа не управляет внешней сетью, а лишь пользуется её ресурсами. В платформе может быть настроено несколько внешних сетей с различными диапазонами IP адресов, и существует механизм управления доступом пользователей к внешним сетям.
11. Сетевой доступ к экземпляру _compute_ (виртуальному серверу) реализуется через его подключение к ViNS и/или прямое подключение во внешнюю сеть (External Network). Один и тот же экземпляр _compute_ может одновременно иметь несколько подключений в разные ViNS и/или различные внешние сети.
## Способы авторизации
Облачная платформа DECORT поддерживает три базовых типа авторизации:
1. С использованием авторизационного провайдера, работающего по протоколу _Oauth2_. Данный способ является предпочтительным, так как обеспечивает бОльшую гибкость и безопасность. Для авторизации в этом режиме при инициализации Terrafrom провайдера DECORT необходимо указать параметры `oauth2_url` и `controller_url`, а также предоставить одно из нижеперечисленного:
- Комбинация Application ID & Application secret, соответствующих пользователю, от имени которого будет осуществляться управление облачными ресурсами в текущей сессии. В процессе проверки предоставленных Application ID & Application secret модуль получает от авторизационного провайдера токен (JSON Web Token, JWT), который затем используется для доступа к указанному контроллеру DECORT. Для авторизации по данному варианту, при инициализации Terraform провайдера DECORT следует установить аргумент `authenticator=decs3o` и задать аргументы `app_id` и `app_secret` (или определить соответствующие переменные окружения `DECORT_APP_ID` и `DECORT_APP_SECRET`).
- JSON Web Token заранее полученный от авторизационного провайдера токен доступа, ассоциированный с определенным пользователем, от имени которого будет осуществляться управление облачными ресурсами в текущей сессии. Для авторизации по данному варианту, при инициализации Terraform провайдера DECORT следует установить аргумент `authenticator=jwt` и задать аргумент `jwt` (или определить переменную окружения `DECORT_JWT`).
2. С использованием комбинации _имя пользователя : пароль_. Данный режим не использует внешних авторизационных провайдеров и подразумевает, что пользователь с такой комбинацией зарегистрирован непосредственно на указанном в параметре `controller_url` контроллере облачной платформы DECORT.
- Чтобы провайдер авторизовался по данному варианту, при его инициализации следует установить аргумент `authenticator=legacy` и задать аргументы `user` и `password` (или определить соответствующие переменные окружения `DECORT_USER` и `DECORT_PASSWORD`).
3. С использованием авторизационного провайдера, работающего по протоколу _Oauth2_oidc_. Для авторизации в этом режиме при инициализации Terrafrom провайдера DECORT необходимо указать параметры `oauth2_url` и `controller_url`, а также Application ID & Application secret, _имя пользователя и пароль_, соответствующих пользователю, от имени которого будет осуществляться управление облачными ресурсами в текущей сессии, и _имя домена_. В процессе проверки предоставленных Application ID & Application secret и пары _имя пользователя-пароль_ модуль получает от авторизационного провайдера токен (JSON Web Token, JWT), который затем используется для доступа к указанному контроллеру DECORT. Для авторизации по данному варианту, при инициализации Terraform провайдера DECORT следует установить аргумент `authenticator=bvs`, задать аргументы `app_id` и `app_secret` (или определить соответствующие переменные окружения `DECORT_APP_ID` и `DECORT_APP_SECRET`), `bvs_user` и `bvs_password` (или определить соответствующие переменные окружения `DECORT_BVS_USER` и `DECORT_BVS_PASSWORD`), а также указать `domain` (или определить соответствующие переменные окружения `DECORT_DOMAIN`).
После успешной авторизации пользователь (или приложение-клиент) получает доступ к ресурсам, находящимся под управлением соответствующего DECORT контроллера. Доступ предоставляется в рамках подписчиков (_account_), с которыми ассоциирован данный пользователь (_user_), и в соответствии с присвоенными ему ролями.
## Пользовательская и административная группы API
Пользовательская группа API - группа API платформы DECORT, которая позволяет выполнять операции с платформой с правами обычного пользователя. Покрывает большую часть задач.
Административная группа API - группа API платформы DECORT, которая позволяет выполнять операции с платформой с расширенными правами. Данные права подразумевают расширенный перечень операций над ресурсами, расширенный перечень ресурсов, расширенную информацию. Требуются права администратора для взаимодействия с этой группой API.

@ -0,0 +1,6 @@
Данный раздел описывает:
- Системные требования
- Установку провайдера
- Инициализацию провайдера
- Переключение режима работы между разными группами API
- Получение gid/grid_id площадки

@ -0,0 +1,150 @@
## Системные требования
Для запуска провайдера вам потребуется машина, на которой установлен Terraform.
Кроме того, в связи с тем, что начиная с версии 0.12 Terraform изменил алгоритм поиска и инициализации локальных провайдеров, настройка данного провайдера для работы с Terraform 0.12 или более новыми версиями потребует выполнения ряда дополнительных действий. Подробнее см. [8.3 Настройка локального провайдера для работы с новыми версиями Terraform](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/08.-Полезные-советы#user-content-8-3-настройка-локального-провайдера-для-работы-с-новыми-версиями-terraform.md).
## Установка
Начиная с версии провайдера `4.3.0` в релизном архиве находятся скрипты-инсталляторы.
Чтобы выполнить установку, необходимо:
1. Перейти по адресу: https://repository.basistech.ru/BASIS/terraform-provider-decort/releases
2. Выбрать необходимую версию провайдера подходящую под операционную систему.
3. Скачать архив.
4. Распаковать архив.
5. Выполнить скрипт установщика, `install.sh` или `install.bat` для Windows.<br/>
*Для запуска `install.sh` не забудьте изменить права доступа к файлу*
```bash
chmod u+x install.sh
```
6. Дождаться сообщения об успешной установке. Установщик выведет актуальный блок конфигурации провайдера, скопируйте его
```bash
DECORT provider version 4.3.0 has been successfully installed
Copy this provider configuration to main.tf file:
terraform {
required_providers {
decort = {
version = "4.3.0"
source = "basis/decort/decort"
}
}
}
```
7. После этого, создайте файл `main.tf` в рабочей директории, которая может находится в любом удобном для пользователя месте.
В данном примере, рабочая директория с файлом main.tf находится по пути:
```bash
~/work/tfdir/main.tf
```
8. Вставьте в `main.tf` блок конфигурации провайдера, который был выведен на экран установщиком:
```terraform
terraform {
required_providers {
decort = {
version = "4.3.0"
source = "basis/decort/decort"
}
}
}
```
9. Добавьте в файл блок с инициализацией провайдера.
```terraform
provider "decort" {
authenticator = "decs3o"
controller_url = "https://mr4.digitalenergy.online"
oauth2_url = "https://sso.digitalenergy.online"
allow_unverified_ssl = true
}
```
10. В консоли выполните команду
```bash
terraform init
```
11. В случае успешной установки, Terraform инициализирует провайдер и будет готов к дальнейшей работе.
## Установка из релизов
Terraform провайдер DECORT имеет скомпилированные релизные версии, которые расположены по адресу: [Релизы](https://repository.basistech.ru/BASIS/terraform-provider-decort/releases).
Чтобы выполнить установку из релиза, необходимо:
1. Перейти по адресу: https://repository.basistech.ru/BASIS/terraform-provider-decort/releases
2. Выбрать необходимую версию провайдера подходящую под операционную систему.
3. Скачать архив.
4. Распаковать архив.
5. Полученный файл (в директории `bin/`) необходимо поместить:
Linux:
```bash
~/.terraform.d/plugins/${host_name}/${namespace}/${type}/${version}/${target}
```
Windows:
```powershell
%APPDATA%\terraform.d\plugins\${host_name}\${namespace}\${type}\${version}\${target}
```
Где:
- host_name - имя хоста, держателя провайдера, например, basis
- namespace - пространство имен хоста, например decort
- type - тип провайдера, может совпадать с пространством имен, например, decort
- version - версия провайдера, например 4.3.0
- target - архитектура операционной системы, например windows_amd64
В примере ниже используется путь до провайдера на машине с ОС Linux:
```bash
~/.terraform.d/plugins/basis/decort/decort/4.3.0/linux_amd64/tf-provider
^ ^ ^ ^ ^ ^
host_name | | | | | |
| | | | |
namespace | | | | |
| | | |
type | | | |
| | |
version | | |
| |
target | |
|
исполняемый файл |
```
6. После этого, создайте файл `main.tf` в рабочей директории, которая может находится в любом удобном для пользователя месте.
В данном примере, рабочая директория с файлом main.tf находится по пути:
```bash
~/work/tfdir/main.tf
```
7. Добавьте в `main.tf` следующий блок
```terraform
terraform {
required_providers {
decort = {
version = "4.3.0"
source = "basis/decort/decort"
}
}
}
```
В поле `version` указывается версия провайдера.
<br/>
**ВНИМАНИЕ: Версии в блоке и в пути к исполняемому файлу провайдера должны совпадать!**
В поле `source` помещается путь до репозитория с версией вида:
```bash
${host_name}/${namespace}/${type}
```
**ВНИМАНИЕ: Версии в блоке и в пути к исполняемому файлу провайдера должны совпадать!**
8. Добавьте в файл блок с инициализацией провайдера.
```terraform
provider "decort" {
authenticator = "decs3o"
controller_url = "https://mr4.digitalenergy.online"
oauth2_url = "https://sso.digitalenergy.online"
allow_unverified_ssl = true
}
```
9. В консоли выполните команду
```bash
terraform init
```
10. В случае успешной установки, Terraform инициализирует провайдер и будет готов к дальнейшей работе.

@ -0,0 +1,64 @@
## Список аргументов для инициализации
Перед началом использования любой Terraform провайдер должен быть инициализирован.
В процессе инициализации Terraform провайдера DECORT проверяется корректность переданных аргументов и выполняется авторизация в указанном контроллере облачной инфраструктуры. Подробнее о способах авторизации в платформе DECORT смотри соответствующий [раздел](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT#user-content-способы-авторизации.md).
При инициализации Terraform провайдера DECORT используются следующие аргументы:
| Аргумент | Переменная окружения | Описание |
| --- | --- | --- |
| allow_unverified_ssl | - | Если данный аргумент явно установлен в `true`, то провайдер **не будет** проверять SSL сертификаты при взаимодействии с авторизационным сервисом OAuth2 и контроллером облачной платформы.<br>Отключение проверок может быть полезным при работе в доверенной среде, использующей самоподписанные SSL сертификаты. Однако, так как отключение проверок несёт потенциальные риски безопасности, данную настройку следует использовать с осторожностью.<br/>Разрешённые значения: `false` (значение по умолчанию) и `true`. |
| app_id | DECORT_APP_ID | Идентификатор приложения (клиента) для авторизации в контроллере облачной платформы в режиме `decs3o` или `bvs`.<br> Аргументы `app_id` и `app_secret` являются обязательными для режимов авторизации `authenticator=decs3o` и `authenticator=bvs`.<br>Если `app_id` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_APP_ID`. |
| app_secret | DECORT_APP_SECRET | Секретный код приложения (клиента) для авторизации в контроллере облачной платформы в режиме `decs3o` или `bvs`.<br> Аргументы `app_id` и `app_secret` являются обязательными для режимов авторизации `authenticator=decs3o` и `authenticator=bvs`.<br>Если `app_secret` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_APP_SECRET`. |
| authenticator | - | Режим авторизации при подключении к контроллеру облачной платформы.<br/>Доступные режимы: `decs3o`, `legacy`, `jwt` или `bvs`.<br>Данный аргумент является обязательным. |
| bvs_user | DECORT_BVS_USER | Имя пользователя для авторизации в контроллере облачной платформы в режиме `bvs`.<br>Аргументы `bvs_password` и `bvs_user` являются обязательными для режима авторизации `authenticator=bvs`.<br>Если `bvs_user` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_BVS_USER`. |
| bvs_password | DECORT_BVS_PASSWORD | Пароль пользователя для авторизации в контроллере облачной платформы в режиме `bvs`.<br>Аргументы `bvs_user` и `bvs_password` являются обязательными для режима авторизации `authenticator=bvs`.<br>Если `bvs_password` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_BVS_PASSWORD`. |
| domain | DECORT_DOMAIN | Имя домена в контроллере облачной платформы в режиме `bvs`.<br>Данный аргумент является обязательным.<br>Если `domain` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_DOMAIN`. |
| controller_url | DECORT_CONTROLLER_URL | URL контроллера облачной платформы, через который будет осуществляться управление облачными ресурсами.<br>Данный аргумент является обязательным. |
| jwt | DECORT_JWT | JSON Web Token (JWT), который используется для авторизации в контроллере облачной платформы в режиме `jwt`.<br>Данный аргумент является обязательным для режима авторизации `authenticator=jwt`.<br>Если `jwt` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_JWT` |
| oauth2_url | DECORT_OAUTH2_URL | URL авторизационного сервиса OAuth2, который используется для управления доступом пользователей (или программных клиентов) к контроллеру облачной платформы.<br>Данный аргумент является обязательным для режимов авторизации `authenticator=decs3o`, `authenticator=bvs` и `authenticator=jwt`.<br>Если `oauth2_url` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_OAUTH2_URL` |
| password | DECORT_PASSWORD | Пароль для авторизации в контроллере облачной платформы в режиме `legacy`.<br> Аргументы `password` и `user` являются обязательными для режима авторизации `authenticator=legacy`.<br>Если `password` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_PASSWORD`. |
| user | DECORT_USER | Имя пользователя для авторизации в контроллере облачной платформы в режиме `legacy`.<br> Аргументы `user` и `password` являются обязательными для режима авторизации `authenticator=legacy`.<br>Если `user` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_USER`. |
## Пример инициализации в режиме авторизации `decs3o`
Пример инициализации Terraform провайдера DECORT:
```terraform
provider "decort" {
authenticator = "decs3o"
controller_url = "https://ctrl.decort.online"
oauth2_url = "https://oauth2.decort.online:7777"
}
```
В данном примере используется режим авторизации `decs3o`.
Как отмечено выше, в данном режиме требуется указать аргументы `app_id` и `app_secret`, идентифицирующие пользователя (или приложение-клиент), от лица которого будут выполняться дальнейшие действия. Однако, так как данная информация является конфиденциальной (по сути, она эквивалентна паре _имя пользователя : пароль_), то в общем случае заносить такого рода данные в tf-файл не следует. Рекомендуется определять в среде запуска Terraform переменные окружения `DECORT_APP_ID` и `DECORT_APP_SECRET`, из которых провайдер извлечёт нужные данные. Приведенный пример подразумевает, что нужная информация будет получена из этих переменных окружения.
Пользователь, от лица которого Terrafrom будет выполнять действия в облачной платформе, должен заранее создать пару _Application ID_ и _Application Secret_ в авторизационном приложении OAuth2. Именно эти значения, а также URL авторизационного приложения Oauth2, должны присваиваться аргументам `app_id`, `app_secret` и `oauth2_url` соответственно для успешной инициализации провайдера.
Также обратите внимание на формат задания аргументов `controller_url` и `oauth2_url`. В общем случае они должны содержать идентификатор протокола (_https://_) и сетевой порт, если он отличается от порта по умолчанию (в примере для авторизационного сервиса OAuth2 указан порт _7777_). Эту информацию вы можете узнать у администратора вашей облачной инфраструктуры DECORT.
## Пример инициализации в режиме авторизации `bvs`
Пример инициализации Terraform провайдера DECORT:
```terraform
provider "decort" {
authenticator = "bvs"
controller_url = "https://delta.qa.loc"
oauth2_url = "https://bvs-delta.qa.loc:8443"
app_id = "delta"
app_secret = ""
bvs_password = ""
bvs_user = ""
domain = "dynamix"
}
```
В данном примере используется режим авторизации `bvs`.
Как отмечено выше, в данном режиме требуется указать аргументы `app_id` - идентификатор площадки - delta, alpha, poc, etc. Можно найти на странице администратора по следующему пути: вкладка безопасность - клиентские сервисы - наименование площадки. `app_secret` - пароль площадки. Можно найти на странице администратора по следующему пути: вкладка безопасность - клиентские сервисы - наименование площадки (символ i) - поле "Пароль". Однако, так как данная информация является конфиденциальной, то в общем случае заносить такого рода данные в tf-файл не следует. Рекомендуется определять в среде запуска Terraform переменные окружения `DECORT_APP_ID` и `DECORT_APP_SECRET`, из которых провайдер извлечёт нужные данные. Приведенный пример подразумевает, что нужная информация будет получена из этих переменных окружения.
Также обязательными аргументами являются: `bvs_user` - имя пользователя, `bvs_password` - пароль пользователя. Рекомендуется не заносить их в tf-файл, а определять в среде запуска Terraform переменные окружения `DECORT_BVS_USER` и `DECORT_BVS_PASSWORD`, из которых провайдер извлечёт нужные данные. Приведенный пример подразумевает, что нужная информация будет получена из этих переменных окружения.
Домен для подключения `domain` - указывается наименование площадки. Данный аргумент является обязательным. Рекомендуется не заносить его в tf-файл, а определять в среде запуска Terraform переменную окружения `DECORT_DOMAIN`, из которой провайдер извлечёт нужные данные. Приведенный пример подразумевает, что нужная информация будет получена из этих переменных окружения.
Пользователь, от лица которого Terrafrom будет выполнять действия в облачной платформе, должен заранее получить от администратора _Application ID_ и _Application Secret_, _bvs user_ и _bvs password_, а также _domain_. А также осуществить первичный вход на платформу посредством браузера.
Также обратите внимание на формат задания аргументов `controller_url` и `oauth2_url`. В общем случае они должны содержать идентификатор протокола (_https://_) и сетевой порт, если он отличается от порта по умолчанию (в примере для авторизационного сервиса OAuth2 указан порт _8443_). Эту информацию вы можете узнать у администратора вашей облачной инфраструктуры DECORT.

@ -0,0 +1,38 @@
Так как платформа DECORT предоставляет для работы две группы API, то terraform провайдер позволяет свободно переключать режимы работы между этими группами.
По умолчанию стоит пользовательская группа API. Ее можно сменить на административную группу.
Если прав у пользователя будет достаточно, то запрос будет выполнен, если нет, то будет ошибка:
```bash
Permission denied
```
Которая говорит о том, что прав недостаточно. Тогда для выполнения операции обратитесь к администратору платформы.
Установка режима взаимодействия с группами API осуществляется через установку переменной окружения _DECORT_ADMIN_MODE_.
Для более подробного описания возможностей каждой группы API см. соответствующий раздел.
## Переключение режима работы в Windows
Используйте сл. команду:
```Powershell
$Env:DECORT_ADMIN_MODE=1
```
Для отключения:
```Powershell
$Env:DECORT_ADMIN_MODE=0
```
## Переключение режима работы в Linux
Используйте сл. команду:
```bash
DECORT_ADMIN_MODE=1
```
или
```bash
export DECORT_ADMIN_MODE=1
```
Для отключения:
```bash
DECORT_ADMIN_MODE=0
```
или
```bash
export DECORT_ADMIN_MODE=0
```
**ОБРАТИТЕ ВНИМАНИЕ**
Переменные окружения создаются для терминальной сессии. В сл. раз их придется задавать еще раз, если требуется режим, отличный от пользовательского.

@ -0,0 +1,31 @@
Платформа может располагаться на нескольких площадках(grid).
Такие площадки имеют свой id.
Для создания некоторых ресурсов требуется ввести grid_id или gid площадки.
Получение gid различается для пользовательского и административного API.
## Получение gid для пользовательского API
Для получения gid с помощью пользовательского API, необходимо получить информацию из _data_source_ функции _decort_locations_list_, как указано ниже:
```terraform
data "decort_locations_list" "ll" {
}
output "test" {
value = data.decort_locations_list.ll
}
```
В файл состояния будет сохранен результат, где можно посмотреть доступные для работы площадки.
## Получение gid для административного API
Для получения gid с помощью административного API, необходимо получить информацию из _data_source_ функции _decort_grid_list_, как указано ниже:
```terraform
data "decort_grid_list" "gl" {
}
output "test" {
value = data.decort_grid_list.gl
}
```
В файл состояния будет сохранен результат, где можно посмотреть доступные для работы площадки.

@ -0,0 +1,43 @@
Образ приложения - современный способ запуска приложений. Образ приложения представляет собой контейнер, в который входит ОС и необходимые для работы приложения пакеты.
Способов создать образ приложения довольно много, для этого существуют программы контейнеризации:
- Docker
- Podman
- и другие
Образ представляет собой "зафиксированную" версию приложения, что означает, что никакие изменения в приложения внесены быть не могут. Так же означает то, что приложение не может создавать побочные файлы при работе.
Контейнер - это запущенный экземпляр образа. То есть, один образ может порождать множество контейнеров, каждый из которых будет включать в себя отдельный экземпляр приложения.
Одно из преимуществ работы приложения в контейнере - кроссплатформенность. Это преимущество обуславливается тем, что образ приложения уже включает в себя все необходимое для успешной работы приложения, в том числе операционную систему. Поэтому, пользователю достаточно установить на вычислительной машине программу, которая обеспечивает работу с образами приложений.
## Docker
Docker является одной из самых популярных программ для работы с образами.
Docker позволяет:
- Создавать образы
- Запускать контейнеры
- Управлять контейнерами
- Управлять образами
Скачать и установить Docker можно по ссылке https://docs.docker.com/get-docker/
## Сборка terraform провайдера
### Требования:
- Docker
- git
- Компилятор языка GO
= make
### Установка необходимых программ
1. Компилятор языка GO можно скачать и установить по ссылке: https://go.dev/dl/
2. Docker можно скачать и установить по ссылке выше.
3. Git можно скачать и установить по ссылке: https://git-scm.com/
4. Программа make входит в пакет установленных программ для ОС Linux. Для Windows можно воспользоваться инструкцией со stack overflow: https://stackoverflow.com/questions/32127524/how-to-install-and-use-make-in-windows
### Порядок действий
1. Склонировать репозиторий с провайдером:
```bash
git clone https://github.com/rudecs/terraform-provider-decort.git
```
2. Перейти в директорию со скачанным кодом:
```bash
cd terraform-provider-decort
```
3. Выполнить команду:
```bash
make image
```
В результате выполнения данной последовательности, будет создан docker образ, который содержит в себе приложение terraform, terraform провайдер.

@ -0,0 +1,4 @@
Раздел описывает некоторые практики работы с terraform, которые могут быть полезны пользователю.
Раздел включает в себя следующие статьи:
- Импортирование ресурсов
- Работа с таймаутами

@ -0,0 +1,75 @@
Импортирование ресурсов в terraform позволяет привести в соответствие состояние terraform (.tfstate) к состоянию ресурса в платформе.
Необходимость такого приведения возникает в нескольких случаях:
- Ресурс был создан через портал платформы, работа продолжается через terraform провайдер,
- Ресурс был создан через terraform провайдер, однако был изменен через портал платформы,
- Ресурс был создан через terraform провайдер, однако был изменен другим пользователем через terraform провайдер,
- И так далее
Такие расхождения в состоянии ресурсов нередки, путей их решения несколько:
- Использовать импортирование ресурсов,
- Использовать общие файлы состояний ресурсов, к которым будут иметь доступ все участники, занятые в работе с платформой.
В текущем разделе рассматривается первый вариант.
## Импортирование ресурсов
Импортирование ресурсов позволяет совершить запрос к платформе, чтобы сформировать файл состояния.
Чтобы совершить импортирование ресурсов необходимо ввести сл. команду:
```bash
terraform import <resource-name>.<resource-variable> <resource-id>
```
## Пример
Предположим, что у нас ресурс, описывающий диск:
```terraform
resource "decort_disk" "disk" {
account_id = 121212
gid = 3333
disk_name = "mySuperDisk"
size_max = 100500
}
```
Если запустить команду:
```bash
terraform apply
```
То у нас будет создан новый диск.
Но, такой диск уже есть на площадке и мы хотели бы сформировать .tfstate для этого ресурса.
Поэтому, для начала, необходимо получить список дисков:
```terraform
data "decort_disk_list" "dl"{
}
output "test" {
value = data.decort_disk_list.dl
}
```
В полученных данных необходимо найти требуемый диск, получить его id - параметр disk_id. Пусть это будет - 777777
Теперь можно выполнить импортирование:
```bash
terraform import decort_disk.disk 777777
```
Команда должна успешно завершиться, появиться файл состояний, который позволит манипулировать ресурсом.
## Ошибки при импортировании
При импортировании ресурса может возникнуть сл. ошибка:
```bash
Error: <field-name>: required field is not set
```
Где <field-name> - наименование поля.
Ошибка возникает в том случае, если в описании ресурса отсутствует обязательное поле.
Например:
```terraform
resource "decort_disk" "disk" {
account_id = 121212
gid = 3333
size_max = 100500
}
```
В приведенном выше описании отсутствует поле disk_name, поэтому, при попытке импортирования возникнет ошибка.
Для ее устранения, необходимо выполнить запрос на получение списка дисков, найти недостающее поле, после чего добавить его в описание ресурса.
После этого повторить попытку импортирования.
## Общий алгоритм устранения ошибок
1. Выполнить запрос импортирования
2. В случае ошибки - внести недостающие поля.
3. Повторить п.1.

@ -0,0 +1,100 @@
Terraform провайдер DECORT поддерживает тонкую настройку таймаутов выполнения запросов к платформе. Таймауты необходимы для определения максимального времени выполнения запроса. При превышении этого времени соединение рвется и запрос считается невыполненным.
Таймауты применяются при работе с _resource_ функциями провайдера. _Data source_ функции по-умолчанию имеют таймаут в 20 минут и изменяться не может.
## Стандартные таймауты terraform
| Операция | Время | Описание |
| --- | --- | --- |
| create | 20 минут | Создание ресурса |
| read | 20 минут | Чтение ресурса |
| update | 20 минут | Обновление ресурса |
| delete | 20 минут | Удаление ресурса |
| default | 20 минут | Значение по умолчанию. Устанавливает значение для всех операций |
## Стандартные таймауты провайдера DECORT
В провайдере DECORT таймауты переопределены для того, чтобы уменьшить нагрузку на платформу.
| Операция | Время | Описание |
| --- | --- | --- |
| create | 10 минут | Создание ресурса |
| read | 5 минут | Чтение ресурса |
| update | 5 минут | Обновление ресурса |
| delete | 5 минут | Удаление ресурса |
| default | 5 минут | Значение по умолчанию. Устанавливает значение для всех операций |
## Установка таймаутов
Все таймауты можно установить самостоятельно для каждого ресурса.
Для этого используется блок _timeouts_, который имеется в каждом ресурсе провайдера.
Пример:
```terraform
resource "decort_res" "res_name" {
timeouts {
create = "10m"
update = "1m"
delete = "2m"
read = "7m"
#default = "15m"
}
}
```
Где:
- create - операция создания ресурса
- read - операция чтения ресурса
- update - операция обновления ресурса
- delete - операция удаления ресурса
- default - установит заданное время для всех операций
## Формат установления времени
Как видно из примера выше, провайдер принимает на вход строку вида:
```
"<time-num><time-val>"
```
Где:
- time-num - число
- time-val - сокращенная запись значения временного отрезка.
Таблица с временными отрезками:
| Отрезок | Значение |
| --- | --- |
| n | наносекунда |
| ms | миллисекунда |
| s | секунда |
| m | минута |
| h | час |
Примеры:
```
"10m"
"1s"
"1h10m"
```
И так далее
## Работа с таймером через .tf-файл
В .tf-файле, в блоке ресурса можно задавать таймауты для операций над ресурсом, однако, при работе с таймаутом, следует помнить о правиле:
__В случае изменения таймаутов в .tf-файле, операции с новыми таймаутами будут производиться только после apply/plan/destroy__
То есть, если изменить таймауты и выполнить операцию, то она выполнится со старыми таймаутами, а сл. операция уже будет выполнена с новыми таймаутами.
Это объясняется тем, что значения таймаутов считываются из файла состояний .tfstate при выполнении операции, и новые значения таймаутов попадут туда только при успешно выполненной операции.
## Ошибки при работе с таймаутом
### context deadline exceeded
Если время таймаута слишком короткое, то можно получить сл. ошибку:
```
context deadline exceeded
```
Которая говорит, что было выполнено прерывание работы программы из-за истечения времени на операцию.
Для исправления можно увеличить размер окна таймаута и выполнить успешный запрос (например, с помощью терминала), чтобы новое значения таймаутов было добавлено в .tfstate. В противном случае, файл состояния придется править в ручную, либо удалить его и импортировать ресурс для формирования .tfstate.
### 504 ошибка
Данная ошибка говорит о том, что сервер принудительно разорвал соединения из-за истечения времени на ответ.
В случае получения данной ошибки, обратитесь в службу технической поддержки.
## Работа с таймаутами через терминал
Сл. команда выполнит операцию terraform с заданным таймаутом:
```bash
timeout <time> terraform <cmd>
```
Где:
- time - время таймаута, например, 1h, 10m, и так далее
- cmd - команда terraform, например, apply, plan и так далее
## Заключение
Таймауты - мощный механизм terraform провайдера, который позволяет более тонко настраивать время выполнения операций.
Как и любой подобный механизм тонкой настройки, он требует внимательного и аккуратного использования.

@ -0,0 +1,29 @@
Ресурсы в платформе можно удалять в корзину (с возможностью восстановления), удалять сразу без возможности восстановления.
## Удаление ресурса
Для удаления ресурса применяется команда:
```bash
terraform destroy
```
После выполнения данной команды произойдет следующее:
- Будет удален файл состояния ресурса .tfstate
- Ресурс не удалится с платформы, а будет помещен в корзину, с возможностью восстановления
## Восстановление ресурсов
__Ресурс можно восстановить, если у него есть поле `restore`__, в противном случае, необходимо воспользоваться порталом для восстановления.
После удаления ресурса, он помечается как "Deleted" и его можно восстановить.
Для восстановления ресурса необходимо выполнить следующие действия:
- Создать файл .tf и описать в нем восстанавливаемый ресурс
- Импортировать ресурс
- Добавить поле restore со значением `true`
- Выполнить `terraform apply`
## Удаление ресурсов без возможности восстановления
Ресурсы можно удалять с платформы сразу, минуя корзину. Однако, такое удаление возможно только для ресурсов, имеющих поле `permanently`.
Для этого необходимо выполнить сл. шаги:
- В файле .tf добавить поле `permanently = true`
- Применить изменения `terraform apply`
- Выполнить удаление `terraform destroy`
**Проводя мгновенное удаление, ресурс восстановить будет невозможно!**

@ -0,0 +1,448 @@
Иногда требуется создать несколько ресурсов, которые будут отличаться незначительными изменениями (например, имя).
В terraform имеются специальные мета-аргументы, которые позволяют описать данную инфраструктуру максимально быстро, избегая повторений блоков.
Однако, при таком подходе стоит учитывать то, что созданная при помощи такого подхода инфраструктура является неким "монолитом" и любые изменения будут применятся для всех ресурсов, которые были созданы с помощью мета аргументов.
__ВНИМАНИЕ: СОЗДАННЫЕ ТАКИМ ОБРАЗОМ РЕСУРСЫ, УПРАВЛЯЮТСЯ КАК ОДИН РЕСУРС__
## Создание дисков. Обычный вариант
Предположим, что необходимо создать несколько дисков, которые будут иметь одинаковые поля, а отличаться только именем.
Тогда, будут использованы несколько блоков resource с описанием данных ресурсов:
```terraform
resource "decort_disk" "disk1" {
account_id = 777
disk_name = "disk-1"
size_max = 10
gid = 212
}
resource "decort_disk" "disk2" {
account_id = 777
disk_name = "disk-2"
size_max = 10
gid = 212
}
```
Все блоки повторяются и отличаются только именем. Если не планируется изменение каждого ресурса по-отдельности, то можно вынести имена дисков в отдельную переменную, и считывать их из нее.
## Рефакторинг
Вынесем значения имен дисков в блок locals:
```terraform
locals {
disk_names = [
"disk-1",
"disk-2",
]
}
resource "decort_disk" "disk1" {
account_id = 777
disk_name = "disk-1"
size_max = 10
gid = 212
}
resource "decort_disk" "disk2" {
account_id = 777
disk_name = "disk-2"
size_max = 10
gid = 212
}
```
Оставшиеся блоки resource идентичны друг другу, за исключением наименования ресурса, поэтому, их создание и работу с ними можно объединить.
## Мета аргумент for_each
Мета аргумент for_each служит для итерации по набору (set) строки, либо по мапе (map, object). Результатом работы этого мета аргумента станет так же объект, ключами которого будут либо строки, входящие в набор, либо параметры, указанные при итерировании объекта.
Мета аргумент for_each предоставляет переменную each, в которую, при каждой итерации будут ключи (если итерация идет по набору строк), либо ключи и соответствующие им значения, если итерация идет по объекту.
Обратиться к ним можно через символ ".", например:
```terraform
each.key
each.value
```
Таким образом, конфигурирование одинаковых ресурсов сократится до одного.
При добавлении в код выше, получится:
```terraform
locals {
disk_names = [
"disk-1",
"disk-2",
]
}
#обратите внимание, что ресурс был переименован
resource "decort_disk" "disks" {
#преобразование массива к набору строк для успешной работы for_each
for_each = toset(local.disk_names)
account_id = 777
#получение имени диска из переменной each
disk_name = each.key
size_max = 10
gid = 212
}
#блок output демонстрирует вывод работы на экран
output "test" {
value = decort_disk.disks
}
```
При выполнении данной конфигурации в terraform output будет следующее:
```
Changes to Outputs:
+ test = {
+ disk-1 = {
+ account_id = 777
+ account_name = (known after apply)
+ acl = (known after apply)
+ boot_partition = (known after apply)
+ compute_id = (known after apply)
+ compute_name = (known after apply)
+ created_time = (known after apply)
+ deleted_time = (known after apply)
+ desc = (known after apply)
+ destruction_time = (known after apply)
+ detach = false
+ devicename = (known after apply)
+ disk_id = (known after apply)
+ disk_name = "disk-1"
+ disk_path = (known after apply)
+ gid = 212
+ guid = (known after apply)
+ id = (known after apply)
+ image_id = (known after apply)
+ images = (known after apply)
+ iotune = (known after apply)
+ iqn = (known after apply)
+ login = (known after apply)
+ milestones = (known after apply)
+ order = (known after apply)
+ params = (known after apply)
+ parent_id = (known after apply)
+ passwd = (known after apply)
+ pci_slot = (known after apply)
+ permanently = false
+ pool = (known after apply)
+ purge_attempts = (known after apply)
+ purge_time = (known after apply)
+ reality_device_number = (known after apply)
+ reference_id = (known after apply)
+ res_id = (known after apply)
+ res_name = (known after apply)
+ restore = false
+ role = (known after apply)
+ sep_id = (known after apply)
+ sep_type = (known after apply)
+ size_max = 10
+ size_used = (known after apply)
+ snapshots = (known after apply)
+ status = (known after apply)
+ tech_status = (known after apply)
+ timeouts = null
+ type = (known after apply)
+ vmid = (known after apply)
}
+ disk-2 = {
+ account_id = 777
+ account_name = (known after apply)
+ acl = (known after apply)
+ boot_partition = (known after apply)
+ compute_id = (known after apply)
+ compute_name = (known after apply)
+ created_time = (known after apply)
+ deleted_time = (known after apply)
+ desc = (known after apply)
+ destruction_time = (known after apply)
+ detach = false
+ devicename = (known after apply)
+ disk_id = (known after apply)
+ disk_name = "disk-2"
+ disk_path = (known after apply)
+ gid = 212
+ guid = (known after apply)
+ id = (known after apply)
+ image_id = (known after apply)
+ images = (known after apply)
+ iotune = (known after apply)
+ iqn = (known after apply)
+ login = (known after apply)
+ milestones = (known after apply)
+ order = (known after apply)
+ params = (known after apply)
+ parent_id = (known after apply)
+ passwd = (known after apply)
+ pci_slot = (known after apply)
+ permanently = false
+ pool = (known after apply)
+ purge_attempts = (known after apply)
+ purge_time = (known after apply)
+ reality_device_number = (known after apply)
+ reference_id = (known after apply)
+ res_id = (known after apply)
+ res_name = (known after apply)
+ restore = false
+ role = (known after apply)
+ sep_id = (known after apply)
+ sep_type = (known after apply)
+ size_max = 10
+ size_used = (known after apply)
+ snapshots = (known after apply)
+ status = (known after apply)
+ tech_status = (known after apply)
+ timeouts = null
+ type = (known after apply)
+ vmid = (known after apply)
}
}
```
После подтверждения команды, будет создан файл состояния инфраструктуры, в который запишутся данные.
### Обращение к конфигурации, созданной с помощью for_each
Получить доступ к ресурсам, созданным с помощью for_each можно по сл. схеме:
```
<resource_type>.<resource_name>["<key>"]
```
Пример получения доступа к ресурсу disk-2:
```
decort_disk.disks["disk-2"]
```
Чтобы получить доступ к полям, которые содержит ресурс:
```
<resource_type>.<resource_name>["<key>"].<field_name>
```
Например, для получения account_id для disk-2:
```
decort_disk.disks["disk-2"].account_id
```
### Использование for_each для более сложной конфигурации
Иногда, необходимо объединить несколько ресурсов с разной конфигурацией в один ресурс, с помощью for_each. Для того, чтобы это сделать, необходимо воспользоваться функцией for для перебора информации о каждом ресурсе, в котором так же необходимо указать какое из полей будет указывать на определенный ресурс.
Рассмотрим более сложный пример создания нескольких дисков:
```terraform
#создание массива из объектов, описывающих инфраструктуру
locals {
disks = [
{
account_id = 777
diskname = "test-disk"
disk2_gb = 100
gid = 212
},
{
account_id = 778
diskname = "test-disk-1"
disk2_gb = 200
gid = 213
}
]
}
resource "decort_disk" "disks" {
#цикл for проходит по каждому элементы списка, превращая его в объект, где
#ключом будет - имя диска
#знаяением - сам диск
for_each = { for disk in local.disks : disk.diskname => disk }
#получение account_id каждого диска
account_id = each.value.account_id
#шаблон задания имени диска
#так же, если не надо вносить изменения, можно использовать:
#disk_name = each.value.diskname
disk_name = "${each.value.diskname}-data"
#получение размера диска
size_max = each.value.disk2_gb
#получение gid диска
gid = each.value.gid
}
```
Таким образом, будут созданы ресурсы с разной конфигурацией.
## Мета аргумент count
Мета аргумент count так же служит для множественного создания ресурсов, объединяя их в один, с тем лишь исключением, что это будет массив, а не объект.
Аргумент count принимает на вход либо число, либо выражение, которое возвращает число.
Число - количество итерацией, которые предстоит произвести.
Например:
```terraform
count = 3
count = length(some_data)
```
Рассмотрим пример:
```terraform
#без изменений
locals {
disk_names = [
"disk-1",
"disk-2",
]
}
#без изменений, ресурс так же называется - "disks"
resource "decort_disk" "disks" {
#Используется функция length для подсчета длины списка имен дисков
count = length(local.disk_names)
account_id = 777
#аргумент count имеет поле index, которое возвращает индекс(счетчик) текущей итерации
disk_name = local.disk_names[count.index]
size_max = 10
gid = 212
}
output "test" {
value = decort_disk.disks
}
```
При выполнении данной конфигурации в terraform output будет следующее:
```
Changes to Outputs:
+ test = [
+ {
+ account_id = 777
+ account_name = (known after apply)
+ acl = (known after apply)
+ boot_partition = (known after apply)
+ compute_id = (known after apply)
+ compute_name = (known after apply)
+ created_time = (known after apply)
+ deleted_time = (known after apply)
+ desc = (known after apply)
+ destruction_time = (known after apply)
+ detach = false
+ devicename = (known after apply)
+ disk_id = (known after apply)
+ disk_name = "disk-1"
+ disk_path = (known after apply)
+ gid = 212
+ guid = (known after apply)
+ id = (known after apply)
+ image_id = (known after apply)
+ images = (known after apply)
+ iotune = (known after apply)
+ iqn = (known after apply)
+ login = (known after apply)
+ milestones = (known after apply)
+ order = (known after apply)
+ params = (known after apply)
+ parent_id = (known after apply)
+ passwd = (known after apply)
+ pci_slot = (known after apply)
+ permanently = false
+ pool = (known after apply)
+ purge_attempts = (known after apply)
+ purge_time = (known after apply)
+ reality_device_number = (known after apply)
+ reference_id = (known after apply)
+ res_id = (known after apply)
+ res_name = (known after apply)
+ restore = false
+ role = (known after apply)
+ sep_id = (known after apply)
+ sep_type = (known after apply)
+ size_max = 10
+ size_used = (known after apply)
+ snapshots = (known after apply)
+ status = (known after apply)
+ tech_status = (known after apply)
+ timeouts = null
+ type = (known after apply)
+ vmid = (known after apply)
},
+ {
+ account_id = 777
+ account_name = (known after apply)
+ acl = (known after apply)
+ boot_partition = (known after apply)
+ compute_id = (known after apply)
+ compute_name = (known after apply)
+ created_time = (known after apply)
+ deleted_time = (known after apply)
+ desc = (known after apply)
+ destruction_time = (known after apply)
+ detach = false
+ devicename = (known after apply)
+ disk_id = (known after apply)
+ disk_name = "disk-2"
+ disk_path = (known after apply)
+ gid = 212
+ guid = (known after apply)
+ id = (known after apply)
+ image_id = (known after apply)
+ images = (known after apply)
+ iotune = (known after apply)
+ iqn = (known after apply)
+ login = (known after apply)
+ milestones = (known after apply)
+ order = (known after apply)
+ params = (known after apply)
+ parent_id = (known after apply)
+ passwd = (known after apply)
+ pci_slot = (known after apply)
+ permanently = false
+ pool = (known after apply)
+ purge_attempts = (known after apply)
+ purge_time = (known after apply)
+ reality_device_number = (known after apply)
+ reference_id = (known after apply)
+ res_id = (known after apply)
+ res_name = (known after apply)
+ restore = false
+ role = (known after apply)
+ sep_id = (known after apply)
+ sep_type = (known after apply)
+ size_max = 10
+ size_used = (known after apply)
+ snapshots = (known after apply)
+ status = (known after apply)
+ tech_status = (known after apply)
+ timeouts = null
+ type = (known after apply)
+ vmid = (known after apply)
},
]
```
### Обращение к конфигурации, созданной с помощью сount
Получить доступ к ресурсам, созданным с помощью count можно по сл. схеме:
```
<resource_type>.<resource_name>[<index>]
```
Пример получения доступа к ресурсу disk-2:
```
decort_disk.disks[1]
```
Чтобы получить доступ к полям, которые содержит ресурс:
```
<resource_type>.<resource_name>[<index>].<field_name>
```
Например, для получения account_id для disk-2:
```
decort_disk.disks[1].account_id
```
### Использование count для более сложной конфигурации
Иногда, необходимо объединить несколько ресурсов с разной конфигурацией в один ресурс, с помощью count. Для того, чтобы это сделать, необходимо воспользоваться функцией length для установления длины входящих параметров. После чего, обращаться к ним, получая значения, используя индекс.
Рассмотрим более сложный пример создания нескольких дисков:
```terraform
#создание массива из объектов, описывающих инфраструктуру
locals {
disks = [
{
account_id = 777
diskname = "test-disk"
disk2_gb = 100
gid = 212
},
{
account_id = 778
diskname = "test-disk-1"
disk2_gb = 200
gid = 213
}
]
}
resource "decort_disk" "disks" {
#получение значения длины входящих параметров
count = length(local.disks)
#получение идентификатора аккаунта
account_id = local.disks[count.index].account_id
#получение имени диска
disk_name = "${local.disks[count.index].diskname}-data"
#получение размера диска
size_max = local.disks[count.index].disk2_gb
#получение gid
gid = local.disks[count.index].gid
}
```
Таким образом, будут созданы ресурсы, с разной конфигурацией.

@ -0,0 +1,262 @@
Ресурсы в terraform можно как создавать, редактировать, так и удалять. При удалении ресурса, terraform провайдер производит необходимые действия на платформе, после чего очищает эти ресурсы из своего .tfstate - файла, в котором хранится состояние инфраструктуры.
В данном разделе рассмотрены различные способы удаления ресурсов, проблемы, которые могут возникнуть, их причины, а так же способы их решить.
## Команда destroy
Для удаления ресурса, в terraform имеется команда
```bash
terraform destroy
```
По умолчанию, эта команда производит удаление всей инфраструктуры, описанной и сохраненной в .tfstate-файле.
### Влияние конфигурационного параметра permanently
В некоторых ресурсах terraform провайдера имеется параметр permanently, который регулирует удаление ресурса:
- Если флаг имеет значение - `true`, то ресурс будет мгновенно удален с платформы и восстановить его будет невозможно.
- Если флаг имеет значение - `false` (используется по умолчанию), то ресурс будет помещен в корзину, с возможностью дальнейшего восстановления. Ресурс будет удален автоматически из корзины через 7 дней (зависит от настроек платформы).
#### Возможные проблемы
Так как terraform, при удалении ресурса, производит удаление .tfstate-файла, то при использовании фдага permanently = false, ресурс невозможно будет восстановить из конфигурационного файла инфраструктуры - при использовании `terraform apply` - будет создана новая инфраструктура. Поэтому, старую инфраструктуру необходимо импортировать, чтобы сформировать .tfstate - файл, а потом применить `terraform apply` - тогда ресурс будет восстановлен из корзины (_фича находится в разработке - доступно в ресурсе disks_, в провайдере версии 3.2.0+)
## Команда destroy с флагом target
Как и было сказано выше, команда `terraform destroy` производит удаление всей инфраструктуры. Для того, чтобы произвести удаление определенных ресурсов, используется флаг `-target`. Флаг, в качестве параметра, принимает название ресурса для удаления, вида
```
<тип-ресурса>.<имя-ресурса>
```
либо
```
<модуль>.<имя-ресурса>
```
для ресурсов, содержащихся в модулях.
Таким образом, общая команда выглядит так:
```
terraform destroy -target <тип-ресурса>.<имя-ресурса>
```
или
```
terraform destroy -target <модуль>.<имя-ресурса>
```
В примерах не используется модуль, поэтому, далее, в качестве примера, будет взята команда `terraform destroy -target <тип-ресурса>.<имя-ресурса>`
### Способы передачи параметра
1. `terraform destroy -target <тип-ресурса>.<имя-ресурса>`
2. `terraform destroy -target="<тип-ресурса>.<имя-ресурса>"`
### Пример использования target
В качестве примера возьмем пример конфигурации из [прошлой статьи](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/05.04-Массовое-создание-ресурсов.-Мета-аргументы.md):
```terraform
resource "decort_disk" "disk1" {
account_id = 777
disk_name = "disk-1"
size_max = 10
gid = 212
}
resource "decort_disk" "disk2" {
account_id = 777
disk_name = "disk-2"
size_max = 10
gid = 212
}
```
- Чтобы удалить всю инфраструктуру, необходимо просто выполнить в терминале команду
```bash
terraform destroy
```
- Чтобы удалить "disk2", можно воспользоваться командой:
```
terraform destroy -target decort_disk.disk2
```
- Чтобы удалить "disk1", можно воспользоваться другим способом удаления:
```
terraform destroy -target="decort_disk.disk1"
```
Таким образом, определенный ресурс можно удалить с помощью флага target.
### Использование флага target при работе с ресурсами, созданными с помощью мета аргументов.
При создании ресурсов с помощью мета аргументов, первые получают дополнительные символы в именах ресурсов, что может привести к некоторым проблемам при работе с такими ресурсами.
#### Работа с for_each
При работе с for_each, ресурс получается имя вида: `<тип-ресурса>.<общее-имя-ресурса>["<название>"]`
Таким образом, обращение к такому ресурсу будет выглядит следующим образом:
```
terraform destroy -target='<тип-ресурса>.<общее-имя-ресурса>[\"<название>\"]'
```
или
```
terraform destroy -target '<тип-ресурса>.<общее-имя-ресурса>[\"<название>\"]'
```
Пример:
Для примера рассмотрим создание ресурса с помощью мета аргумента for_each из предыдущей статьи:
```terraform
locals {
disk_names = [
"disk-1",
"disk-2",
]
}
resource "decort_disk" "disks" {
for_each = toset(local.disk_names)
account_id = 777
disk_name = each.key
size_max = 10
gid = 212
}
```
В результате применения команды `terrafrom apply`, будут созданы ресурсы с именами:
- decort_disk.disks["disk-1"]
- decort_disk.disks["disk-2"]
Чтобы удалить определенный ресурс, можно воспользоваться одной из команд:
```
#для удаления disk-1
terraform destroy -target='decort_disk.disks[\"disk-1\"]'
```
```
#для удаления disk-2
terraform destroy -target 'decort_disk.disks[\"disk-2\"]'
```
Либо:
```
#для удаления всей инфраструктуры
terraform destroy
```
Такая запись с экранирование кавычек обуславливается работой терминальной оболочки, через которую будет производится вызов данной команды, а так же то, что terraform в качестве параметра флага ожидает строку. Так же, есть еще одно правило - в terraform в квадратных скобках указывается либо строка в двойных кавычках (в качестве имени ключа для объекта, используется для for_each), либо число - в качестве индекса для массива (используется для count)
#### Работа с count
При работе с count, ресурс получается имя вида: `<тип-ресурса>.<общее-имя-ресурса>[<индекс>]`
Таким образом, обращение к такому ресурсу будет выглядит следующим образом:
```
terraform destroy -target="<тип-ресурса>.<общее-имя-ресурса>[<индекс>]"
```
или
```
terraform destroy -target <тип-ресурса>.<общее-имя-ресурса>[<индекс>]
```
Пример:
Для примера рассмотрим создание ресурса с помощью мета аргумента for_each из предыдущей статьи:
```terraform
locals {
disk_names = [
"disk-1",
"disk-2",
]
}
resource "decort_disk" "disks" {
count = length(local.disk_names)
account_id = 777
disk_name = local.disk_names[count.index]
size_max = 10
gid = 212
}
```
В результате применения команды `terrafrom apply`, будут созданы ресурсы с именами:
- decort_disk.disks[0]
- decort_disk.disks[1]
Чтобы удалить определенный ресурс, можно воспользоваться одной из команд:
```
#для удаления disk-1
terraform destroy -target="decort_disk.disks[0]"
```
```
#для удаления disk-2
terraform destroy -target decort_disk.disks[1]
```
Либо:
```
#для удаления всей инфраструктуры
terraform destroy
```
### Удаление ресурса из состояния
В ходе работы, могут возникать случаи, когда состояние (state, стейт) terraform имеет ресурсы, которые были удалены с платформы. В таком случае, можно, при выполнении команд `terraform plan/apply` получить ошибку:
```bash
Planning failed. Terraform encountered an error while generating this plan.
│ Error: The resource cannot be updated because it has been destroyed
│ with decort_kvmvm.instances["pgsmonsietc03"],
│ on main.tf line 33, in resource "decort_kvmvm" "instances":
│ 33: resource "decort_kvmvm" "instances" {
```
Либо, в ходе неверного выполнения может возникнуть подобная ошибка:
```bash
│ Error: Failed to read the given file as a state or plan file
│ State read error: Error loading statefile: open data.decort_cb_vins.vins: no such file or directory
│ Plan read error: open data.decort_cb_vins.vins: no such file or directory
```
Для того, чтобы этого избежать, необходимо удалить отсутствующий ресурс из стейта, выполнив команду `terraform state rm <res>.<name>`
Например, `terraform state rm decort_kvmvm.vm1`
В случае, если ресурс был создан путен работы генераторов count/for_each, работают те же правила, что и для команды `terraform destroy`.
## Возможные проблемы
Были обнаружены проблемы при использовании _oh my zsh_, которые заключались в том, что не считывались данные, переданные, при экранировании строки.
Рекомендация: использовать _bash_.
## Заключение
Таким образом, terraform позволяет выполнять удаление:
- всей инфраструктуры, хранящейся в файле .tfstate с помощью `terraform destroy`
- части инфраструктуры, используя флаг target. ОБщий вид команды такой: `terraform destroy -target <тип-ресурса>.<имя-ресурса>`

@ -0,0 +1,46 @@
# Установка Terraform
На момент написания инструкции, приложение Terraform по прямой ссылке с сайта-разработчика программного обеспечения невозможно скачать, по этой же причине, невозможно произвести установку с помощью разных пакетных менеджеров.
Существует два способа произвести установку приложения:
- Скачать скомпилированное приложение с зеркала компании Digital Energy.
- Из исходных кодов.
## Скачивание и установка скомпилированного приложения с зеркала компании Digital Energy
1. Перейти по ссылке https://colba.decs.online/index.php/s/JfkXWbwTqww64Tz , выбрать версию terraform для подходящей ОС.
2. Скачать архив.
3. Разархивировать приложение и переместить:
- Для Linux или MacOS: `/usr/local/bin`
- Для Windows: в любую папку, после чего добавить в $PATH в переменных окружения путь до приложения
4. Ввести в терминале `terraform -help`, в случае успеха, на экран будет информация о программе.
### Указание переменных среды окружения в Windows
Меню -> Панель управления -> Система -> Настройки -> Переменные окружения
Или
Поиск -> Изменение системных переменных среды
В открывшемся окне -> Переменные среды
Далее, необходимо выбрать переменную Path -> Изменить
Создать -> ввести путь до файла -> ОК
## Из исходных кодов
Для компилирования приложения потребуется:
- Компилятор языка программирования GO
- Система контроля версий git
- Исходные файлы приложения.
Сначала необходимо скачать и установить компилятор языка программирования GO. Для этого, необходимо перейти по ссылке https://go.dev/doc/install . На странице сайта будет автоматически представлена последняя версия компилятора подходящая операционной системе.
Далее, необходимо скачать и установить систему контроля версий git (https://git-scm.com/), на сайте будет так же автоматически предложена самая последняя и подходящая версия.
После установки компилятора и системы контроля версий, необходимо произвести клонирование исходных кодов приложения. Выполнить это можно, введя в терминале следующую команду:
```bash
git clone https://github.com/hashicorp/terraform.git
```
Обратите внимание, что клонирование будет происходить в директорию, из которой происходил вызов команды.
После клонирования, можно приступить к сборке приложения.
Для этого необходимо перейти в каталог, в который произошло клонирование исходных кодов и выполнить команду в терминале:
```bash
go install
```
Или
```bash
go build
```
Результатом выполнения данной программы станет бинарный файл terraform.
Полученный файл необходимо поместить в каталог `/usr/local/bin` для MacOS или Linux, либо в любой каталог и указать его путь в переменных окружения для ОС Windows.
После всех действий, команда `terraform -help` должна выводить информацию в терминал.
Полезные ссылки:
- https://learn.hashicorp.com/tutorials/terraform/install-cli
- https://stackoverflow.com/questions/1618280/where-can-i-set-path-to-make-exe-on-windows

@ -0,0 +1,179 @@
Начиная с версии `4.2.0` провайдера была добавлена новая логика работы с k8s кластерами. Заключается она в разделении ответственности между двумя ресурсами:
- `decort_k8s_cp` - используется для первичного создания и управления control plane кластера
- `decort_k8s_wg` - используется для управления worker-группами
### `decort_k8s_cp` - мастер-узел кластера
В отличии от ресурса `decort_k8s` не имеет возможности управления worker-группами и может быть создан без указания названия дефолтной группы. При успешном создании ресурса, кластер будет создан без рабочих узлов.
### `decort_k8s_wg` - worker-группы кластера
Ресурс используется для создания, удаления или изменения рабочих узлов, которых у одного кластера может быть как ни одного, так и множество.
**При использовании `decort_k8s_cp` не рекомендуется параллельное использование `decort_k8s` для управления одним и тем же кластером во избежание проблем с идемпотентностью** <br/>
## Инструкция по миграции созданных кластеров
Ниже приведен пример ресурса, миграция которого будет проведена:
```terraform
resource "decort_k8s" "cluster" {
name = "tf-wiki"
rg_id = 1649
k8sci_id = 55
extnet_id = 13
wg_name = "wiki-wg"
network_plugin = "flannel"
# Описание мастер-узла
masters {
cpu = 2
ram = 2048
num = 3
disk = 15
}
# Описание дефолтной воркер-группы
workers {
name = "wiki-wg"
cpu = 1
num = 1
ram = 1024
disk = 15
}
# Описание дополнительной воркер-группы
workers {
name = "additional-wg"
cpu = 1
num = 1
ram = 1024
disk = 15
}
}
```
1. Для начала, создадим в файле конфигурации ресурс `decort_k8s_cp`:
```terraform
resource "decort_k8s_cp" "control_plane" {}
```
2. Выполним команду импортирования с указанием ID кластера:
```
terraform import decort_k8s_cp.<CP_NAME> <K8s_ID>
```
Для кластера выше:
```
terraform import decort_k8s_cp.control_plane 556
```
2.1: В случае, если в кластере присутствуют worker группы, провайдер напомнит об этом:
```
Warning: Found worker-group with ID 1353. Make sure to import it to decort_k8s_wg resource if you wish to manage it
Warning: Found worker-group with ID 1354. Make sure to import it to decort_k8s_wg resource if you wish to manage it
```
3. После этого, заполним поля ресурса данными из `decort_k8s`:
```terraform
resource "decort_k8s_cp" "control_plane" {
name = "tf-wiki"
rg_id = 1649
k8sci_id = 55
extnet_id = 13
network_plugin = "flannel"
# Описание мастер-узла вынесено в корень ресурса
cpu = 2
num = 2048
num = 3
disk = 15
# Данных о рабочих узлов в ресурсе нет - они описываются в decort_k8s_wg
}
```
4. В случае, если есть уже созданные рабочие узлы, стоит добавить ресурсы `decort_k8s_wg` для каждого в конфигурационный файл:
```terraform
resource "decort_k8s_wg" "<WG1_NAME> {
# Для удобства можно сразу указать k8s_id из ранее созданного ресурса decort_k8s_cp
k8s_id = decort_k8s_cp.<CP_NAME>.k8s_id
}
```
4.1 Для кластера в примере:
```terraform
resource "decort_k8s_wg" "wg1" {
k8s_id = decort_k8s_cp.control_plane.k8s_id
name = "wiki-wg"
cpu = 1
num = 1
ram = 1024
disk = 15
}
resource "decort_k8s_wg" "wg2" {
k8s_id = decort_k8s_cp.control_plane.k8s_id
name = "additional-wg"
cpu = 1
num = 1
ram = 1024
disk = 15
}
```
5. Выполним команду `terraform import` (отдельно для каждого ресурса):
```
terraform import decort_k8s_wg.<WG1_NAME> <WG_ID>#<K8s_ID>
```
```
terraform import decort_k8s_wg.wg1 1353#556
terraform import decort_k8s_wg.wg2 1354#556
```
6. В случае успеха, команда `terraform plan` успешно завершится со статусом*:
```
No changes. Your infrastructure matches the configuration.
```
**кроме случаев, когда терраформ пытается записать автоматически генерируемые (дефолтные) значения параметров в стейт (например, start меняется с null на true) или ресурс был изменен вне терраформа*<br/>
7. После успешной миграции стоит удалить описание ресурса `decort_k8s`.
8. Теперь k8s кластер находится под полным управлением terraform.
### Конф. файл после всех изменений:
```terraform
resource "decort_k8s_cp" "control_plane" {
name = "tf-wiki"
rg_id = 1649
k8sci_id = 55
extnet_id = 13
network_plugin = "flannel"
# Описание мастер-узла вынесено в корень ресурса
cpu = 2
num = 2048
num = 3
disk = 15
# Данных о рабочих узлов в ресурсе нет - они описываются в decort_k8s_wg
}
resource "decort_k8s_wg" "wg1" {
k8s_id = decort_k8s_cp.control_plane.k8s_id
name = "wiki-wg"
cpu = 1
num = 1
ram = 1024
disk = 15
}
resource "decort_k8s_wg" "wg2" {
k8s_id = decort_k8s_cp.control_plane.k8s_id
name = "additional-wg"
cpu = 1
num = 1
ram = 1024
disk = 15
}
```
## P. S
1. После успешной миграции **не рекомендуется** использовать `decort_k8s` параллельно с `decort_k8s_cp` - это может привести к нежелательным проблемам идемпотентности
2. При удалении `decort_k8s_cp` удалится как сам кластер, так и все зависимые воркер-группы, а соответственно и `decort_k8s_wg`

@ -0,0 +1,4 @@
В данном разделе представлены _data_source_ функции провайдера.
Все функции разделены на две группы:
- Пользовательская группа
- Административная группа

@ -0,0 +1 @@
В данном разделе представлены функции для взаимодействия с пользовательской группой API.

@ -0,0 +1,289 @@
_Data source_ функция **decort_kvmvm** служит для получения информации об уже существующей в облачной платформе виртуальной машине (Virtual Machine, VM), созданной на базе системы виртуализации KVM.
## Аргументы
_Data source_ функция **decort_kvmvm** принимает следующие аргументы:
| Аргумент | Тип | Обязательный | Описание |
| --- | --- | --- | --- |
| compute_id | int | :heavy_check_mark: | Идентификатор экземпляра _compute_, соответствующего данной виртуальной машине (подробнее о понятии _compute_ см. в разделе [Обзор облачной платформы DECORT](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT.md)). |
Пользователь облачной платформы, от лица которого происходит обращение к данной функции, должен иметь доступ к указанному виртуальному серверу и ресурсной группе. В противном случае возникнет ошибка доступа.
Пользователь облачной платформы задается на стадии инициализации Terraform провайдера DECORT (см. [подробности](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/04.02-Инициализация-Terraform-провайдера-DECORT.md)).
## Возвращаемые значения
В случае успешного выполнения _data source_ функция **decort_kvmvm** возвращает в указанную при вызове переменную следующие значения:
| Параметр | Тип | Описание
| --- | --- | --- |
| acl | []Struct [см. ниже](#описание-структуры-acl) | Cписок Acces Control |
| account_id | int | Уникальный идентификатор подписчика-владельца ("account") данной виртуальной машины |
| account_name | string | Имя подписчика, которому принадлежит данная виртуальная машина |
| affinity_label | string | Лейбл аффинити |
| affinity_rules | []Struct [см. ниже](#описание-структуры-affinity-rules) | Правила аффинити для компьютов |
| affinity_weight | int | weight аффинити |
| arch | string | Архитектура |
| auto_start_w_node | bool | Автостарт при рестарте ноды |
| boot_order | []string | Boot order |
| boot_disk_id | int | Идентификатор загрузочного диска виртуальной машины |
| boot_disk_size | int | Размер загрузочного диска в ГБ |
| chipset | string | Тип эмулируемой системы |
| cd_image_id | int | ID cd image id |
| clone_reference | int | кол-во клонов |
| clones | []int | id клонов |
| computeci_id | int | Id computeci |
| cpu_pin | bool | Необходимость запускать ВМ на выделенных CPU ядрах |
| cpus | int | Количество виртуальных CPU, выделенных данному серверу |
| created_by | string | Кем создан ресурс |
| created_time | int | Время создания ресурса |
| custom_fields | []Struct [см. ниже](#описание-структуры-custom-fields) | Кастомные поля |
| deleted_by | string | Кем удален ресурс |
| deleted_time | int | Время удаления ресурса |
| desc | string | Текстовое описание виртуальной машины |
| devices | string | Девайсы |
| disks | []Struct [см. ниже](#описание-структуры-disks) | информация о дисках компьюта |
| driver | string | Аппаратная архитектура данной виртуальной машины |
| gid | int | GID |
| guid | int | GUID |
| hp_backed | bool | Необходимость использовать для выделения RAM виртуальной машины Huge Pages ядрах |
| image_id | int | Идентификатор образа ОС, на базе которого создан загрузочный диск этой виртуальной машины |
| image_name | string | Имя образа ОС, на базе которого создан загрузочный диск этой виртуальной машины |
| interfaces | []Struct [см. ниже](#описание-структуры-interfaces) | Информация о интерфейсах компьюта |
| lock_status | string | Статус доступности |
| manager_id | int | Manager id |
| manager_type | string | Type manager |
| migrationjob | int | Migrationjob |
| milestones | int | Вехи |
| name | string | Имя виртуального сервера |
| natable_vins_id | int | NAT vins id |
| natable_vins_ip | string | NAT vins ip |
| natable_vins_name | string | NAT vins name |
| natable_vins_network | string | NAT vins network |
| natable_vins_network_name | string | NAT vins network name |
| need_reboot | bool | флаг, указывающий, что требуется перезагрузка |
| numa_affinity | string | Необходимость выравнивать ВМ по NUMA |
| numa_node_id | int | ID узла NUMA |
| os_users | []Struct [см. ниже](#описание-структуры-os-users) | Имена и пароли пользователей гостевой ОС, установленные платформой при создании виртуального сервера. Формат структуры:<br/>* (string) `login` - учётная запись в гостевой ОС.<br/>* (string) `password` - пароль к этой учётной записи. |
| pinned | bool | добавлен ли компьют на стек |
| ram | int | Объём оперативной памяти в МБ, выделенной этой виртуальной машине |
| reference_id | string | ID reference |
| registered | bool | Компьют зарегестрирован |
| res_name | string | Res name |
| reserved_node_cpus | []int | Количество зарезервированных CPU в узле |
| rg_id | int | Идентификатор ресурсной группы, к которой принадлежит виртуальная машина |
| rg_name | string | Имя ресурсной группы, к которой принадлежит виртуальная машина |
| snap_sets | []Struct [см. ниже](#описание-структуры-snap-sets) | Snap sets |
| status | string | Cтатус |
| tags | map[string]string | Тэги |
| tech_status | string | Технический статус |
| updated_by | string | Кем обновлен ресурс |
| updated_time | int | Время обновления ресурса |
| user_managed | bool | User managed |
| pci_devices | []int | Список PCI девайсов |
| userdata | string | Параметры cloud_init |
| vnc_password | string | vnc пароль |
| vgpus | []int | Список vgpu |
| virtual_image_id | int | ID виртуального образа |
| virtual_image_name | string | Имя образа ОС, на базе которого создан загрузочный диск этой виртуальной машины |
### Описание структуры acl
| Параметр | Тип | Описание |
| --- | --- | --- |
| account_acl | []Struct [см. ниже](#описание-структуры-List-acl) | Информация о списке пользователей аккаунтов |
| compute_acl | []Struct [см. ниже](#описание-структуры-List-acl) | Информация о списке пользователей компьютов |
| rg_acl | []Struct [см. ниже](#описание-структуры-List-acl) | Информация о списке пользователей ресурной группы |
### Описание структуры affinity rules
| Параметр | Тип | Описание |
| --- | --- | --- |
| guid | string | guid |
| key | string | Ключ |
| mode | string | Режим сравнения |
| policy | string | Степень "строгости" этого правила |
| topology | string | Топология |
| value | string | Значение |
### Описание структуры List acl
| Параметр | Тип | Описание |
| --- | --- | --- |
| explicit | bool | Явно ли указан доступ |
| guid | string | guid Ресурса |
| right | string | Права на ресурс |
| status | string | Статус ресурса |
| type | string | Тип ресурса |
| user_group_id | string | ID user group |
### Описание структуры custom fields
| Параметр | Тип | Описание |
| --- | --- | --- |
| key | string | Ключ |
| val | string | Значение |
### Описание структуры os users
| Параметр | Тип | Описание |
| --- | --- | --- |
| guid | string | GUID |
| login | string | Логин |
| password | string | Пароль |
| public_key | string | Публичный ssh ключ |
### Описание структуры disks
| Параметр | Тип | Описание |
| --- | --- | --- |
| _ckey | string | ckey |
| acl | string | Acces Control List |
| account_id | int | ID аккаунта |
| bus_number | int | Номер шины |
| boot_partition | int | Загрузочный раздел |
| created_time | int | Время создания диска |
| deleted_time | int | Время удаления диска |
| description | string | Описание |
| destruction_time | int | Время удаления |
| disk_path | string | Путь диска |
| gid | int | GID |
| guid | int | GUID |
| disk_id | int | ID диска |
| image_id | int | ID образа |
| images | []int | Список образов |
| iotune | []Struct [см. ниже](#описание-структуры-iotune) | Ограничения диска |
| iqn | string | iqn диска |
| login | string | Логин для доступа к диску |
| milestones | int | Вехи |
| name | string | Наименование диска |
| order | int | Номер диска |
| params | string | Параметры диска |
| parent_id | int | id родительского диска |
| passwd | string | Пароль для доступа к диску |
| pci_slot | int | id pci слота, к которому подключен диск |
| pool | string | Имя пула в системе хранения, на ресурсах которой размещён данный диск |
| present_to | []int | Список ID ресурсов, которым предоставлен диск |
| purge_time | int | Время последней попытки |
| replication | Struct{} [см. ниже](#описание-структуры-replication) | Информация о реплике диска |
| reality_device_number | int | Реальный номер устройства |
| res_id | int | id ресурса |
| role | string | Роль диска |
| sep_id | int | Идентификатор Storage Endpoint Provider (SEP). SEP это способ идентифицировать конкретную систему хранения, на ресурсах которой размещён данный диск |
| shareable | bool | Флаг, отвечающий за доступность диска дургим ресурсам |
| size_max | int | Размер диска в ГБ |
| size_used | float | Кол-во используемого места, в ГБ |
| snapshots | []Struct{}[см. ниже](#описание-структуры-snapshots) | Снимки состояния диска |
| status | string | Статус диска |
| tech_status | string | Технический статус диска |
| type | string | Тип диска с точки зрения его роли в составе _compute_. Может принимать одно из фиксированных значений:<br/>"B" - признак загрузочного диска ("boot").<br/>"D" - признак дополнительного диска ("data") |
| vmid | int | Идентификатор виртуальной машины (устаревшее) |
### Описание структуры iotune
| Параметр | Тип | Описание |
| --- | --- | --- |
| read_bytes_sec | int | Кол-во байт для чтения в секунду |
| read_bytes_sec_max | int | Максимальное кол-во байт для чтения |
| read_iops_sec | int | Кол-во операций чтения io в секунду | |
| read_iops_sec_max | int | Максимальное число io операций чтения |
| size_iops_sec | int | Размер io операций |
| total_bytes_sec | int | Общий размер байт в секунду |
| total_bytes_sec_max | int | Максимальный общий размер байт в секунду |
| total_iops_sec | int | Общее кол-во io операций в секунду |
| total_iops_sec_max | int | Максимальное общее кол-во io операций в секунду |
| write_bytes_sec | int | Кол-во байт для записи в секунду |
| write_bytes_sec_max | int | Максимальное кол-во байт для записи в секунду |
| write_iops_sec | int | Кол-во операций записи в секунду |
| write_iops_sec_max | int | Максимальное число операций записей |
### Описание структуры replication
| Параметр | Тип | Описание |
| --- | --- | --- |
| disk_id | int | id диска |
| pool_id | string | id пула |
| role | string | Роль диска (главный или реплика) |
| self_volume_id | string | id раздела |
| storage_id | int | id хранилища |
| volume_id | int | id раздела |
### Описание структуры snapshots
| Параметр | Тип | Описание |
| --- | --- | --- |
| guid | string | id снимка |
| label | string | Наименование снимка |
| res_id | string | Ссылка на снимок |
| snap_set_guid | string | Установленный id снимка |
| reference_id | int | Reference ID |
| snap_set_time | int | Установленное время снимка |
| timestamp | int | Время снимка |
### Описание структуры interfaces
| Параметр | Тип | Описание |
| --- | --- | --- |
| bus_number | int | Номер шины |
| conn_id | int | ID connect |
| conn_type | string | Тип connect |
| enabled | bool | Доступность подключения |
| def_gw | string | Шлюз по умолчанию |
| flip_group_id | int | id flip group |
| guid | string | GUID |
| ip_address | string | IP адрес |
| listen_ssh | bool | открыт ли ssh connect |
| mac | string | MAC адрес устройства |
| mtu | string | Максимальный объём данных, который может быть передан за одну итерацию |
| name | string | Имя |
| net_id | int | ID сети |
| netmask | int | Маска сети |
| net_type | string | Тип сети |
| node_id | int | ID узла |
| pci_slot | int | Pci Slot |
| qos | []Struct{}[см. ниже](#описание-структуры-qos) | QOS |
| target | string | Цель сети |
| type | string | Тип |
| vnfs | []int | VNFS |
| libvirt_settings | []Struct{}[см. ниже](#описание-структуры-libvirt_settings) | Параметры libvirt virtio интерфейса |
### Описание структуры libvirt_settings
| Параметр | Тип | Описание |
| --- | --- | --- |
| guid | string | GUID |
| txmode | string | TX mode |
| ioeventfd | string | IO event |
| event_idx | string | Event ID |
| queues | int | Количество очередей |
| rx_queue_size | int | Длина очереди RX |
| tx_queue_size | int | Длина очереди TX |
### Описание структуры qos
| Параметр | Тип | Описание |
| --- | --- | --- |
| e_rate | int | E rate |
| guid | string | ID ресурса |
| in_brust | int | In brust |
| in_rate | int | In rate |
### Описание структуры snap sets
| Параметр | Тип | Описание |
| --- | --- | --- |
| disks | []int | Список id дисков |
| guid | string | GUID |
| label | string | Лейбл |
| timestamp | int | Время |
## Пример использования
В нижеприведённом примере посредством вызова _data source_ функции **decort_kvmvm** извлекается информация об уже существующем в платформе виртуальном сервере со следующими характеристиками:
* Имя сервера _MyOldVM_;
* Идентификатор ресурсной группы, в которой находится данный сервер - 123.
```terraform
data "decort_kvmvm" "comp" {
#получение информации по идентификатору машины - compute_id
#id виртуальной машины
#обязательный параметр
#тип - целое число
compute_id = 11346
}
```
Данный пример подразумевает, что ранее по тексту tf-файла выполнена корректная инициализация провайдера (подробнее об инициализации Terraform провайдера DECORT см. соответствующий [раздел](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/04.02-Инициализация-Terraform-провайдера-DECORT.md)).
Чтобы получить идентификатор ресурсной группы (аргумент `rg_id`), можно воспользоваться _data source_ функцией [decort_resgroup](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/06.01.12-Data_decort_rg_list.md).
После успешного завершения такого вызова **decort_kvmvm** в переменной `data.decort_kvmvm.comp` будут сохранены возвращаемые значения. Так, например:
* пароль для доступа в гостевую ОС, назначенный по умолчанию при создании VM - `"data.decort_kvmvm.comp.os_users.0.password`
* идентификатор образа ОС, на базе которого была создана данная VM - `data.decort_kvmvm.comp.image_id`
* текущий объём ОЗУ - `data.decort_kvmvm.comp.ram`

@ -0,0 +1,128 @@
_Data source_ функция **decort_resgroup** служит для получения информации об уже существующей ресурсной группе.
Ресурсная группа в облачной платформе DECORT это способ группирования _compute_-ов (например, по функциональному признаку или принадлежности к одному и тому же проекту). Ресурсную группу можно рассматривать как небольшой персональный дата-центр, в котором размещаются один или несколько серверов и виртуальных сетевых сегментов (ViNS).
Экземпляры _compute_ (виртуальные серверы) всегда создаются в принадлежности к какой-либо ресурсной группе. Как следствие, для создания экземпляра _compute_ помимо других параметров требуется указать идентификатор целевой ресурсной группы. Для получения такого идентификатора можно воспользоваться рассматриваемой здесь _data source_ функцией **decort_resgroup**.
## Изменения в 3.5.0
- Убраны опциональные поля account_id и name
- Опциональное поле rg_id стало обязательным
- Возвращаемые значения приведены в соответвие с версией платформы 3.8.5
## Изменения в 3.4.0
- В возвращаемые значения добавлено новое поле gid
- В возвращаемые значения добавлено новое поле resources
- В возвращаемые значения добавлено новое поле status
- В возвращаемые значения добавлено новое поле vins
- В возвращаемые значения добавлено новое поле vms
- Обязательное поле account_id изменено на опциональное
## Аргументы
_Data source_ функция **decort_resgroup** принимает следующие аргументы:
| Аргумент | Тип | Обязательный | Описание |
| --- | --- | --- | --- |
| rg_id | int | :heavy_check_mark: | Идентификатор ресурсной группы, по которой требуется получить информацию. Идентификатор не может быть нулевым.<br/>Вы можете задать или `rg_id`, или `name`. Если задан параметр `rg_id`, то параметр `name` игнорируся. |
Пользователь облачной платформы, от лица которого происходит обращение к данной функции, должен иметь доступ к указанному `account` и ресурсной группе. В противном случае возникнет ошибка доступа.
Пользователь облачной платформы задается на стадии инициализации Terraform провайдера DECORT (см. [подробности](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/04.02-Инициализация-Terraform-провайдера-DECORT.md)).
## Возвращаемые значения
В случае успешного выполнения _data source_ функция **decort_resgroup** возвращает в указанную при вызове переменную следующие значения:
| Параметр | Тип | Описание |
| --- | --- | --- |
| resources | Struct{} [см. ниже](#описание-структуры-resources) | Информация о занимаемых ресурсах |
| account_id | int | Уникальный идентификатор подписчика-владельца данной ресурсной группы. |
| account_name | string | Имя подписчика ("account"), которому принадлежит данная ресурсная группа. |
| compute_features | []string | Доступ к дополнительным функциям управления ВМ |
| acl | []Struct [см. ниже](#описание-структуры-acl) | Cписок Acces Control |
| created_by | string | Кем создан ресурс |
| created_time | int | Время создания ресурса |
| def_net_id | int | Уникальный идентификатор сети, установленной по умолчанию для данной ресурсной группы. Экземпляры _compute_, создаваемые в данной ресурсной группе, по умолчанию будут иметь подключение к данной сети, если при их создании явно не указано иное.<br/>Для `def_net_type = "EXTNET" в этом параметре указан идентификатор внешней сети. Для `def_net_type = "PRIVATE" - идентификатор ViNS. |
| def_net_type | string | Тип сети, установленной по умолчанию для данной ресурсной группы. Может принимать одно из следующих значений:<br> * EXTNET - подключение во внешнюю сеть с идентификатором `def_net_id`<br> * PRIVATE - подключение в виртуальный сетевой сегмент (ViNS ) с идентификатором `def_net_id`<br> * NONE - сеть по умолчанию не задана, экземпляры _compute_ в данной ресурсной группе будут создаваться без сетевых подключений, если при их создании явно не указано иное. |
| deleted_by | string | Кем удален ресурс |
| deleted_time | int | Время удаления ресурса |
| desc | string | Текстовое описание данной ресурсной группы. |
| dirty | bool | Dirty |
| gid | int | Идентификатор grid, которому будет принадлежать создаваемая ресурсная группа. |
| guid | int | GUID |
| lock_status | string | Lock статус |
| milestones | int | Milestones |
| name | string | Имя данной ресурсной группы. Обратите внимание, что имя ресурсной группы является уникальным только в рамках одного и того же подписчика ("account"). |
| register_computes | bool | Флаг отвечающий за то зарегестрированы ли компьюты |
| resource_limits | [см. ниже](#описание-структуры-resource-limits) | Лимиты ресурсов |
| secret | string | Секрет |
| status | string | Статус resgroup |
| updated_by | string | Кем был сделан апдейт |
| updated_time | int | Время апдейта |
| vins | []int | Список id виртуальных сетей |
| computes | []int | Список id компьютов |
| cpu_allocation_parameter | string | Параметр выделения CPU |
| cpu_allocation_ratio | float | Отношение выделения CPU |
| res_types | []string | Res types |
| uniq_pools | []string | Uniq pools |
| id | int | Идентификатор данной ресурсной группы. |
### Описание структуры acl
| Параметр | Тип | Описание |
| --- | --- | --- |
| explicit | bool | Явно ли указан доступ |
| guid | string | guid Ресурса |
| right | string | Права на ресурс |
| status | string | Статус ресурса |
| type | string | Тип ресурса |
| user_group_id | string | ID user group |
### Описание структуры resources
| Параметр | Тип | Описание |
| --- | --- | --- |
| current | Struct{} [см. ниже](#описание-структуры-current-и-reserved) | Информация о текуших ресурсах |
| reserved | Struct{} [см. ниже](#описание-структуры-current-и-reserved) | Информация о зарезверированных аккаунтом ресурсах |
### Описание структуры current и reserved
| Параметр | Тип | Описание |
| --- | --- | --- |
| cpu | int | Количество CPU |
| disk_size | int | Размер диска |
| disk_size_max | int | Максимальный размер диск |
| extips | int | Внешние IPs |
| exttraffic | int | Внешний Traffic |
| gpu | int | Количество GPU |
| ram | int | Количество RAM |
| seps | []Struct{} [см . ниже](#описание-структуры-seps) | Информация о seps |
### Описание структуры seps
| Параметр | Тип | Описание |
| --- | --- | --- |
| sep_id | int | ID SEP |
| data_name | string | Имя пула информации внутри SEP'а |
| disk_size | int | Количество занятого места |
| disk_size_max | int | Размер диска |
### Описание структуры resources limits
| Параметр | Тип | Описание |
| --- | --- | --- |
| cu_c | float | Количество ядер CPU |
| cu_d | float | Размер диска |
| cu_i | float | Количество публичных IP адресов |
| cu_m | float | размер RAM |
| cu_np | float | Хранилище траффика |
| gpu_units | float | количество GPU ядер |
## Пример использования
Пример вызова _data source_ функции **decort_resgroup**:
```terraform
data "decort_resgroup" "rg" {
#id ресурсной группы
#обязательный параметр
#тип - целое число
rg_id = 1535
}
```
Данный пример подразумевает, что ранее по тексту tf-файла выполнена корректная инициализация провайдера (подробнее об инициализации Terraform провайдера DECORT см. соответствующий [раздел](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/04.02-Инициализация-Terraform-провайдера-DECORT.md) и [пример](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/02.-Пример-работы.md)).
После успешного завершения такого вызова **decort_resgroup** в переменной `data.decort_resgroup.rg` будут сохранены возвращаемые значения. В частности, для получения идентификатора ресурсной группы следует использовать конструкцию `data.decort_resgroup.rg.id`

@ -0,0 +1,115 @@
_Data source_ функция **decort_disk** служит для получения информации об уже существующем диске.
## Изменения в версии 3.4.0
- В возвращаемые значения добавлено новое поле shareable
- В возвращаемые значения добавлено новое поле present_to
- Убраны поля compute_id и compute_name и заменены на поле computes, которое представляет из себя список структур [см. ниже](#описание-структуры-computes)
## Аргументы
_Data source_ функция **decort_disk** принимает следующие аргументы:
| Аргумент | Тип | Обязательный | Описание |
| --- | --- | --- | --- |
| disk_id | int | :heavy_check_mark: | Идентификатор диска |
## Возвращаемые значения
В случае успешного выполнения _data source_ функция **decort_disk** возвращает в указанную при вызове переменную следующие значения:
| Параметр | Тип | Описание |
| --- | --- | --- |
| account_id | int | Уникальный идентификатор подписчика-владельца диска |
| account_name | string | Имя подписчика ("account"), которому принадлежит данный диск |
| computes | Struct{} [см. ниже](#описание-структуры-computes) | Информация о компьютах (виртуальных машинах) |
| created_time | int | Время создания |
| deleted_time | int | Время удаления |
| desc | string | Текстовое описание диска |
| destruction_time | int | Время окончательного удаления |
| devicename | string | Наименование устройства |
| disk_id | int | Идентификатор диска. Дублирует значение параметра `id`. |
| disk_path | string | Адрес диска |
| gid | int | Идентификатор площадки (grid id) |
| id | int | Идентификатор диска |
| image_id | int | Идентификатор образа, содержимое которого было склонировано/скопировано в данный диск при его создании. 0 означает, что данный диск не создавался как клон/копия какого-либо образа |
| images | []int | Идентификаторы образов, использующих диск |
| iotune | Struct{}[см. ниже](#описание-структуры-iotune) | Информация об ограничениях IO диска |
| disk_name | string | Наименование диска |
| order | int | Номер диска |
| params | string | Параметры диска |
| parent_id | int | id родительского диска |
| pci_slot | int | id pci слота, к которому подключен диск |
| pool | string | Имя пула в системе хранения, на ресурсах которой размещён данный диск |
| present_to | []int | Список ID ресурсов, которым предоставлен диск |
| purge_time | int | Время последней попытки |
| replication | Struct{} [см. ниже](#описание-структуры-replication) | Информация о реплике диска |
| res_id | int | id ресурса |
| res_name | string | Наименование ресурса |
| role | string | Роль диска |
| sep_id | int | Идентификатор Storage Endpoint Provider (SEP). SEP это способ идентифицировать конкретную систему хранения, на ресурсах которой размещён данный диск |
| sep_type | string | Тип SEP. Определяет тип системы хранения и содержит одно из заданных в облачной платформе значений |
| shareable | bool | Флаг, отвечающий за доступность диска дургим ресурсам |
| size_max | int | Размер диска в ГБ |
| size_used | float | Кол-во используемого места, в ГБ |
| snapshots | []Struct{}[см. ниже](#описание-структуры-snapshots) | Снимки состояния диска |
| status | string | Статус диска |
| tech_status | string | Технический статус диска |
| type | string | Тип диска с точки зрения его роли в составе _compute_. Может принимать одно из фиксированных значений:<br/>"B" - признак загрузочного диска ("boot").<br/>"D" - признак дополнительного диска ("data") |
| vmid | int | Идентификатор виртуальной машины (устаревшее) |
### Описание структуры computes
| Параметр | Тип | Описание |
| --- | --- | --- |
| compute_id | int | Идентификатор компьюта |
| compute_name | string | Имя компьюта |
### Описание структуры iotune
| Параметр | Тип | Описание |
| --- | --- | --- |
| read_bytes_sec | int | Кол-во байт для чтения в секунду |
| read_bytes_sec_max | int | Максимальное кол-во байт для чтения |
| read_iops_sec | int | Кол-во операций чтения io в секунду |
| read_iops_sec_max | int | Максимальное число io операций чтения |
| size_iops_sec | int | Размер io операций |
| total_bytes_sec | int | Общий размер байт в секунду |
| total_bytes_sec_max | int | Максимальный общий размер байт в секунду |
| total_iops_sec | int | Общее кол-во io операций в секунду |
| total_iops_sec_max | int | Максимальное общее кол-во io операций в секунду |
| write_bytes_sec | int | Кол-во байт для записи в секунду |
| write_bytes_sec_max | int | Максимальное кол-во байт для записи в секунду |
| write_iops_sec | int | Кол-во операций записи в секунду |
| write_iops_sec_max | int | Максимальное число операций записей |
### Описание структуры replication
| Параметр | Тип | Описание |
| --- | --- | --- |
| disk_id | int | id диска |
| pool_id | string | id пула |
| role | string | Роль диска (главный или реплика) |
| self_volume_id | string | id раздела |
| storage_id | int | id хранилища |
| volume_id | int | id раздела |
### Описание структуры snapshots
| Параметр | Тип | Описание |
| --- | --- | --- |
| guid | string | id снимка |
| label | string | Наименование снимка |
| res_id | string | Ссылка на снимок |
| snap_set_guid | string | Установленный id снимка |
| snap_set_time | int | Установленное время снимка |
| timestamp | int | Время снимка |
## Пример использования
Пример вызова _data source_ функции **decort_disk**:
```terraform
data "decort_disk" "acl" {
#фильтр по id диска
#обязательный параметр
#тип - целое число
disk_id = 49304
}
```
Данный пример подразумевает, что ранее по тексту tf-файла выполнена корректная инициализация провайдера (подробнее об инициализации Terraform провайдера DECORT см. соответствующий [раздел](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/04.02-Инициализация-Terraform-провайдера-DECORT.md) и [пример](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/02.-Пример-работы.md)).
После успешного завершения такого вызова **decort_disk** в переменной `data.decort_disk.my_data_disk` будут сохранены возвращаемые значения. В частности, для получения наименования диска следует использовать конструкцию `data.decort_disk.my_data_disk.acl`

@ -0,0 +1,292 @@
_Data source_ функция **decort_vins** служит для получения информации об уже существующем виртуальном сетевом сегменте (Virtual Network Segment, ViNS).
## Аргументы
_Data source_ функция **decort_vins** принимает следующие аргументы:
| Аргумент | Тип | Обязательный | Описание |
| --- | --- | --- | --- |
| vins_id | int | :heavy_check_mark: | ID виртуальной сети |
## Возвращаемые значения
В случае успешного выполнения _data source_ функция **decort_vins** возвращает в указанную при вызове переменную следующие значения:
| Параметр | Тип | Описание |
| --- | --- | --- |
| vnf_dev | []Struct{} [см. ниже](#описание-структуры-vnf_dev) | VNFDEV |
| \_ckey | string | CKey |
| account_id | int | Уникальный идентификатор подписчика-владельца ViNS. |
| account_name | string | Имя подписчика ("account"), которому принадлежит ViNS. |
| computes | []Struct{} [см. ниже](#описание-структуры-computes) | Информация о компьютах |
| default_gw | string | Шлюз по умолчанию |
| default_qos | []Struct{} [см. ниже](#описание-структуры-qos) | qos виртуальной сети |
| desc | string | Текстовое описание ViNS. |
| gid | int | Grid ID |
| guid | int | ID ресурса |
| lock_status | string | Статус доступа виртуальной сети |
| manager_id | int | ID manager |
| manager_type | string | Type of manager |
| milestones | int | Milestones |
| name | string | Имя ViNS. |
| net_mask | int | Маска подсети |
| network | string | Сеть Vins |
| pre_reservations_num | int | Кол-во зарезервированных ip адресов |
| redundant | bool | Redudant |
| rg_id | int | Идентификатор ресурсной группы, на уровне которой создан ViNS. Для ViNS, существующих на уровне "account", данный параметр будет равен 0. |
| rg_name | string | Имя ресурсной группы |
| sec_vnf_dev_id | int | ID sec vnf |
| status | string | Статус |
| user_managed | bool | Флаг user managed |
| vnfs | []Struct{} [см. ниже](#описание-структуры-vnfs) | VNFS |
| vxlan_id | int | ID vxlan |
### Описание структуры vnf_dev
| Параметр | Тип | Описание |
| --- | --- | --- |
| \_ckey | string | Ckey |
| account_id | int | ID аккаунта |
| capabilities | []string | Возможности vnf_dev |
| config | Struct{} [см. ниже](#описание-структуры-config) | Конфиг VNF |
| config_saved | bool | Флаг, отвечающий за то сохранен ли конфиг |
| custom_pre_cfg | bool | Custom |
| desc | string | Описание |
| gid | int | Grid ID |
| guid | int | ID ресурса |
| vnf_id | int | ID vnf |
| interfaces | []Struct{} [см. ниже](#описание-структуры-interfaces) | Информация о интерфейсах |
| lock_status | string | Статус доступа vnf_dev |
| milestones | int | Этапы |
| vnf_name | string | Имя VNF |
| status | string | Статус |
| tech_status | string | Технический статус |
| type | string | Тип vnf |
| vnc_password | string | vnc пароль |
| vins | []int | Список виртуальных сетей |
### Описание структуры config
| Параметр | Тип | Описание |
| --- | --- | --- |
| mgmt | Struct{} [см. ниже](#описание-структуры-mgmt) | Config Mgmt |
| resources | []Struct{} [см. ниже](#описание-структуры-resources) | Config resources |
### Описание структуры mgmt
| Параметр | Тип | Описание |
| --- | --- | --- |
| ip_addr | string | IP адрес mgmt |
| password | string | Пароль юзера |
| ssh_key | string | Публичный SSH ключ |
| user | string | Имя юзера |
### Описание структуры resources
| Параметр | Тип | Описание |
| --- | --- | --- |
| cpu | int | Кол-во cpu ресурса |
| ram | int | Кол-во ram ресурса |
| stack_id | int | ID stack ресурса |
| uuid | string | UUID ресурса |
### Описание структуры interfaces
| Параметр | Тип | Описание |
| --- | --- | --- |
| conn_id | int | ID коннекта |
| conn_type | string | Тип коннекта |
| def_gw | string | Шлюз по умолчанию |
| flipgroup_id | int | ID flipgroup |
| guid | string | ID ресурса |
| ip_address | string | IP адрес интерфейса |
| listen_ssh | bool | Флаг, говорящий о том, слушается ли ssh |
| mac | string | MAC адрес интерфейса |
| mtu | string | Максимальный объём данных, который может быть передан за одну итерацию |
| name | string | Имя интерфейса |
| net_id | int | ID сети |
| net_mask | int | Маска |
| net_type | string | Тип сети |
| node_id | int | ID узла |
| pci_slot | int | Слот pci |
| bus_number | int | Номер шины |
| qos | Struct{} [см. ниже](#описание-структуры-qos) | QOS |
| target | string | Таргет интерфейса |
| type | string | Тип интерфейса |
| vnfs | []int | Список ID vnf |
| libvirt_settings | []Struct{}[см. ниже](#описание-структуры-libvirt_settings) | Параметры libvirt virtio интерфейса |
### Описание структуры libvirt_settings
| Параметр | Тип | Описание |
| --- | --- | --- |
| guid | string | GUID |
| txmode | string | TX mode |
| ioeventfd | string | IO event |
| event_idx | string | Event ID |
| queues | int | Количество очередей |
| rx_queue_size | int | Длина очереди RX |
| tx_queue_size | int | Длина очереди TX |
### Описание структуры computes
| Параметр | Тип | Описание |
| --- | --- | --- |
| compute_id | int | ID компьюта |
| compute_name | string | Имя компьюта |
### Описание структуры qos
| Параметр | Тип | Описание |
| --- | --- | --- |
| e_rate | int | E rate |
| guid | string | ID ресурса |
| in_brust | int | In brust |
| in_rate | int | In rate |
### Описание структуры vnfs
| Параметр | Тип | Описание |
| --- | --- | --- |
| dhcp | []Struct{} [см. ниже](#описание-структуры-dhcp) | информаиця о DHCP |
| gw | []Struct{} [см. ниже](#описание-структуры-gw) | GW |
| nat | []Struct{} [см. ниже](#описание-структуры-nat) | NAT |
### Описание структуры dhcp
| Параметр | Тип | Описание |
| --- | --- | --- |
| \_ckey | string | CKey |
| account_id | int | Уникальный идентификатор подписчика-владельца ViNS. |
| config | Struct{} [см. ниже](#описание-структуры-dhcp-config) | Информация о DHCP конфиге |
| created_time | int | Время создания |
| devices | []Struct{} [см. ниже](#описание-структуры-devices) | Информация о девайсах |
| gid | int | GRID ID |
| guid | int | ID ресурса |
| dhcp_id | int | ID dhcp |
| lock_status | string | Статус доступа виртуальной сети |
| milestones | int | Milestones |
| owner_id | int | ID владельца |
| owner_type | string | Тип владельца |
| pure_virtual | bool | Флаг, показывающий является ли ресурс чисто виртуальным |
| status | string | Статус |
| tech_status | string | Технический статус |
| type | string | Тип ресурса |
### Описание структуры dhcp config
| Параметр | Тип | Описание |
| --- | --- | --- |
| default_gw | string | Шлюз по умолчанию |
| dns | []string | Список dns |
| ip_end | string | Конец диапазона IP адресов |
| ip_start | string | Старт диапазона IP адресов |
| lease | int | срок |
| netmask | int | Маска сети |
| network | string | Сеть |
| reservations | []Struct{} [см. ниже](#описание-структуры-reservations) | Информация о резервациях |
### Описание структуры reservations
| Параметр | Тип | Описание |
| --- | --- | --- |
| account_id | int | ID аккаунта |
| ip | string | IP адрес |
| mac | string | MAC адрес |
| type | string | Тип |
| vm_id | int | ID виртуальной машины |
### Описание структуры devices
| Параметр | Тип | Описание |
| --- | --- | --- |
| primary | Struct{} [см. ниже](#описание-структуры-primary) | Первичная информация |
### Описание структуры primary
| Параметр | Тип | Описание |
| --- | --- | --- |
| dev_id | int | ID dev |
| iface01 | string | Интерфейс 1 |
| iface02 | string | Интерфейс 2 |
### Описание структуры gw
| Параметр | Тип | Описание |
| --- | --- | --- |
| \_ckey | string | CKey |
| account_id | int | Уникальный идентификатор подписчика-владельца ViNS. |
| config | Struct{} [см. ниже](#описание-структуры-gw-config) | Информация о конфиге |
| created_time | int | Время создания |
| devices | []Struct{} [см. ниже](#описание-структуры-devices) | Информация о девайсах |
| gid | int | GRID ID |
| guid | int | ID ресурса |
| gw_id | int | ID GW |
| lock_status | string | Статус доступа виртуальной сети |
| milestones | int | Milestones |
| owner_id | int | ID владельца |
| owner_type | string | Тип владельца |
| pure_virtual | bool | Флаг, показывающий является ли ресурс чисто виртуальным |
| status | string | Статус |
| tech_status | string | Технический статус |
| type | string | Тип ресурса |
### Описание структуры gw config
| Параметр | Тип | Описание |
| --- | --- | --- |
| default_gw | string | Шлюз по умолчанию |
| ext_net_id | int | ID внешней сети |
| ext_net_ip | string | IP внешней сети |
| ext_netmask | int | Маска внешней сети |
| qos | Struct{} [см. ниже](#описание-структуры-qos) | QOS |
### Описание структуры nat
| Параметр | Тип | Описание |
| --- | --- | --- |
| \_ckey | string | CKey |
| account_id | int | Уникальный идентификатор подписчика-владельца ViNS. |
| created_time | int | Время создания |
| config | Struct{} [см. ниже](#описание-структуры-nat-config) | Информация о конфиге |
| devices | []Struct{} [см. ниже](#описание-структуры-devices) | Информация о девайсах |
| gid | int | GRID ID |
| guid | int | ID ресурса |
| nat_id | int | ID NAT |
| lock_status | string | Статус доступа виртуальной сети |
| milestones | int | Milestones |
| owner_id | int | ID владельца |
| owner_type | string | Тип владельца |
| pure_virtual | bool | Флаг, показывающий является ли ресурс чисто виртуальным |
| status | string | Статус |
| tech_status | string | Технический статус |
| type | string | Тип ресурса |
### Описание структуры nat config
| Параметр | Тип | Описание |
| --- | --- | --- |
| net_mask | int | Маска сети |
| network | string | Сеть |
| rules | []Struct{} [см. ниже](#описание-структуры-rules) | Правила NAT |
### Описание структуры rules
| Параметр | Тип | Описание |
| --- | --- | --- |
| rule_id | int | ID правила |
| local_ip | string | Локальный IP адрес |
| local_port | int | Локальный порт |
| protocol | string | Протокол |
| public_port_end | int | Конец диапазона портов |
| public_port_start | int | Начало диапазона портов |
| vm_id | int | ID виртуальной машины |
| vm_name | string | Имя виртуальной машины |
## Пример использования
Пример вызова _data source_ функции **decort_vins**:
```terraform
data "decort_vins" "vins" {
#обязательный параметр
#id желаемого vins
#тип - целое число
vins_id = 10101
}
```
После успешного завершения такого вызова **decort_vins** в переменной `data.decort_vins.vins` будут сохранены возвращаемые значения. В частности, для получения идентификатора ViNS следует использовать конструкцию `data.decort_vins.vins.id`

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save