Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
efe0c88556 | ||
| 5496073a0c | |||
| dc39a6412e |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,4 +4,5 @@ url_scrapping/
|
||||
terraform-provider-decort*
|
||||
.vscode/
|
||||
.DS_Store
|
||||
|
||||
vendor/
|
||||
.idea/
|
||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,16 +1,19 @@
|
||||
## Version 4.7.3
|
||||
## Version 4.8.2
|
||||
|
||||
### Добавлено
|
||||
### Исправлено
|
||||
|
||||
#### 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-854 | Исправлена ошибка, при которой неккоректно закреплялась vm к stack, теперь закрепление происходит к stack_id, указанному при создании resource `decort_cb_kvmvm` в cloudbroker/kvmvm |
|
||||
| BATF-853 | Исправлена ошибка удаления виртуальной машины с прикрепленными PCI девайсами в resource `decort_cb_kvmvm` в cloudbroker/kvmvm и resource `decort_kvmvm` в cloudapi/kvmvm |
|
||||
| BATF-862 | Исправлена логика смены image_id виртуальной машины в resource `decort_cb_kvmvm` в cloudbroker/kvmvm и resource `decort_kvmvm` в cloudapi/kvmvm |
|
||||
|
||||
|
||||
### Удалено
|
||||
|
||||
#### kvmvm
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BATF-648 | Обязательное поле `mac` в опциональном блок `libvirt_settings` в resource `decort_cb_kvmvm` в cloudbroker/kvmvm |
|
||||
| BATF-854 | Опциональное поле `target_stack_id` в resource `decort_cb_kvmvm` в cloudbroker/kvmvm |
|
||||
| BATF-862 | Опциональные поля `data_sisks, auto_start` в resource `decort_cb_kvmvm` в cloudbroker/kvmvm и resource `decort_kvmvm` в cloudapi/kvmvm |
|
||||
2
Makefile
2
Makefile
@@ -7,7 +7,7 @@ ZIPDIR = ./zip
|
||||
BINARY=${NAME}
|
||||
WORKPATH= ./examples/terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAMESPACE}/${VERSION}/${OS_ARCH}
|
||||
MAINPATH = ./cmd/decort/
|
||||
VERSION=4.7.3
|
||||
VERSION=4.8.2
|
||||
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)
|
||||
|
||||
61
docs/data-sources/cb_extnet_reserved_ip_list.md
Normal file
61
docs/data-sources/cb_extnet_reserved_ip_list.md
Normal file
@@ -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)
|
||||
@@ -77,6 +78,7 @@ description: |-
|
||||
- `pci_devices` (List of Number)
|
||||
- `pinned` (Boolean)
|
||||
- `pool` (String)
|
||||
- `preferred_cpu` (List of Number)
|
||||
- `ram` (Number)
|
||||
- `reference_id` (String)
|
||||
- `registered` (Boolean)
|
||||
@@ -100,6 +102,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)
|
||||
@@ -99,6 +101,7 @@ Read-Only:
|
||||
- `numa_node_id` (Number)
|
||||
- `os_users` (List of Object) (see [below for nested schema](#nestedobjatt--items--os_users))
|
||||
- `pinned` (Boolean)
|
||||
- `preferred_cpu` (List of Number)
|
||||
- `ram` (Number)
|
||||
- `reference_id` (String)
|
||||
- `registered` (Boolean)
|
||||
|
||||
@@ -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)
|
||||
@@ -94,6 +95,7 @@ Read-Only:
|
||||
- `numa_node_id` (Number)
|
||||
- `os_users` (List of Object) (see [below for nested schema](#nestedobjatt--items--os_users))
|
||||
- `pinned` (Boolean)
|
||||
- `preferred_cpu` (List of Number)
|
||||
- `ram` (Number)
|
||||
- `reference_id` (String)
|
||||
- `registered` (Boolean)
|
||||
|
||||
@@ -28,12 +28,15 @@ description: |-
|
||||
- `consumption` (List of Object) (see [below for nested schema](#nestedatt--consumption))
|
||||
- `cpu_allocation_ratio` (Number)
|
||||
- `cpu_info` (List of Object) (see [below for nested schema](#nestedatt--cpu_info))
|
||||
- `dpdk` (List of Object) (see [below for nested schema](#nestedatt--dpdk))
|
||||
- `gid` (Number)
|
||||
- `id` (String) The ID of this resource.
|
||||
- `ipaddr` (List of String)
|
||||
- `isolated_cpus` (List of String)
|
||||
- `name` (String)
|
||||
- `need_reboot` (Boolean)
|
||||
- `net_addr` (List of Object) (see [below for nested schema](#nestedatt--net_addr))
|
||||
- `network_mode` (String)
|
||||
- `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)
|
||||
@@ -41,6 +44,10 @@ description: |-
|
||||
- `sriov_enabled` (Boolean)
|
||||
- `stack_id` (Number)
|
||||
- `status` (String)
|
||||
- `to_active` (List of Object) (see [below for nested schema](#nestedatt--to_active))
|
||||
- `to_installing` (List of Object) (see [below for nested schema](#nestedatt--to_installing))
|
||||
- `to_maintenance` (List of Object) (see [below for nested schema](#nestedatt--to_maintenance))
|
||||
- `to_restricted` (List of Object) (see [below for nested schema](#nestedatt--to_restricted))
|
||||
- `version` (String)
|
||||
|
||||
<a id="nestedblock--timeouts"></a>
|
||||
@@ -109,6 +116,42 @@ Read-Only:
|
||||
- `phys_count` (Number)
|
||||
|
||||
|
||||
<a id="nestedatt--dpdk"></a>
|
||||
### Nested Schema for `dpdk`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `bridges` (List of Object) (see [below for nested schema](#nestedobjatt--dpdk--bridges))
|
||||
- `hp_memory` (Map of Number)
|
||||
- `pmd_cpu` (List of Number)
|
||||
|
||||
<a id="nestedobjatt--dpdk--bridges"></a>
|
||||
### Nested Schema for `dpdk.bridges`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `backplane1` (List of Object) (see [below for nested schema](#nestedobjatt--dpdk--bridges--backplane1))
|
||||
|
||||
<a id="nestedobjatt--dpdk--bridges--backplane1"></a>
|
||||
### Nested Schema for `dpdk.bridges.backplane1`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `interfaces` (List of String)
|
||||
- `numa_node` (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`
|
||||
|
||||
@@ -156,3 +199,45 @@ Read-Only:
|
||||
- `one_g` (Number)
|
||||
- `total` (Number)
|
||||
- `two_m` (Number)
|
||||
|
||||
|
||||
|
||||
|
||||
<a id="nestedatt--to_active"></a>
|
||||
### Nested Schema for `to_active`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `actor` (String)
|
||||
- `reason` (String)
|
||||
- `time` (Number)
|
||||
|
||||
|
||||
<a id="nestedatt--to_installing"></a>
|
||||
### Nested Schema for `to_installing`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `actor` (String)
|
||||
- `reason` (String)
|
||||
- `time` (Number)
|
||||
|
||||
|
||||
<a id="nestedatt--to_maintenance"></a>
|
||||
### Nested Schema for `to_maintenance`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `actor` (String)
|
||||
- `reason` (String)
|
||||
- `time` (Number)
|
||||
|
||||
|
||||
<a id="nestedatt--to_restricted"></a>
|
||||
### Nested Schema for `to_restricted`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `actor` (String)
|
||||
- `reason` (String)
|
||||
- `time` (Number)
|
||||
|
||||
@@ -52,6 +52,7 @@ Read-Only:
|
||||
- `additional_pkgs` (List of String)
|
||||
- `cpu_info` (List of Object) (see [below for nested schema](#nestedobjatt--items--cpu_info))
|
||||
- `description` (String)
|
||||
- `dpdk` (List of Object) (see [below for nested schema](#nestedobjatt--items--dpdk))
|
||||
- `gid` (Number)
|
||||
- `guid` (String)
|
||||
- `hostkey` (String)
|
||||
@@ -86,6 +87,7 @@ Read-Only:
|
||||
- `status` (String)
|
||||
- `tags` (List of String)
|
||||
- `type` (String)
|
||||
- `uefi_firmware_file` (String)
|
||||
- `version` (String)
|
||||
|
||||
<a id="nestedobjatt--items--cpu_info"></a>
|
||||
@@ -98,6 +100,33 @@ Read-Only:
|
||||
- `phys_count` (Number)
|
||||
|
||||
|
||||
<a id="nestedobjatt--items--dpdk"></a>
|
||||
### Nested Schema for `items.dpdk`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `bridges` (List of Object) (see [below for nested schema](#nestedobjatt--items--dpdk--bridges))
|
||||
- `hp_memory` (Map of Number)
|
||||
- `pmd_cpu` (List of Number)
|
||||
|
||||
<a id="nestedobjatt--items--dpdk--bridges"></a>
|
||||
### Nested Schema for `items.dpdk.bridges`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `backplane1` (List of Object) (see [below for nested schema](#nestedobjatt--items--dpdk--bridges--backplane1))
|
||||
|
||||
<a id="nestedobjatt--items--dpdk--bridges--backplane1"></a>
|
||||
### Nested Schema for `items.dpdk.bridges.backplane1`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `interfaces` (List of String)
|
||||
- `numa_node` (Number)
|
||||
|
||||
|
||||
|
||||
|
||||
<a id="nestedobjatt--items--net_addr"></a>
|
||||
### Nested Schema for `items.net_addr`
|
||||
|
||||
|
||||
@@ -25,15 +25,14 @@ description: |-
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `ckey` (String) ckey
|
||||
- `config` (String) config
|
||||
- `consumed_by` (Set of Number) consumed by
|
||||
- `desc` (String) description
|
||||
- `gid` (Number) gid
|
||||
- `guid` (Number) guid
|
||||
- `id` (String) The ID of this resource.
|
||||
- `meta` (List of String) meta
|
||||
- `milestones` (Number) milestones
|
||||
- `multipath_num` (Number) multipath_num
|
||||
- `name` (String) name
|
||||
- `obj_status` (String) object status
|
||||
- `provided_by` (List of Number) provided by
|
||||
|
||||
@@ -49,14 +49,13 @@ Optional:
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `ckey` (String)
|
||||
- `config` (String)
|
||||
- `consumed_by` (Set of Number)
|
||||
- `desc` (String)
|
||||
- `gid` (Number)
|
||||
- `guid` (Number)
|
||||
- `meta` (List of String)
|
||||
- `milestones` (Number)
|
||||
- `multipath_num` (Number)
|
||||
- `name` (String)
|
||||
- `obj_status` (String)
|
||||
- `provided_by` (List of Number)
|
||||
|
||||
@@ -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`
|
||||
@@ -240,10 +241,7 @@ Read-Only:
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `client_type` (String)
|
||||
- `description` (String)
|
||||
- `domain_name` (String)
|
||||
- `host_name` (String)
|
||||
- `account_id` (Number)
|
||||
- `ip` (String)
|
||||
- `mac` (String)
|
||||
- `type` (String)
|
||||
|
||||
@@ -90,6 +90,7 @@ Read-Only:
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `account_id` (Number)
|
||||
- `client_type` (String)
|
||||
- `desc` (String)
|
||||
- `domainname` (String)
|
||||
|
||||
61
docs/data-sources/extnet_reserved_ip_list.md
Normal file
61
docs/data-sources/extnet_reserved_ip_list.md
Normal file
@@ -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)
|
||||
@@ -74,6 +75,7 @@ description: |-
|
||||
- `os_users` (List of Object) (see [below for nested schema](#nestedatt--os_users))
|
||||
- `pci_devices` (List of Number)
|
||||
- `pinned` (Boolean)
|
||||
- `preferred_cpu` (List of Number)
|
||||
- `ram` (Number)
|
||||
- `reference_id` (String)
|
||||
- `registered` (Boolean)
|
||||
@@ -94,6 +96,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)
|
||||
@@ -96,6 +97,7 @@ Read-Only:
|
||||
- `numa_affinity` (String)
|
||||
- `numa_node_id` (Number)
|
||||
- `pinned` (Boolean)
|
||||
- `preferred_cpu` (List of Number)
|
||||
- `ram` (Number)
|
||||
- `reference_id` (String)
|
||||
- `registered` (Boolean)
|
||||
|
||||
@@ -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)
|
||||
@@ -94,6 +95,7 @@ Read-Only:
|
||||
- `numa_affinity` (String)
|
||||
- `numa_node_id` (Number)
|
||||
- `pinned` (Boolean)
|
||||
- `preferred_cpu` (List of Number)
|
||||
- `ram` (Number)
|
||||
- `reference_id` (String)
|
||||
- `registered` (Boolean)
|
||||
|
||||
@@ -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.
|
||||
@@ -59,6 +60,7 @@ description: |-
|
||||
- `pin_to_stack` (Boolean)
|
||||
- `pool` (String) Pool to use if sepId is set, can be also empty if needed to be chosen by system.
|
||||
- `port_forwarding` (Block Set) (see [below for nested schema](#nestedblock--port_forwarding))
|
||||
- `preferred_cpu` (List of Number) Recommended isolated CPUs. Field is ignored if compute.cpupin=False or compute.pinned=False
|
||||
- `reset` (Boolean)
|
||||
- `restore` (Boolean)
|
||||
- `rollback` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--rollback))
|
||||
@@ -128,6 +130,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`
|
||||
|
||||
@@ -37,11 +37,10 @@ description: |-
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `ckey` (String) ckey
|
||||
- `guid` (Number) guid
|
||||
- `id` (String) The ID of this resource.
|
||||
- `meta` (List of String) meta
|
||||
- `milestones` (Number) milestones
|
||||
- `multipath_num` (Number) multipath_num
|
||||
- `obj_status` (String) object status
|
||||
- `tech_status` (String) tech status
|
||||
|
||||
|
||||
@@ -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`
|
||||
@@ -306,10 +307,7 @@ Read-Only:
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `client_type` (String)
|
||||
- `description` (String)
|
||||
- `domain_name` (String)
|
||||
- `host_name` (String)
|
||||
- `account_id` (Number)
|
||||
- `ip` (String)
|
||||
- `mac` (String)
|
||||
- `type` (String)
|
||||
|
||||
@@ -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.
|
||||
@@ -55,6 +56,7 @@ description: |-
|
||||
- `pin_to_stack` (Boolean)
|
||||
- `pool` (String) Pool to use if sepId is set, can be also empty if needed to be chosen by system.
|
||||
- `port_forwarding` (Block Set) (see [below for nested schema](#nestedblock--port_forwarding))
|
||||
- `preferred_cpu` (List of Number) Recommended isolated CPUs. Field is ignored if compute.cpupin=False or compute.pinned=False
|
||||
- `reset` (Boolean)
|
||||
- `restore` (Boolean)
|
||||
- `rollback` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--rollback))
|
||||
@@ -121,6 +123,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.
|
||||
|
||||
|
||||
2
go.mod
2
go.mod
@@ -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.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
4
go.sum
4
go.sum
@@ -273,5 +273,5 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
repository.basistech.ru/BASIS/decort-golang-sdk v1.9.2 h1:MPH1tMQrDN1Gri4FrQP3cx60uR3uZioEDb707D88/7c=
|
||||
repository.basistech.ru/BASIS/decort-golang-sdk v1.9.2/go.mod h1:OaUynHHuSjWMzpfyoL4au6oLcUogqUkPPBKA15pbHWo=
|
||||
repository.basistech.ru/BASIS/decort-golang-sdk v1.10.1 h1:Z6drv1seHY6nkyEdjGp2LoNKbne1ihrNRs32q93UhcM=
|
||||
repository.basistech.ru/BASIS/decort-golang-sdk v1.10.1/go.mod h1:OaUynHHuSjWMzpfyoL4au6oLcUogqUkPPBKA15pbHWo=
|
||||
|
||||
@@ -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,
|
||||
@@ -881,6 +885,13 @@ func dataSourceComputeSchemaMake() map[string]*schema.Schema {
|
||||
Type: schema.TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
"preferred_cpu": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
},
|
||||
"ram": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
@@ -950,6 +961,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,
|
||||
@@ -269,6 +273,13 @@ func itemComputeSchemaMake() map[string]*schema.Schema {
|
||||
Type: schema.TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
"preferred_cpu": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
},
|
||||
"ram": {
|
||||
Type: schema.TypeInt,
|
||||
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,
|
||||
@@ -217,6 +218,7 @@ func flattenComputeList(computes *compute.ListComputes) []map[string]interface{}
|
||||
"numa_affinity": compute.NumaAffinity,
|
||||
"numa_node_id": compute.NumaNodeId,
|
||||
"pinned": compute.Pinned,
|
||||
"preferred_cpu": compute.PreferredCPU,
|
||||
"ram": compute.RAM,
|
||||
"reference_id": compute.ReferenceID,
|
||||
"registered": compute.Registered,
|
||||
@@ -362,6 +364,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)
|
||||
@@ -413,6 +416,7 @@ func flattenCompute(d *schema.ResourceData, computeRec compute.RecordCompute, pc
|
||||
return err
|
||||
}
|
||||
d.Set("pinned", computeRec.Pinned)
|
||||
d.Set("preferred_cpu", computeRec.PreferredCPU)
|
||||
d.Set("ram", computeRec.RAM)
|
||||
d.Set("reference_id", computeRec.ReferenceID)
|
||||
d.Set("registered", computeRec.Registered)
|
||||
@@ -429,6 +433,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 +618,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)
|
||||
@@ -655,6 +661,7 @@ func flattenDataCompute(d *schema.ResourceData, computeRec compute.RecordCompute
|
||||
d.Set("natable_vins_network_name", computeRec.NatableVINSNetworkName)
|
||||
d.Set("os_users", flattenOsUsers(computeRec.OSUsers))
|
||||
d.Set("pinned", computeRec.Pinned)
|
||||
d.Set("preferred_CPU", computeRec.PreferredCPU)
|
||||
d.Set("ram", computeRec.RAM)
|
||||
d.Set("reference_id", computeRec.ReferenceID)
|
||||
d.Set("registered", computeRec.Registered)
|
||||
@@ -672,6 +679,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)
|
||||
|
||||
@@ -248,6 +248,16 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
createReqX86.HPBacked = d.Get("hp_backed").(bool)
|
||||
createReqX86.Chipset = d.Get("chipset").(string)
|
||||
|
||||
if preferredCPU, ok := d.GetOk("preferred_cpu"); ok {
|
||||
preferredList := preferredCPU.([]interface{})
|
||||
if len(preferredList) > 0 {
|
||||
for _, v := range preferredList {
|
||||
cpuNum := v.(int)
|
||||
createReqX86.PreferredCPU = append(createReqX86.PreferredCPU, int64(cpuNum))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86")
|
||||
apiResp, err := c.CloudAPI().KVMX86().Create(ctx, createReqX86)
|
||||
if err != nil {
|
||||
@@ -278,6 +288,25 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
|
||||
log.Debugf("resourceComputeCreate: new simple Compute ID %d, name %s created", computeId, d.Get("name").(string))
|
||||
|
||||
if ars, ok := d.GetOk("pci_devices"); ok {
|
||||
log.Debugf("resourceComputeCreate: add pci devices on ComputeID: %d", computeId)
|
||||
addedPciDevices := ars.(*schema.Set).List()
|
||||
if len(addedPciDevices) > 0 {
|
||||
for _, v := range addedPciDevices {
|
||||
devicesConv := v.(int)
|
||||
req := compute.AttachPCIDeviceRequest{
|
||||
ComputeID: computeId,
|
||||
DeviceID: uint64(devicesConv),
|
||||
}
|
||||
|
||||
_, err := c.CloudAPI().Compute().AttachPCIDevice(ctx, req)
|
||||
if err != nil {
|
||||
warnings.Add(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
argVal, ok = d.GetOk("extra_disks")
|
||||
if ok && argVal.(*schema.Set).Len() > 0 {
|
||||
log.Debugf("resourceComputeCreate: calling utilityComputeExtraDisksConfigure to attach %d extra disk(s)", argVal.(*schema.Set).Len())
|
||||
@@ -307,6 +336,17 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if d.Get("pin_to_stack").(bool) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// Note bene: we created compute in a STOPPED state (this is required to properly attach 1st network interface),
|
||||
// now we need to start it before we report the sequence complete
|
||||
if start, ok := d.GetOk("started"); ok {
|
||||
@@ -487,11 +527,14 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if d.Get("pin_to_stack").(bool) {
|
||||
req := compute.PinToStackRequest{
|
||||
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().PinToStack(ctx, req)
|
||||
_, err := c.CloudAPI().Compute().Update(ctx, req)
|
||||
if err != nil {
|
||||
warnings.Add(err)
|
||||
}
|
||||
@@ -507,24 +550,6 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if ars, ok := d.GetOk("pci_devices"); ok {
|
||||
log.Debugf("resourceComputeCreate: add pci devices on ComputeID: %d", computeId)
|
||||
addedPciDevices := ars.(*schema.Set).List()
|
||||
if len(addedPciDevices) > 0 {
|
||||
for _, v := range addedPciDevices {
|
||||
devicesConv := v.(int)
|
||||
req := compute.AttachPCIDeviceRequest{
|
||||
ComputeID: computeId,
|
||||
DeviceID: uint64(devicesConv),
|
||||
}
|
||||
|
||||
_, err := c.CloudAPI().Compute().AttachPCIDevice(ctx, req)
|
||||
if err != nil {
|
||||
warnings.Add(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Debugf("resourceComputeCreate: new Compute ID %d, name %s creation sequence complete", computeId, d.Get("name").(string))
|
||||
|
||||
@@ -619,7 +644,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 +653,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 {
|
||||
@@ -802,6 +827,22 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
resizeReq.CPU = 0
|
||||
}
|
||||
|
||||
if resizeReq.CPU != 0 {
|
||||
if preferredCPU, ok := d.GetOk("preferred_cpu"); ok {
|
||||
preferredList := preferredCPU.([]interface{})
|
||||
if len(preferredList) > 0 {
|
||||
for _, v := range preferredList {
|
||||
cpuNum := v.(int)
|
||||
resizeReq.PreferredCPU = append(resizeReq.PreferredCPU, int64(cpuNum))
|
||||
}
|
||||
}
|
||||
}
|
||||
oldPCPU, newPCPU := d.GetChange("preferred_cpu")
|
||||
if len(oldPCPU.([]interface{})) != 0 && len(newPCPU.([]interface{})) == 0 {
|
||||
resizeReq.PreferredCPU = []int64{-1}
|
||||
}
|
||||
}
|
||||
|
||||
oldRam, newRam := d.GetChange("ram")
|
||||
if oldRam.(int) != newRam.(int) {
|
||||
resizeReq.RAM = uint64(newRam.(int))
|
||||
@@ -855,14 +896,31 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("network") {
|
||||
err = utilityComputeNetworksConfigure(ctx, d, m)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
if d.HasChange("pin_to_stack") {
|
||||
oldPin, newPin := d.GetChange("pin_to_stack")
|
||||
if !newPin.(bool) {
|
||||
req := compute.UnpinFromStackRequest{
|
||||
ComputeID: computeRec.ID,
|
||||
}
|
||||
|
||||
_, err := c.CloudAPI().Compute().UnpinFromStack(ctx, req)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if !oldPin.(bool) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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", "preferred_cpu") {
|
||||
req := compute.UpdateRequest{
|
||||
ComputeID: computeRec.ID,
|
||||
}
|
||||
@@ -876,21 +934,32 @@ 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)
|
||||
}
|
||||
if d.HasChange("preferred_cpu") {
|
||||
if preferredCPU, ok := d.GetOk("preferred_cpu"); ok {
|
||||
preferredList := preferredCPU.([]interface{})
|
||||
if len(preferredList) > 0 {
|
||||
for _, v := range preferredList {
|
||||
cpuNum := v.(int)
|
||||
req.PreferredCPU = append(req.PreferredCPU, int64(cpuNum))
|
||||
}
|
||||
}
|
||||
}
|
||||
oldPCPU, newPCPU := d.GetChange("preferred_cpu")
|
||||
if len(oldPCPU.([]interface{})) != 0 && len(newPCPU.([]interface{})) == 0 {
|
||||
req.PreferredCPU = []int64{-1}
|
||||
}
|
||||
}
|
||||
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", "preferred_cpu") && d.Get("started").(bool) {
|
||||
isStopRequired = true
|
||||
}
|
||||
if isStopRequired {
|
||||
@@ -912,6 +981,13 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("network") {
|
||||
err = utilityComputeNetworksConfigure(ctx, d, m)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("disks") {
|
||||
deletedDisks := make([]interface{}, 0)
|
||||
addedDisks := make([]interface{}, 0)
|
||||
@@ -1465,30 +1541,6 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("pin_to_stack") {
|
||||
oldPin, newPin := d.GetChange("pin_to_stack")
|
||||
if !newPin.(bool) {
|
||||
req := compute.UnpinFromStackRequest{
|
||||
ComputeID: computeRec.ID,
|
||||
}
|
||||
|
||||
_, err := c.CloudAPI().Compute().UnpinFromStack(ctx, req)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if !oldPin.(bool) {
|
||||
req := compute.PinToStackRequest{
|
||||
ComputeID: computeRec.ID,
|
||||
}
|
||||
|
||||
_, err := c.CloudAPI().Compute().PinToStack(ctx, req)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("pause") {
|
||||
oldPause, newPause := d.GetChange("pause")
|
||||
if !newPause.(bool) {
|
||||
@@ -1531,6 +1583,9 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
ComputeID: computeRec.ID,
|
||||
Force: false,
|
||||
}
|
||||
if forceStop, ok := d.GetOk("force_stop"); ok {
|
||||
stopReq.Force = forceStop.(bool)
|
||||
}
|
||||
|
||||
_, err := c.CloudAPI().Compute().Stop(ctx, stopReq)
|
||||
if err != nil {
|
||||
@@ -1541,15 +1596,13 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
req := compute.RedeployRequest{
|
||||
ComputeID: computeRec.ID,
|
||||
ImageID: uint64(newImage.(int)),
|
||||
DataDisks: "KEEP",
|
||||
}
|
||||
|
||||
if diskSize, ok := d.GetOk("boot_disk_size"); ok {
|
||||
req.DiskSize = uint64(diskSize.(int))
|
||||
}
|
||||
if dataDisks, ok := d.GetOk("data_disks"); ok {
|
||||
req.DataDisks = dataDisks.(string)
|
||||
}
|
||||
if autoStart, ok := d.GetOk("auto_start"); ok {
|
||||
if autoStart, ok := d.GetOk("started"); ok {
|
||||
req.AutoStart = autoStart.(bool)
|
||||
}
|
||||
if forceStop, ok := d.GetOk("force_stop"); ok {
|
||||
@@ -1665,6 +1718,16 @@ func resourceComputeDelete(ctx context.Context, d *schema.ResourceData, m interf
|
||||
c := m.(*controller.ControllerCfg)
|
||||
computeId, _ := strconv.ParseUint(d.Id(), 10, 64)
|
||||
|
||||
if start, ok := d.GetOk("started"); ok {
|
||||
if start.(bool) {
|
||||
req := compute.StopRequest{ComputeID: computeId}
|
||||
log.Debugf("resourceComputeDelete: stoping Compute ID %d", computeId)
|
||||
if _, err := c.CloudAPI().Compute().Stop(ctx, req); err != nil {
|
||||
diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pciList, ok := d.GetOk("pci_devices")
|
||||
|
||||
if d.Get("permanently").(bool) && ok {
|
||||
@@ -2123,11 +2186,11 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema {
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
"auto_start": {
|
||||
"auto_start_w_node": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
Description: "Flag for redeploy compute",
|
||||
Computed: true,
|
||||
Description: "Flag for start compute after node exits from MAINTENANCE state",
|
||||
},
|
||||
"force_stop": {
|
||||
Type: schema.TypeBool,
|
||||
@@ -2141,13 +2204,6 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema {
|
||||
Default: false,
|
||||
Description: "Flag for resize compute",
|
||||
},
|
||||
"data_disks": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validation.StringInSlice([]string{"KEEP", "DETACH", "DESTROY"}, false),
|
||||
Default: "DETACH",
|
||||
Description: "Flag for redeploy compute",
|
||||
},
|
||||
"started": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
@@ -2193,6 +2249,15 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema {
|
||||
Default: false,
|
||||
Description: "Use Huge Pages to allocate RAM of the virtual machine. The system must be pre-configured by allocating Huge Pages on the physical node.",
|
||||
},
|
||||
"preferred_cpu": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
Description: "Recommended isolated CPUs. Field is ignored if compute.cpupin=False or compute.pinned=False",
|
||||
},
|
||||
"pci_devices": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
@@ -2411,6 +2476,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 +2513,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",
|
||||
"disks", "extra_disks", "tags", "port_forwarding", "user_access", "snapshot", "pci_devices") {
|
||||
if diff.HasChanges() || diff.HasChanges("chipset", "pin_to_stack", "auto_start_w_node", "network", "affinity_rules", "anti_affinity_rules",
|
||||
"extra_disks", "tags", "port_forwarding", "user_access", "snapshot", "pci_devices", "preferred_cpu") {
|
||||
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,21 +34,45 @@ 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 {
|
||||
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("") // ensure ID is empty in this case
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
diagnosis, err := utilityGridGetDiagnosisCheckPresence(ctx, d, m)
|
||||
if err != nil {
|
||||
d.SetId("")
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
d.SetId(strconv.Itoa(d.Get("gid").(int)))
|
||||
d.Set("diagnosis", diagnosis)
|
||||
|
||||
log.Debugf("dataSourceGridGetDiagnosisRead: write data to file with name: %s", filePath)
|
||||
_, err = file.WriteString(diagnosis)
|
||||
if err != nil {
|
||||
d.SetId("") // ensure ID is empty in this case
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
id := uuid.New()
|
||||
d.SetId(id.String())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -66,29 +90,3 @@ func DataSourceGridGetDiagnosis() *schema.Resource {
|
||||
Schema: dataSourceGridGetDiagnosisSchemaMake(),
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceGridPostDiagnosisRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
|
||||
diagnosis, err := utilityGridPostDiagnosisCheckPresence(ctx, d, m)
|
||||
if err != nil {
|
||||
d.SetId("")
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
d.SetId(strconv.Itoa(d.Get("gid").(int)))
|
||||
d.Set("diagnosis", diagnosis)
|
||||
return nil
|
||||
}
|
||||
|
||||
func DataSourceGridPostDiagnosis() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
SchemaVersion: 1,
|
||||
|
||||
ReadContext: dataSourceGridPostDiagnosisRead,
|
||||
|
||||
Timeouts: &schema.ResourceTimeout{
|
||||
Read: &constants.Timeout30s,
|
||||
Default: &constants.Timeout60s,
|
||||
},
|
||||
|
||||
Schema: dataSourceGridPostDiagnosisSchemaMake(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -75,6 +76,7 @@ func flattenCompute(d *schema.ResourceData, computeRec *compute.RecordCompute, p
|
||||
d.Set("numa_node_id", computeRec.NumaNodeId)
|
||||
d.Set("os_users", flattenOSUsers(computeRec.OSUsers))
|
||||
d.Set("pinned", computeRec.Pinned)
|
||||
d.Set("preferred_cpu", computeRec.PreferredCPU)
|
||||
d.Set("reference_id", computeRec.ReferenceID)
|
||||
d.Set("registered", computeRec.Registered)
|
||||
d.Set("res_name", computeRec.ResName)
|
||||
@@ -92,6 +94,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 +297,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,
|
||||
@@ -329,6 +333,7 @@ func flattenComputeList(computes *compute.ListComputes) []map[string]interface{}
|
||||
"numa_node_id": computeItem.NumaNodeId,
|
||||
"os_users": flattenOSUsers(computeItem.OSUsers),
|
||||
"pinned": computeItem.Pinned,
|
||||
"preferred_cpu": computeItem.PreferredCPU,
|
||||
"ram": computeItem.RAM,
|
||||
"reference_id": computeItem.ReferenceID,
|
||||
"registered": computeItem.Registered,
|
||||
@@ -613,6 +618,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)
|
||||
@@ -652,6 +658,7 @@ func flattenDataCompute(d *schema.ResourceData, compFacts *compute.RecordCompute
|
||||
d.Set("numa_node_id", compFacts.NumaNodeId)
|
||||
d.Set("os_users", flattenOSUsers(compFacts.OSUsers))
|
||||
d.Set("pinned", compFacts.Pinned)
|
||||
d.Set("preferred_cpu", compFacts.PreferredCPU)
|
||||
d.Set("ram", compFacts.RAM)
|
||||
d.Set("reference_id", compFacts.ReferenceID)
|
||||
d.Set("registered", compFacts.Registered)
|
||||
@@ -671,6 +678,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)
|
||||
|
||||
@@ -197,6 +197,16 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
createReqX86.HPBacked = d.Get("hp_backed").(bool)
|
||||
createReqX86.Chipset = d.Get("chipset").(string)
|
||||
|
||||
if preferredCPU, ok := d.GetOk("preferred_cpu"); ok {
|
||||
preferredList := preferredCPU.([]interface{})
|
||||
if len(preferredList) > 0 {
|
||||
for _, v := range preferredList {
|
||||
cpuNum := v.(int)
|
||||
createReqX86.PreferredCPU = append(createReqX86.PreferredCPU, int64(cpuNum))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86")
|
||||
apiResp, err := c.CloudBroker().KVMX86().Create(ctx, createReqX86)
|
||||
if err != nil {
|
||||
@@ -232,6 +242,25 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
|
||||
log.Debugf("resourceComputeCreate: new simple Compute ID %d, name %s created", computeId, d.Get("name").(string))
|
||||
|
||||
if ars, ok := d.GetOk("pci_devices"); ok {
|
||||
log.Debugf("resourceComputeCreate: add pci devices on ComputeID: %d", computeId)
|
||||
addedPciDevices := ars.(*schema.Set).List()
|
||||
if len(addedPciDevices) > 0 {
|
||||
for _, v := range addedPciDevices {
|
||||
devicesConv := v.(int)
|
||||
req := compute.AttachPCIDeviceRequest{
|
||||
ComputeID: computeId,
|
||||
DeviceID: uint64(devicesConv),
|
||||
}
|
||||
|
||||
_, err := c.CloudBroker().Compute().AttachPCIDevice(ctx, req)
|
||||
if err != nil {
|
||||
warnings.Add(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extraDisks, ok := d.GetOk("extra_disks")
|
||||
if ok && extraDisks.(*schema.Set).Len() > 0 {
|
||||
log.Debugf("resourceComputeCreate: calling utilityComputeExtraDisksConfigure to attach %d extra disk(s)", extraDisks.(*schema.Set).Len())
|
||||
@@ -260,6 +289,26 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if pin, ok := d.GetOk("pin_to_stack"); ok && pin.(bool) {
|
||||
req := compute.PinToStackRequest{
|
||||
ComputeID: computeId,
|
||||
TargetStackID: uint64(d.Get("stack_id").(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 {
|
||||
warnings.Add(err)
|
||||
}
|
||||
}
|
||||
|
||||
if libvirtSettings, ok := d.GetOk("libvirt_settings"); ok {
|
||||
if libvirtSettings.(*schema.Set).Len() > 0 {
|
||||
lvs := libvirtSettings.(*schema.Set).List()
|
||||
@@ -474,17 +523,14 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if pin, ok := d.GetOk("pin_to_stack"); ok && pin.(bool) {
|
||||
req := compute.PinToStackRequest{
|
||||
ComputeID: computeId,
|
||||
TargetStackID: uint64(d.Get("target_stack_id").(int)),
|
||||
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),
|
||||
}
|
||||
|
||||
if force, ok := d.Get("force_pin").(bool); ok {
|
||||
req.Force = force
|
||||
}
|
||||
|
||||
_, err := c.CloudBroker().Compute().PinToStack(ctx, req)
|
||||
_, err := c.CloudBroker().Compute().Update(ctx, req)
|
||||
if err != nil {
|
||||
warnings.Add(err)
|
||||
}
|
||||
@@ -507,24 +553,6 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if ars, ok := d.GetOk("pci_devices"); ok {
|
||||
log.Debugf("resourceComputeCreate: add pci devices on ComputeID: %d", computeId)
|
||||
addedPciDevices := ars.(*schema.Set).List()
|
||||
if len(addedPciDevices) > 0 {
|
||||
for _, v := range addedPciDevices {
|
||||
devicesConv := v.(int)
|
||||
req := compute.AttachPCIDeviceRequest{
|
||||
ComputeID: computeId,
|
||||
DeviceID: uint64(devicesConv),
|
||||
}
|
||||
|
||||
_, err := c.CloudBroker().Compute().AttachPCIDevice(ctx, req)
|
||||
if err != nil {
|
||||
warnings.Add(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("resourceComputeCreate: new Compute ID %d, name %s creation sequence complete", computeId, d.Get("name").(string))
|
||||
@@ -679,19 +707,25 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChanges("network", "libvirt_settings") {
|
||||
err = utilityComputeNetworksConfigure(ctx, d, m) // pass do_delta = true to apply changes, if any
|
||||
if err != nil {
|
||||
if d.HasChange("pin_to_stack") {
|
||||
if err := utilityComputePinToStack(ctx, d, m); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
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", "preferred_cpu") {
|
||||
if err := utilityComputeUpdate(ctx, d, m); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChanges("network", "libvirt_settings") {
|
||||
err = utilityComputeNetworksConfigure(ctx, d, m) // pass do_delta = true to apply changes, if any
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("disks") {
|
||||
if err := utilityComputeUpdateDisks(ctx, d, m); err != nil {
|
||||
return diag.FromErr(err)
|
||||
@@ -752,12 +786,6 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("pin_to_stack") {
|
||||
if err := utilityComputePinToStack(ctx, d, m); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("pause") {
|
||||
if err := utilityComputePause(ctx, d, m); err != nil {
|
||||
return diag.FromErr(err)
|
||||
@@ -802,6 +830,16 @@ func resourceComputeDelete(ctx context.Context, d *schema.ResourceData, m interf
|
||||
c := m.(*controller.ControllerCfg)
|
||||
computeId, _ := strconv.ParseUint(d.Id(), 10, 64)
|
||||
|
||||
if start, ok := d.GetOk("started"); ok {
|
||||
if start.(bool) {
|
||||
req := compute.StopRequest{ComputeID: computeId}
|
||||
log.Debugf("resourceComputeDelete: stoping Compute ID %d", computeId)
|
||||
if _, err := c.CloudBroker().Compute().Stop(ctx, req); err != nil {
|
||||
diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pciList, ok := d.GetOk("pci_devices")
|
||||
|
||||
if d.Get("permanently").(bool) && ok {
|
||||
@@ -839,8 +877,16 @@ 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",
|
||||
"disks", "extra_disks", "tags", "port_forwarding", "user_access", "snapshot", "pci_devices") {
|
||||
if diff.HasChanges() || diff.HasChanges("chipset", "pin_to_stack", "auto_start_w_node", "libvirt_settings", "network", "affinity_rules", "anti_affinity_rules",
|
||||
"extra_disks", "tags", "port_forwarding", "user_access", "snapshot", "pci_devices", "preferred_cpu") {
|
||||
diff.SetNewComputed("updated_time")
|
||||
diff.SetNewComputed("updated_by")
|
||||
}
|
||||
if diff.HasChanges("pin_to_stack") {
|
||||
diff.SetNewComputed("pinned")
|
||||
}
|
||||
if diff.HasChanges("started") {
|
||||
diff.SetNewComputed("tech_status")
|
||||
diff.SetNewComputed("updated_time")
|
||||
diff.SetNewComputed("updated_by")
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -788,6 +792,13 @@ func dataSourceComputeSchemaMake() map[string]*schema.Schema {
|
||||
Type: schema.TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
"preferred_cpu": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
},
|
||||
"ram": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
@@ -902,6 +913,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 +1005,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 +1165,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,
|
||||
@@ -1474,6 +1498,13 @@ func dataSourceComputeListSchemaMake() map[string]*schema.Schema {
|
||||
Type: schema.TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
"preferred_cpu": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
},
|
||||
"ram": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
@@ -1802,6 +1833,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,
|
||||
@@ -2083,6 +2118,13 @@ func dataSourceComputeListDeletedSchemaMake() map[string]*schema.Schema {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
"preferred_cpu": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
},
|
||||
"reference_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
@@ -3375,9 +3417,10 @@ func resourceComputeSchemaMake() map[string]*schema.Schema {
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
"target_stack_id": {
|
||||
Type: schema.TypeInt,
|
||||
"auto_start_w_node": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"force_pin": {
|
||||
Type: schema.TypeBool,
|
||||
@@ -3405,12 +3448,6 @@ func resourceComputeSchemaMake() map[string]*schema.Schema {
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
"auto_start": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
Description: "Flag for redeploy compute",
|
||||
},
|
||||
"force_stop": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
@@ -3423,13 +3460,6 @@ func resourceComputeSchemaMake() map[string]*schema.Schema {
|
||||
Default: false,
|
||||
Description: "Flag for resize compute",
|
||||
},
|
||||
"data_disks": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validation.StringInSlice([]string{"KEEP", "DETACH", "DESTROY"}, false),
|
||||
Default: "DETACH",
|
||||
Description: "Flag for redeploy compute",
|
||||
},
|
||||
"detach_disks": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
@@ -3459,6 +3489,15 @@ func resourceComputeSchemaMake() map[string]*schema.Schema {
|
||||
Default: false,
|
||||
Description: "Use Huge Pages to allocate RAM of the virtual machine. The system must be pre-configured by allocating Huge Pages on the physical node.",
|
||||
},
|
||||
"preferred_cpu": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
Description: "Recommended isolated CPUs. Field is ignored if compute.cpupin=False or compute.pinned=False",
|
||||
},
|
||||
"pci_devices": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
@@ -3906,6 +3945,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,
|
||||
|
||||
@@ -135,6 +135,22 @@ func utilityComputeResize(ctx context.Context, d *schema.ResourceData, m interfa
|
||||
resizeReq.CPU = 0
|
||||
}
|
||||
|
||||
if resizeReq.CPU != 0 {
|
||||
if preferredCPU, ok := d.GetOk("preferred_cpu"); ok {
|
||||
preferredList := preferredCPU.([]interface{})
|
||||
if len(preferredList) > 0 {
|
||||
for _, v := range preferredList {
|
||||
cpuNum := v.(int)
|
||||
resizeReq.PreferredCPU = append(resizeReq.PreferredCPU, int64(cpuNum))
|
||||
}
|
||||
}
|
||||
}
|
||||
oldPCPU, newPCPU := d.GetChange("preferred_cpu")
|
||||
if len(oldPCPU.([]interface{})) != 0 && len(newPCPU.([]interface{})) == 0 {
|
||||
resizeReq.PreferredCPU = []int64{-1}
|
||||
}
|
||||
}
|
||||
|
||||
oldRam, newRam := d.GetChange("ram")
|
||||
if oldRam.(int) != newRam.(int) {
|
||||
resizeReq.RAM = uint64(newRam.(int))
|
||||
@@ -852,21 +868,33 @@ 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)
|
||||
|
||||
if d.HasChange("preferred_cpu") {
|
||||
if preferredCPU, ok := d.GetOk("preferred_cpu"); ok {
|
||||
preferredList := preferredCPU.([]interface{})
|
||||
if len(preferredList) > 0 {
|
||||
for _, v := range preferredList {
|
||||
cpuNum := v.(int)
|
||||
req.PreferredCPU = append(req.PreferredCPU, int64(cpuNum))
|
||||
}
|
||||
}
|
||||
}
|
||||
oldPCPU, newPCPU := d.GetChange("preferred_cpu")
|
||||
if len(oldPCPU.([]interface{})) != 0 && len(newPCPU.([]interface{})) == 0 {
|
||||
req.PreferredCPU = []int64{-1}
|
||||
}
|
||||
}
|
||||
|
||||
// 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", "preferred_cpu") && d.Get("started").(bool) {
|
||||
isStopRequired = true
|
||||
}
|
||||
if isStopRequired {
|
||||
@@ -1428,12 +1456,17 @@ func utilityComputePinToStack(ctx context.Context, d *schema.ResourceData, m int
|
||||
if !oldPin.(bool) && newPin.(bool) {
|
||||
req := compute.PinToStackRequest{
|
||||
ComputeID: computeId,
|
||||
TargetStackID: uint64(d.Get("target_stack_id").(int)),
|
||||
TargetStackID: uint64(d.Get("stack_id").(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
|
||||
@@ -1501,6 +1534,9 @@ func utilityComputeUpdateImage(ctx context.Context, d *schema.ResourceData, m in
|
||||
if depresent, ok := d.Get("depresent").(bool); ok {
|
||||
stopReq.Depresent = depresent
|
||||
}
|
||||
if forceStop, ok := d.GetOk("force_stop"); ok {
|
||||
stopReq.Force = forceStop.(bool)
|
||||
}
|
||||
|
||||
_, err := c.CloudBroker().Compute().Stop(ctx, stopReq)
|
||||
if err != nil {
|
||||
@@ -1511,15 +1547,13 @@ func utilityComputeUpdateImage(ctx context.Context, d *schema.ResourceData, m in
|
||||
req := compute.RedeployRequest{
|
||||
ComputeID: computeId,
|
||||
ImageID: uint64(newImage.(int)),
|
||||
DataDisks: "KEEP",
|
||||
}
|
||||
|
||||
if diskSize, ok := d.GetOk("boot_disk_size"); ok {
|
||||
req.DiskSize = uint64(diskSize.(int))
|
||||
}
|
||||
if dataDisks, ok := d.GetOk("data_disks"); ok {
|
||||
req.DataDisks = dataDisks.(string)
|
||||
}
|
||||
if autoStart, ok := d.GetOk("auto_start"); ok {
|
||||
if autoStart, ok := d.GetOk("started"); ok {
|
||||
req.AutoStart = autoStart.(bool)
|
||||
}
|
||||
if forceStop, ok := d.GetOk("force_stop"); ok {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -46,11 +46,14 @@ func flattenNode(d *schema.ResourceData, item *node.RecordNode) {
|
||||
d.Set("consumption", flattenConsumption(item.Consumption))
|
||||
d.Set("cpu_info", flattenCpuInfo(item.CpuInfo))
|
||||
d.Set("cpu_allocation_ratio", item.CPUAllocationRatio)
|
||||
d.Set("dpdk", flattenDPDKItem(item.DPDK))
|
||||
d.Set("gid", item.GID)
|
||||
d.Set("ipaddr", item.IPAddr)
|
||||
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("network_mode", item.NetworkMode)
|
||||
d.Set("nic_info", flattenNicInfo(item.NicInfo))
|
||||
d.Set("numa_topology", flattenNumaTopology(item.NumaTopology))
|
||||
d.Set("reserved_cpus", flattenNodeItem(item.ReservedCPUs))
|
||||
@@ -58,6 +61,10 @@ func flattenNode(d *schema.ResourceData, item *node.RecordNode) {
|
||||
d.Set("sriov_enabled", item.SriovEnabled)
|
||||
d.Set("stack_id", item.StackID)
|
||||
d.Set("status", item.Status)
|
||||
d.Set("to_active", flattenRole(item.ToActive))
|
||||
d.Set("to_installing", flattenRole(item.ToInstalling))
|
||||
d.Set("to_maintenance", flattenRole(item.ToMaintenance))
|
||||
d.Set("to_restricted", flattenRole(item.ToRestricted))
|
||||
d.Set("version", item.Version)
|
||||
}
|
||||
|
||||
@@ -106,44 +113,46 @@ func flattenNodeList(nodes *node.ListNodes) []map[string]interface{} {
|
||||
res := make([]map[string]interface{}, 0, len(nodes.Data))
|
||||
for _, item := range nodes.Data {
|
||||
temp := map[string]interface{}{
|
||||
"additional_pkgs": flattenNodeItem(item.AdditionalPkgs),
|
||||
"cpu_info": flattenCpuInfo(item.CpuInfo),
|
||||
"description": item.Description,
|
||||
"gid": item.GID,
|
||||
"guid": item.GUID,
|
||||
"hostkey": item.HostKey,
|
||||
"node_id": item.ID,
|
||||
"ipaddr": item.IPAddr,
|
||||
"isolated_cpus": flattenNodeItem(item.IsolatedCpus),
|
||||
"lastcheck": item.LastCheck,
|
||||
"machine_guid": item.MachineGUID,
|
||||
"mainboard_sn": item.MainboardSN,
|
||||
"memory": item.Memory,
|
||||
"milestones": item.Milestones,
|
||||
"model": item.Model,
|
||||
"name": item.Name,
|
||||
"need_reboot": item.NeedReboot,
|
||||
"net_addr": flattenNetAddr(item.NetAddr),
|
||||
"network_mode": item.NetworkMode,
|
||||
"nic_info": flattenNicInfo(item.NicInfo),
|
||||
"node_uuid": item.NodeUUID,
|
||||
"numa_topology": flattenNumaTopology(item.NumaTopology),
|
||||
"peer_backup": item.PeerBackup,
|
||||
"peer_log": item.PeerLog,
|
||||
"peer_stats": item.PeerStats,
|
||||
"pgpus": item.Pgpus,
|
||||
"public_keys": item.PublicKeys,
|
||||
"release": item.Release,
|
||||
"reserved_cpus": flattenNodeItem(item.ReservedCPUs),
|
||||
"roles": item.Roles,
|
||||
"seps": item.Seps,
|
||||
"serial_num": item.SerialNum,
|
||||
"sriov_enabled": item.SriovEnabled,
|
||||
"stack_id": item.StackID,
|
||||
"status": item.Status,
|
||||
"tags": item.Tags,
|
||||
"type": item.Type,
|
||||
"version": item.Version,
|
||||
"additional_pkgs": flattenNodeItem(item.AdditionalPkgs),
|
||||
"cpu_info": flattenCpuInfo(item.CpuInfo),
|
||||
"description": item.Description,
|
||||
"dpdk": flattenDPDKItem(item.DPDK),
|
||||
"gid": item.GID,
|
||||
"guid": item.GUID,
|
||||
"hostkey": item.HostKey,
|
||||
"node_id": item.ID,
|
||||
"ipaddr": item.IPAddr,
|
||||
"isolated_cpus": flattenNodeItem(item.IsolatedCpus),
|
||||
"lastcheck": item.LastCheck,
|
||||
"machine_guid": item.MachineGUID,
|
||||
"mainboard_sn": item.MainboardSN,
|
||||
"memory": item.Memory,
|
||||
"milestones": item.Milestones,
|
||||
"model": item.Model,
|
||||
"name": item.Name,
|
||||
"need_reboot": item.NeedReboot,
|
||||
"net_addr": flattenNetAddr(item.NetAddr),
|
||||
"network_mode": item.NetworkMode,
|
||||
"nic_info": flattenNicInfo(item.NicInfo),
|
||||
"node_uuid": item.NodeUUID,
|
||||
"numa_topology": flattenNumaTopology(item.NumaTopology),
|
||||
"peer_backup": item.PeerBackup,
|
||||
"peer_log": item.PeerLog,
|
||||
"peer_stats": item.PeerStats,
|
||||
"pgpus": item.Pgpus,
|
||||
"public_keys": item.PublicKeys,
|
||||
"release": item.Release,
|
||||
"reserved_cpus": flattenNodeItem(item.ReservedCPUs),
|
||||
"roles": item.Roles,
|
||||
"seps": item.Seps,
|
||||
"serial_num": item.SerialNum,
|
||||
"sriov_enabled": item.SriovEnabled,
|
||||
"stack_id": item.StackID,
|
||||
"status": item.Status,
|
||||
"tags": item.Tags,
|
||||
"type": item.Type,
|
||||
"uefi_firmware_file": item.UEFIFirmwareFile,
|
||||
"version": item.Version,
|
||||
}
|
||||
res = append(res, temp)
|
||||
}
|
||||
@@ -205,9 +214,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 +230,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{}{
|
||||
@@ -250,3 +269,36 @@ func flattenNodeItem(m []interface{}) []string {
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func flattenDPDKItem(dpdk node.DPDK) []map[string]interface{} {
|
||||
res := make([]map[string]interface{}, 1)
|
||||
bridges := make([]map[string]interface{}, 1)
|
||||
backplane := make([]map[string]interface{}, 1)
|
||||
backplane[0] = map[string]interface{}{
|
||||
"interfaces": dpdk.Bridges.Backplane1.Interfaces,
|
||||
"numa_node": dpdk.Bridges.Backplane1.NumaNode,
|
||||
}
|
||||
|
||||
bridges[0] = map[string]interface{}{
|
||||
"backplane1": backplane,
|
||||
}
|
||||
|
||||
res[0] = map[string]interface{}{
|
||||
"bridges": bridges,
|
||||
"hp_memory": dpdk.HPMemory,
|
||||
"pmd_cpu": dpdk.PMDCPU,
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func flattenRole(role node.Role) []map[string]interface{} {
|
||||
res := make([]map[string]interface{}, 1)
|
||||
temp := map[string]interface{}{
|
||||
"actor": role.Actor,
|
||||
"reason": role.Reason,
|
||||
"time": role.Time,
|
||||
}
|
||||
res[0] = temp
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -105,6 +105,55 @@ func dataSourceNodeSchemaMake() map[string]*schema.Schema {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
"dpdk": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"bridges": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"backplane1": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"interfaces": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
"numa_node": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"hp_memory": {
|
||||
Type: schema.TypeMap,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
},
|
||||
"pmd_cpu": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"gid": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
@@ -131,6 +180,29 @@ 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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"network_mode": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"nic_info": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
@@ -253,6 +325,86 @@ func dataSourceNodeSchemaMake() map[string]*schema.Schema {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"to_active": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"actor": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"reason": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"time": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"to_installing": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"actor": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"reason": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"time": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"to_maintenance": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"actor": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"reason": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"time": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"to_restricted": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"actor": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"reason": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"time": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"version": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
@@ -349,6 +501,55 @@ func dataSourceNodeListSchemaMake() map[string]*schema.Schema {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"dpdk": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"bridges": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"backplane1": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"interfaces": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
"numa_node": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"hp_memory": {
|
||||
Type: schema.TypeMap,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
},
|
||||
"pmd_cpu": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"gid": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
@@ -631,6 +832,10 @@ func dataSourceNodeListSchemaMake() map[string]*schema.Schema {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"uefi_firmware_file": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"version": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
|
||||
@@ -37,18 +37,16 @@ import (
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/sep"
|
||||
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/flattens"
|
||||
)
|
||||
|
||||
func flattenSep(d *schema.ResourceData, desSep *sep.RecordSEP) {
|
||||
d.Set("ckey", desSep.CKey)
|
||||
d.Set("meta", flattens.FlattenMeta(desSep.Meta))
|
||||
d.Set("consumed_by", desSep.ConsumedBy)
|
||||
d.Set("desc", desSep.Description)
|
||||
d.Set("gid", desSep.GID)
|
||||
d.Set("guid", desSep.GUID)
|
||||
d.Set("sep_id", desSep.ID)
|
||||
d.Set("milestones", desSep.Milestones)
|
||||
d.Set("multipath_num", desSep.MultipathNum)
|
||||
d.Set("name", desSep.Name)
|
||||
d.Set("obj_status", desSep.ObjStatus)
|
||||
d.Set("provided_by", desSep.ProvidedBy)
|
||||
@@ -64,21 +62,20 @@ func flattenSepListItems(sl *sep.ListSEP) []map[string]interface{} {
|
||||
for _, item := range sl.Data {
|
||||
data, _ := json.Marshal(item.Config)
|
||||
temp := map[string]interface{}{
|
||||
"ckey": item.CKey,
|
||||
"meta": flattens.FlattenMeta(item.Meta),
|
||||
"consumed_by": item.ConsumedBy,
|
||||
"desc": item.Description,
|
||||
"gid": item.GID,
|
||||
"guid": item.GUID,
|
||||
"sep_id": item.ID,
|
||||
"milestones": item.Milestones,
|
||||
"name": item.Name,
|
||||
"obj_status": item.ObjStatus,
|
||||
"provided_by": item.ProvidedBy,
|
||||
"shared_with": item.SharedWith,
|
||||
"tech_status": item.TechStatus,
|
||||
"type": item.Type,
|
||||
"config": string(data),
|
||||
"consumed_by": item.ConsumedBy,
|
||||
"desc": item.Description,
|
||||
"gid": item.GID,
|
||||
"guid": item.GUID,
|
||||
"sep_id": item.ID,
|
||||
"milestones": item.Milestones,
|
||||
"name": item.Name,
|
||||
"multipath_num": item.MultipathNum,
|
||||
"obj_status": item.ObjStatus,
|
||||
"provided_by": item.ProvidedBy,
|
||||
"shared_with": item.SharedWith,
|
||||
"tech_status": item.TechStatus,
|
||||
"type": item.Type,
|
||||
"config": string(data),
|
||||
}
|
||||
res = append(res, temp)
|
||||
}
|
||||
|
||||
@@ -9,19 +9,6 @@ func dataSourceSepCSchemaMake() map[string]*schema.Schema {
|
||||
Required: true,
|
||||
Description: "sep type des id",
|
||||
},
|
||||
"ckey": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "ckey",
|
||||
},
|
||||
"meta": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Description: "meta",
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
"config": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
@@ -50,6 +37,11 @@ func dataSourceSepCSchemaMake() map[string]*schema.Schema {
|
||||
Computed: true,
|
||||
Description: "guid",
|
||||
},
|
||||
"multipath_num": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Description: "multipath_num",
|
||||
},
|
||||
"milestones": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
@@ -295,19 +287,6 @@ func dataSourceSepListSchemaMake() map[string]*schema.Schema {
|
||||
Description: "sep list",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"ckey": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "ckey",
|
||||
},
|
||||
"meta": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Description: "meta",
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
"config": {
|
||||
Description: "config",
|
||||
Type: schema.TypeString,
|
||||
@@ -346,6 +325,11 @@ func dataSourceSepListSchemaMake() map[string]*schema.Schema {
|
||||
Computed: true,
|
||||
Description: "milestones",
|
||||
},
|
||||
"multipath_num": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Description: "multipath_num",
|
||||
},
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
@@ -607,19 +591,6 @@ func resourceSepSchemaMake() map[string]*schema.Schema {
|
||||
},
|
||||
},
|
||||
},
|
||||
"ckey": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "ckey",
|
||||
},
|
||||
"meta": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Description: "meta",
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
"config": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
@@ -651,6 +622,11 @@ func resourceSepSchemaMake() map[string]*schema.Schema {
|
||||
Computed: true,
|
||||
Description: "milestones",
|
||||
},
|
||||
"multipath_num": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Description: "multipath_num",
|
||||
},
|
||||
"obj_status": {
|
||||
Type: schema.TypeString,
|
||||
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,11 @@ 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,
|
||||
"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,
|
||||
@@ -586,26 +590,11 @@ func dataSourceVinsSchemaMake() map[string]*schema.Schema {
|
||||
Description: "reservations",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"client_type": {
|
||||
Type: schema.TypeString,
|
||||
"account_id": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Description: "client type",
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "description",
|
||||
},
|
||||
"domain_name": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "domain name",
|
||||
},
|
||||
"host_name": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "host name",
|
||||
},
|
||||
"ip": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
@@ -2509,6 +2498,10 @@ func resourceVinsSchemaMake() map[string]*schema.Schema {
|
||||
Computed: true,
|
||||
Description: "type",
|
||||
},
|
||||
"vnc_password": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"vins": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
@@ -2699,26 +2692,11 @@ func resourceVinsSchemaMake() map[string]*schema.Schema {
|
||||
Description: "reservations",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"client_type": {
|
||||
Type: schema.TypeString,
|
||||
"account_id": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Description: "client type",
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "description",
|
||||
},
|
||||
"domain_name": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "domain name",
|
||||
},
|
||||
"host_name": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "host name",
|
||||
},
|
||||
"ip": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
@@ -2745,7 +2723,6 @@ func resourceVinsSchemaMake() map[string]*schema.Schema {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"created_time": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
@@ -3389,7 +3366,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
|
||||
}
|
||||
@@ -269,7 +269,7 @@ resource "decort_kvmvm" "comp" {
|
||||
#тип сети
|
||||
#обязательный параметр
|
||||
#тип - строка
|
||||
#возможные значения - "VINS", "EXTNET", "VFNIC", "DPDK"
|
||||
#возможные значения - "VINS", "EXTNET", "VFNIC", "DPDK" (при выборе типа DPDK, необходимо указать hp_backed = true)
|
||||
net_type = "VINS"
|
||||
|
||||
#id сети
|
||||
@@ -396,6 +396,17 @@ resource "decort_kvmvm" "comp" {
|
||||
#тип - булев
|
||||
pin_to_stack = true
|
||||
|
||||
#список ядер для использования в механизме vcpupinning. Количество указанных ядер должно быть равно количеству виртуальных процессоров ВМ
|
||||
#игнорируется если cpu_pin=false или pin_to_stack=false
|
||||
#опциональный параметр
|
||||
#тип - массив целых чисел
|
||||
preferred_cpu = [1234, 456]
|
||||
|
||||
#флаг для старта компьюта при рестарте ноды
|
||||
#опциональный параметр
|
||||
#тип - булев
|
||||
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
|
||||
#опциональный параметр
|
||||
#тип - строка
|
||||
|
||||
@@ -281,7 +281,7 @@ resource "decort_cb_kvmvm" "comp" {
|
||||
#network {
|
||||
#тип сети
|
||||
#обязательный параметр
|
||||
#возможные значения - "VINS", "EXTNET", "VFNIC", "DPDK"
|
||||
#возможные значения - "VINS", "EXTNET", "VFNIC", "DPDK" (при выборе типа DPDK, необходимо указать hp_backed = true)
|
||||
#тип - строка
|
||||
#net_type = "VINS"
|
||||
|
||||
@@ -409,6 +409,17 @@ resource "decort_cb_kvmvm" "comp" {
|
||||
#тип - булев
|
||||
#pin_to_stack = true
|
||||
|
||||
#список ядер для использования в механизме vcpupinning. Количество указанных ядер должно быть равно количеству виртуальных процессоров ВМ
|
||||
#игнорируется если cpu_pin=false или pin_to_stack=false
|
||||
#опциональный параметр
|
||||
#тип - массив целых чисел
|
||||
#preferred_cpu = [1234, 456]
|
||||
|
||||
#флаг для старта компьюта при рестарте ноды
|
||||
#опциональный параметр
|
||||
#тип - булев
|
||||
#auto_start_w_node = true
|
||||
|
||||
#id stack для добавления компьюта на этот стэк
|
||||
#опциональный параметр
|
||||
#тип - целое число
|
||||
|
||||
@@ -42,7 +42,7 @@ resource "decort_cb_sep" "s" {
|
||||
|
||||
#тип sep
|
||||
#обязательный параметр
|
||||
#возможные значения - des, dorado, tatlin, hitachi
|
||||
#возможные значения - des, dorado, tatlin, hitachi, ovs, local, shared
|
||||
#тип - строка
|
||||
type = "des"
|
||||
|
||||
|
||||
@@ -51,12 +51,6 @@ resource "decort_cb_vins_static_route" "sr" {
|
||||
#обязательный параметр
|
||||
#тип - строка
|
||||
gateway = "192.168.201.40"
|
||||
|
||||
#список виртуальных машин, которым будет предоставлен доступ к роуту
|
||||
#опциональный параметр
|
||||
#тип - массив целых чисел
|
||||
#compute_ids = [111,222]
|
||||
|
||||
}
|
||||
|
||||
output "sr" {
|
||||
|
||||
7
wiki/4.8.0/01.-Введение.md
Normal file
7
wiki/4.8.0/01.-Введение.md
Normal file
@@ -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.
|
||||
92
wiki/4.8.0/02.-Пример-работы.md
Normal file
92
wiki/4.8.0/02.-Пример-работы.md
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
31
wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT.md
Normal file
31
wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT.md
Normal file
@@ -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 площадки
|
||||
150
wiki/4.8.0/04.01-Установка-Terraform-провайдера-DECORT.md
Normal file
150
wiki/4.8.0/04.01-Установка-Terraform-провайдера-DECORT.md
Normal file
@@ -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.-Полезные-советы.md#8-3-настройка-локального-провайдера-для-работы-с-новыми-версиями-terraform).
|
||||
|
||||
## Установка
|
||||
Начиная с версии провайдера `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.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.
|
||||
38
wiki/4.8.0/04.03-Переключение-между-группами-API.md
Normal file
38
wiki/4.8.0/04.03-Переключение-между-группами-API.md
Normal file
@@ -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
|
||||
```
|
||||
**ОБРАТИТЕ ВНИМАНИЕ**
|
||||
Переменные окружения создаются для терминальной сессии. В сл. раз их придется задавать еще раз, если требуется режим, отличный от пользовательского.
|
||||
31
wiki/4.8.0/04.04-Получение-gid-или-grid_id.md
Normal file
31
wiki/4.8.0/04.04-Получение-gid-или-grid_id.md
Normal file
@@ -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
|
||||
}
|
||||
|
||||
```
|
||||
В файл состояния будет сохранен результат, где можно посмотреть доступные для работы площадки.
|
||||
43
wiki/4.8.0/04.05-Сборка-terraform-провайдера-в-образ.md
Normal file
43
wiki/4.8.0/04.05-Сборка-terraform-провайдера-в-образ.md
Normal file
@@ -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 провайдер.
|
||||
4
wiki/4.8.0/05.-Работа-с-terraform.md
Normal file
4
wiki/4.8.0/05.-Работа-с-terraform.md
Normal file
@@ -0,0 +1,4 @@
|
||||
Раздел описывает некоторые практики работы с terraform, которые могут быть полезны пользователю.
|
||||
Раздел включает в себя следующие статьи:
|
||||
- Импортирование ресурсов
|
||||
- Работа с таймаутами
|
||||
75
wiki/4.8.0/05.01-Импортирование-ресурсов.md
Normal file
75
wiki/4.8.0/05.01-Импортирование-ресурсов.md
Normal file
@@ -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.
|
||||
|
||||
|
||||
100
wiki/4.8.0/05.02-Работа-с-таймаутами.md
Normal file
100
wiki/4.8.0/05.02-Работа-с-таймаутами.md
Normal file
@@ -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 провайдера, который позволяет более тонко настраивать время выполнения операций.
|
||||
Как и любой подобный механизм тонкой настройки, он требует внимательного и аккуратного использования.
|
||||
29
wiki/4.8.0/05.03-Восстановление-ресурсов.md
Normal file
29
wiki/4.8.0/05.03-Восстановление-ресурсов.md
Normal file
@@ -0,0 +1,29 @@
|
||||
Ресурсы в платформе можно удалять в корзину (с возможностью восстановления), удалять сразу без возможности восстановления.
|
||||
|
||||
## Удаление ресурса
|
||||
Для удаления ресурса применяется команда:
|
||||
```bash
|
||||
terraform destroy
|
||||
```
|
||||
После выполнения данной команды произойдет следующее:
|
||||
- Будет удален файл состояния ресурса .tfstate
|
||||
- Ресурс не удалится с платформы, а будет помещен в корзину, с возможностью восстановления
|
||||
|
||||
|
||||
## Восстановление ресурсов
|
||||
__Ресурс можно восстановить, если у него есть поле `restore`__, в противном случае, необходимо воспользоваться порталом для восстановления.
|
||||
После удаления ресурса, он помечается как "Deleted" и его можно восстановить.
|
||||
Для восстановления ресурса необходимо выполнить следующие действия:
|
||||
- Создать файл .tf и описать в нем восстанавливаемый ресурс
|
||||
- Импортировать ресурс
|
||||
- Добавить поле restore со значением `true`
|
||||
- Выполнить `terraform apply`
|
||||
|
||||
## Удаление ресурсов без возможности восстановления
|
||||
Ресурсы можно удалять с платформы сразу, минуя корзину. Однако, такое удаление возможно только для ресурсов, имеющих поле `permanently`.
|
||||
Для этого необходимо выполнить сл. шаги:
|
||||
- В файле .tf добавить поле `permanently = true`
|
||||
- Применить изменения `terraform apply`
|
||||
- Выполнить удаление `terraform destroy`
|
||||
|
||||
**Проводя мгновенное удаление, ресурс восстановить будет невозможно!**
|
||||
448
wiki/4.8.0/05.04-Массовое-создание-ресурсов.-Мета-аргументы.md
Normal file
448
wiki/4.8.0/05.04-Массовое-создание-ресурсов.-Мета-аргументы.md
Normal file
@@ -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
|
||||
}
|
||||
```
|
||||
Таким образом, будут созданы ресурсы, с разной конфигурацией.
|
||||
262
wiki/4.8.0/05.05-Удаление-ресурсов.md
Normal file
262
wiki/4.8.0/05.05-Удаление-ресурсов.md
Normal file
@@ -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 <тип-ресурса>.<имя-ресурса>`
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user