diff --git a/.gitignore b/.gitignore index 0e42255..45125da 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ url_scrapping/ terraform-provider-decort* .vscode/ .DS_Store - +vendor/ +.idea/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index dd0e081..4b23866 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,54 @@ -## Version 4.7.3 +## Version 4.8.0 ### Добавлено +#### extnet +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-656 | Вычисляемое поле `account_id` в блоке `reservations` в resource `decort_cb_extnet` и data sources `decort_extnet, decort_cb_extnet` в cloudapi/extnet и cloudbroker/extnet | +| BATF-658 | Data sources `decort_extnet_reserved_ip_list, decort_cb_extnet_reserved_ip_list` в cloudapi/extnet и cloudbroker/extnet | +| BATF-658 | Опциональный блок `reserved_ip`в resource `decort_cb_extnet` в cloudbroker/extnet | + +#### image +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-667 | Вычисляемое поле `snapshot_id` в resources `decort_cb_image, decort_cb_image_from_blank_compute, decort_cb_image_from_platform_disk, decort_cb_virtual_image, decort_cb_cdrom_image` и data sources `decort_cb_image, decort_cb_image_list` в cloudbroker/image | + +#### grid +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-669 | Обязательно поле `file_path` в data source `decort_cb_grid_post_diagnosis` в cloudbroker/grid | + #### kvmvm | Идентификатор
задачи | Описание | | --- | --- | -| BATF-648 | Обязательные поля `net_type, net_id` в опциональный блок `libvirt_settings` в resource `decort_cb_kvmvm` в cloudbroker/kvmvm | -| BATF-648 | Опциональное поле `mtu` в опциональный блок `network` в resources `decort_cb_kvmvm, decort_kvmvm` в cloudbroker/kvmvm и cloudapi/kvmvm | +| BATF-656 | Вычисляемое поле `vnc_password` в resources `decort_kvmvm, decort_cb_kvmvm` и data sources `decort_kvmvm, decort_cb_kvmvm` в cloudapi/kvmvm и cloudbroker/kvmvm | +| BATF-656 | Опциональное поле `cd_image_id`в data_source `decort_cb_kvmvm_list` в cloudbroker/kvmvm | +| BATF-666 | Опциональное поле `auto_start_w_node`в resources `decort_kvmvm, decort_cb_kvmvm` в cloudapi/kvmvm и cloudbroker/kvmvm | +| BATF-666 | Вычисляемое поле `auto_start_w_node`в data_sources `decort_kvmvm, decort_kvmvm_list, decort_kvmvm_list_deleted, decort_cb_kvmvm, decort_cb_kvmvm_list, decort_cb_kvmvm_list_deleted ` в cloudapi/kvmvm и cloudbroker/kvmvm | + +#### node +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-663 | Вычисляемый блок `net_addr` в data source `decort_cb_node` в cloudbroker/node | + +#### vins +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-656 | Вычисляемое поле `vnc_password` в блоке `vnf_dev` в resources `decort_vins, decort_cb_vins` и data sources `decort_vins, decort_cb_vins` в cloudapi/vins и cloudbroker/vins | +| BATF-656 | Вычисляемое поле `account_id` в блоке `reservations` в resource `decort_vins` и data source `decort_vins` в cloudapi/vins | ### Удалено -#### kvmvm +#### grid +| Идентификатор
задачи | Описание | +| --- | --- | +| BATF-669 | Data source `decort_cb_grid_post_diagnosis` в cloudbroker/grid | +| BATF-669 | Вычисляемое поле `diagnosis` в data source `decort_cb_grid_get_diagnosis` в cloudbroker/grid | + + +#### vins | Идентификатор
задачи | Описание | | --- | --- | -| BATF-648 | Обязательное поле `mac` в опциональном блок `libvirt_settings` в resource `decort_cb_kvmvm` в cloudbroker/kvmvm | \ No newline at end of file +| BATF-656 | Вычисляемые поля `client_type, description, domain_name, hostname` в блоке `reservations` в resources `decort_vins, decort_cb_vins` и data sources `decort_vins, decort_cb_vins` в cloudapi/vins и cloudbroker/vins | +| BATF-656 | Опциональное поле `compute_ids` в resources `decort_vins_static_route, decort_cb_vins_static_route` в cloudapi/vins и cloudbroker/vins | \ No newline at end of file diff --git a/Makefile b/Makefile index b806f8e..9b00e4c 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ ZIPDIR = ./zip BINARY=${NAME} WORKPATH= ./examples/terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAMESPACE}/${VERSION}/${OS_ARCH} MAINPATH = ./cmd/decort/ -VERSION=4.7.3 +VERSION=4.8.0 OS_ARCH=$(shell go env GOHOSTOS)_$(shell go env GOHOSTARCH) FILES = ${BINARY}_${VERSION}_darwin_amd64\ diff --git a/README.md b/README.md index 0200736..55d4fb0 100644 --- a/README.md +++ b/README.md @@ -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 | diff --git a/docs/data-sources/cb_extnet.md b/docs/data-sources/cb_extnet.md index cf23a3b..06e2048 100644 --- a/docs/data-sources/cb_extnet.md +++ b/docs/data-sources/cb_extnet.md @@ -93,6 +93,7 @@ Read-Only: Read-Only: +- `account_id` (Number) - `client_type` (String) - `desc` (String) - `domain_name` (String) diff --git a/docs/data-sources/cb_extnet_reserved_ip_list.md b/docs/data-sources/cb_extnet_reserved_ip_list.md new file mode 100644 index 0000000..ea3e22a --- /dev/null +++ b/docs/data-sources/cb_extnet_reserved_ip_list.md @@ -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 + +### 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)) + + +### Nested Schema for `timeouts` + +Optional: + +- `default` (String) +- `read` (String) + + + +### Nested Schema for `items` + +Read-Only: + +- `extnet_id` (Number) +- `reservations` (List of Object) (see [below for nested schema](#nestedobjatt--items--reservations)) + + +### 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) diff --git a/docs/data-sources/cb_grid_get_diagnosis.md b/docs/data-sources/cb_grid_get_diagnosis.md index 2f86dbd..22cad6b 100644 --- a/docs/data-sources/cb_grid_get_diagnosis.md +++ b/docs/data-sources/cb_grid_get_diagnosis.md @@ -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. diff --git a/docs/data-sources/cb_grid_post_diagnosis.md b/docs/data-sources/cb_grid_post_diagnosis.md deleted file mode 100644 index 55d28a3..0000000 --- a/docs/data-sources/cb_grid_post_diagnosis.md +++ /dev/null @@ -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 - -### 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. - - -### Nested Schema for `timeouts` - -Optional: - -- `default` (String) -- `read` (String) diff --git a/docs/data-sources/cb_image.md b/docs/data-sources/cb_image.md index 8be93ca..6f33485 100644 --- a/docs/data-sources/cb_image.md +++ b/docs/data-sources/cb_image.md @@ -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 diff --git a/docs/data-sources/cb_image_list.md b/docs/data-sources/cb_image_list.md index cd26afe..826baa1 100644 --- a/docs/data-sources/cb_image_list.md +++ b/docs/data-sources/cb_image_list.md @@ -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) diff --git a/docs/data-sources/cb_kvmvm.md b/docs/data-sources/cb_kvmvm.md index a118e19..a8aa17a 100644 --- a/docs/data-sources/cb_kvmvm.md +++ b/docs/data-sources/cb_kvmvm.md @@ -33,6 +33,7 @@ description: |- - `affinity_weight` (Number) - `anti_affinity_rules` (List of Object) (see [below for nested schema](#nestedatt--anti_affinity_rules)) - `arch` (String) +- `auto_start_w_node` (Boolean) - `boot_disk_id` (Number) - `boot_disk_size` (Number) - `boot_order` (List of String) @@ -100,6 +101,7 @@ description: |- - `vgpus` (List of Number) - `virtual_image_id` (Number) - `virtual_image_name` (String) +- `vnc_password` (String) ### Nested Schema for `timeouts` diff --git a/docs/data-sources/cb_kvmvm_list.md b/docs/data-sources/cb_kvmvm_list.md index 4f75888..b8f93c4 100644 --- a/docs/data-sources/cb_kvmvm_list.md +++ b/docs/data-sources/cb_kvmvm_list.md @@ -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) diff --git a/docs/data-sources/cb_kvmvm_list_deleted.md b/docs/data-sources/cb_kvmvm_list_deleted.md index cd7d783..bf32fa7 100644 --- a/docs/data-sources/cb_kvmvm_list_deleted.md +++ b/docs/data-sources/cb_kvmvm_list_deleted.md @@ -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) diff --git a/docs/data-sources/cb_node.md b/docs/data-sources/cb_node.md index c35dd0f..c771e4c 100644 --- a/docs/data-sources/cb_node.md +++ b/docs/data-sources/cb_node.md @@ -34,6 +34,7 @@ description: |- - `isolated_cpus` (List of String) - `name` (String) - `need_reboot` (Boolean) +- `net_addr` (List of Object) (see [below for nested schema](#nestedatt--net_addr)) - `nic_info` (List of Object) (see [below for nested schema](#nestedatt--nic_info)) - `numa_topology` (List of Object) (see [below for nested schema](#nestedatt--numa_topology)) - `reserved_cpus` (List of String) @@ -109,6 +110,15 @@ Read-Only: - `phys_count` (Number) + +### Nested Schema for `net_addr` + +Read-Only: + +- `ip` (List of String) +- `name` (String) + + ### Nested Schema for `nic_info` diff --git a/docs/data-sources/cb_vins.md b/docs/data-sources/cb_vins.md index bbbe42c..ece344b 100644 --- a/docs/data-sources/cb_vins.md +++ b/docs/data-sources/cb_vins.md @@ -101,6 +101,7 @@ Read-Only: - `tech_status` (String) - `type` (String) - `vins` (List of Number) +- `vnc_password` (String) ### Nested Schema for `vnf_dev.config` diff --git a/docs/data-sources/extnet.md b/docs/data-sources/extnet.md index 93a35f8..6e93be0 100644 --- a/docs/data-sources/extnet.md +++ b/docs/data-sources/extnet.md @@ -90,6 +90,7 @@ Read-Only: Read-Only: +- `account_id` (Number) - `client_type` (String) - `desc` (String) - `domainname` (String) diff --git a/docs/data-sources/extnet_reserved_ip_list.md b/docs/data-sources/extnet_reserved_ip_list.md new file mode 100644 index 0000000..4a79817 --- /dev/null +++ b/docs/data-sources/extnet_reserved_ip_list.md @@ -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 + +### 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)) + + +### Nested Schema for `timeouts` + +Optional: + +- `default` (String) +- `read` (String) + + + +### Nested Schema for `items` + +Read-Only: + +- `extnet_id` (Number) +- `reservations` (List of Object) (see [below for nested schema](#nestedobjatt--items--reservations)) + + +### 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) diff --git a/docs/data-sources/kvmvm.md b/docs/data-sources/kvmvm.md index e5fc4bc..74d2cd3 100644 --- a/docs/data-sources/kvmvm.md +++ b/docs/data-sources/kvmvm.md @@ -33,6 +33,7 @@ description: |- - `affinity_weight` (Number) - `anti_affinity_rules` (List of Object) (see [below for nested schema](#nestedatt--anti_affinity_rules)) - `arch` (String) +- `auto_start_w_node` (Boolean) - `boot_order` (List of String) - `bootdisk_size` (Number) - `cd_image_id` (Number) @@ -94,6 +95,7 @@ description: |- - `vgpus` (List of Number) - `virtual_image_id` (Number) - `virtual_image_name` (String) +- `vnc_password` (String) ### Nested Schema for `timeouts` diff --git a/docs/data-sources/kvmvm_list.md b/docs/data-sources/kvmvm_list.md index e069365..4aa844a 100644 --- a/docs/data-sources/kvmvm_list.md +++ b/docs/data-sources/kvmvm_list.md @@ -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) diff --git a/docs/data-sources/kvmvm_list_deleted.md b/docs/data-sources/kvmvm_list_deleted.md index 984e139..5e754f3 100644 --- a/docs/data-sources/kvmvm_list_deleted.md +++ b/docs/data-sources/kvmvm_list_deleted.md @@ -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) diff --git a/docs/data-sources/vins.md b/docs/data-sources/vins.md index 8007188..4a21d7f 100644 --- a/docs/data-sources/vins.md +++ b/docs/data-sources/vins.md @@ -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) diff --git a/docs/resources/cb_cdrom_image.md b/docs/resources/cb_cdrom_image.md index 10f2ba0..ad5bbc4 100644 --- a/docs/resources/cb_cdrom_image.md +++ b/docs/resources/cb_cdrom_image.md @@ -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 diff --git a/docs/resources/cb_extnet.md b/docs/resources/cb_extnet.md index 218f737..87da86e 100644 --- a/docs/resources/cb_extnet.md +++ b/docs/resources/cb_extnet.md @@ -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) + +### Nested Schema for `reserved_ip` + +Required: + +- `account_id` (Number) + +Optional: + +- `ip_count` (Number) +- `ips` (Set of String) + + ### Nested Schema for `timeouts` @@ -119,6 +133,7 @@ Read-Only: Read-Only: +- `account_id` (Number) - `client_type` (String) - `desc` (String) - `domain_name` (String) diff --git a/docs/resources/cb_image.md b/docs/resources/cb_image.md index ccc06ad..75d8872 100644 --- a/docs/resources/cb_image.md +++ b/docs/resources/cb_image.md @@ -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 diff --git a/docs/resources/cb_image_from_blank_compute.md b/docs/resources/cb_image_from_blank_compute.md index 42b4628..98851be 100644 --- a/docs/resources/cb_image_from_blank_compute.md +++ b/docs/resources/cb_image_from_blank_compute.md @@ -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) diff --git a/docs/resources/cb_image_from_platform_disk.md b/docs/resources/cb_image_from_platform_disk.md index bd6ac0f..36a915f 100644 --- a/docs/resources/cb_image_from_platform_disk.md +++ b/docs/resources/cb_image_from_platform_disk.md @@ -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) diff --git a/docs/resources/cb_kvmvm.md b/docs/resources/cb_kvmvm.md index 07120f6..67a1270 100644 --- a/docs/resources/cb_kvmvm.md +++ b/docs/resources/cb_kvmvm.md @@ -30,6 +30,7 @@ description: |- - `alt_boot_id` (Number) ID of CD-ROM live image to boot - `anti_affinity_rules` (Block List) (see [below for nested schema](#nestedblock--anti_affinity_rules)) - `auto_start` (Boolean) Flag for redeploy compute +- `auto_start_w_node` (Boolean) - `boot_disk_size` (Number) This compute instance boot disk size in GB. Make sure it is large enough to accomodate selected OS image. - `cd` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--cd)) - `chipset` (String) Type of the emulated system. @@ -128,6 +129,7 @@ description: |- - `vgpus` (List of Number) - `virtual_image_id` (Number) - `virtual_image_name` (String) +- `vnc_password` (String) ### Nested Schema for `affinity_rules` diff --git a/docs/resources/cb_vins.md b/docs/resources/cb_vins.md index de64db8..a4c37ee 100644 --- a/docs/resources/cb_vins.md +++ b/docs/resources/cb_vins.md @@ -167,6 +167,7 @@ Read-Only: - `tech_status` (String) - `type` (String) - `vins` (List of Number) +- `vnc_password` (String) ### Nested Schema for `vnf_dev.config` diff --git a/docs/resources/cb_vins_static_route.md b/docs/resources/cb_vins_static_route.md index eebab8c..287722e 100644 --- a/docs/resources/cb_vins_static_route.md +++ b/docs/resources/cb_vins_static_route.md @@ -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 diff --git a/docs/resources/cb_virtual_image.md b/docs/resources/cb_virtual_image.md index a111057..87a34b4 100644 --- a/docs/resources/cb_virtual_image.md +++ b/docs/resources/cb_virtual_image.md @@ -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 diff --git a/docs/resources/kvmvm.md b/docs/resources/kvmvm.md index 178ab0d..21e045f 100644 --- a/docs/resources/kvmvm.md +++ b/docs/resources/kvmvm.md @@ -29,6 +29,7 @@ description: |- - `affinity_rules` (Block List) (see [below for nested schema](#nestedblock--affinity_rules)) - `anti_affinity_rules` (Block List) (see [below for nested schema](#nestedblock--anti_affinity_rules)) - `auto_start` (Boolean) Flag for redeploy compute +- `auto_start_w_node` (Boolean) Flag for start compute after node exits from MAINTENANCE state - `boot_disk_size` (Number) This compute instance boot disk size in GB. Make sure it is large enough to accomodate selected OS image. - `cd` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--cd)) - `chipset` (String) Type of the emulated system. @@ -121,6 +122,7 @@ description: |- - `vgpus` (List of Number) - `virtual_image_id` (Number) - `virtual_image_name` (String) +- `vnc_password` (String) ### Nested Schema for `affinity_rules` diff --git a/docs/resources/vins.md b/docs/resources/vins.md index fc897ef..644a210 100644 --- a/docs/resources/vins.md +++ b/docs/resources/vins.md @@ -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) diff --git a/docs/resources/vins_static_route.md b/docs/resources/vins_static_route.md index 2b59227..b6b9de9 100644 --- a/docs/resources/vins_static_route.md +++ b/docs/resources/vins_static_route.md @@ -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. diff --git a/go.mod b/go.mod index 213d7d0..757b8ab 100644 --- a/go.mod +++ b/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.0 ) require ( diff --git a/internal/provider/data_sources_map.go b/internal/provider/data_sources_map.go index de5e343..3c1a910 100644 --- a/internal/provider/data_sources_map.go +++ b/internal/provider/data_sources_map.go @@ -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(), diff --git a/internal/service/cloudapi/extnet/data_source_extnet.go b/internal/service/cloudapi/extnet/data_source_extnet.go index 5fa692e..6e6174e 100644 --- a/internal/service/cloudapi/extnet/data_source_extnet.go +++ b/internal/service/cloudapi/extnet/data_source_extnet.go @@ -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, diff --git a/internal/service/cloudapi/extnet/data_source_extnet_reserved_ip.go b/internal/service/cloudapi/extnet/data_source_extnet_reserved_ip.go new file mode 100644 index 0000000..36511c1 --- /dev/null +++ b/internal/service/cloudapi/extnet/data_source_extnet_reserved_ip.go @@ -0,0 +1,137 @@ +/* +Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved. +Authors: +Petr Krutov, +Stanislav Solovev, +Kasim Baybikov, +Tim Tkachev, + +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(), + } +} diff --git a/internal/service/cloudapi/extnet/flattens.go b/internal/service/cloudapi/extnet/flattens.go index d074bee..41f43d1 100644 --- a/internal/service/cloudapi/extnet/flattens.go +++ b/internal/service/cloudapi/extnet/flattens.go @@ -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 +} diff --git a/internal/service/cloudapi/extnet/utility_extnet_reserved_ip.go b/internal/service/cloudapi/extnet/utility_extnet_reserved_ip.go new file mode 100644 index 0000000..db52e60 --- /dev/null +++ b/internal/service/cloudapi/extnet/utility_extnet_reserved_ip.go @@ -0,0 +1,61 @@ +/* +Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved. +Authors: +Petr Krutov, +Stanislav Solovev, +Kasim Baybikov, + +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 +} diff --git a/internal/service/cloudapi/kvmvm/data_source_compute.go b/internal/service/cloudapi/kvmvm/data_source_compute.go index 8585925..9ddf474 100644 --- a/internal/service/cloudapi/kvmvm/data_source_compute.go +++ b/internal/service/cloudapi/kvmvm/data_source_compute.go @@ -703,6 +703,10 @@ func dataSourceComputeSchemaMake() map[string]*schema.Schema { Type: schema.TypeString, Computed: true, }, + "auto_start_w_node": { + Type: schema.TypeBool, + Computed: true, + }, "chipset": { Type: schema.TypeString, Computed: true, @@ -950,6 +954,10 @@ func dataSourceComputeSchemaMake() map[string]*schema.Schema { Type: schema.TypeString, Computed: true, }, + "vnc_password": { + Type: schema.TypeString, + Computed: true, + }, "vgpus": { Type: schema.TypeList, Computed: true, diff --git a/internal/service/cloudapi/kvmvm/data_source_compute_list.go b/internal/service/cloudapi/kvmvm/data_source_compute_list.go index d3f48d5..5d10670 100644 --- a/internal/service/cloudapi/kvmvm/data_source_compute_list.go +++ b/internal/service/cloudapi/kvmvm/data_source_compute_list.go @@ -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, diff --git a/internal/service/cloudapi/kvmvm/flattens.go b/internal/service/cloudapi/kvmvm/flattens.go index 3511c5e..618d17a 100644 --- a/internal/service/cloudapi/kvmvm/flattens.go +++ b/internal/service/cloudapi/kvmvm/flattens.go @@ -183,6 +183,7 @@ func flattenComputeList(computes *compute.ListComputes) []map[string]interface{} "affinity_weight": compute.AffinityWeight, "anti_affinity_rules": flattenListRules(compute.AntiAffinityRules), "arch": compute.Architecture, + "auto_start_w_node": compute.AutoStart, "boot_order": compute.BootOrder, "bootdisk_size": compute.BootDiskSize, "chipset": compute.Chipset, @@ -362,6 +363,7 @@ func flattenCompute(d *schema.ResourceData, computeRec compute.RecordCompute, pc d.Set("account_name", computeRec.AccountName) d.Set("affinity_weight", computeRec.AffinityWeight) d.Set("arch", computeRec.Architecture) + d.Set("auto_start_w_node", computeRec.AutoStart) d.Set("boot_order", computeRec.BootOrder) // we intentionally use the SizeMax field, do not change it until the BootDiskSize field is fixed on the platform d.Set("boot_disk_size", bootDisk.SizeMax) @@ -429,6 +431,7 @@ func flattenCompute(d *schema.ResourceData, computeRec compute.RecordCompute, pc d.Set("updated_by", computeRec.UpdatedBy) d.Set("updated_time", computeRec.UpdatedTime) d.Set("user_managed", computeRec.UserManaged) + d.Set("vnc_password", computeRec.VNCPassword) d.Set("vgpus", computeRec.VGPUs) d.Set("virtual_image_id", computeRec.VirtualImageID) d.Set("virtual_image_name", computeRec.VirtualImageName) @@ -613,6 +616,7 @@ func flattenDataCompute(d *schema.ResourceData, computeRec compute.RecordCompute d.Set("affinity_rules", flattenAffinityRules(computeRec.AffinityRules)) d.Set("affinity_weight", computeRec.AffinityWeight) d.Set("anti_affinity_rules", flattenListRules(computeRec.AntiAffinityRules)) + d.Set("auto_start_w_node", computeRec.AutoStart) d.Set("arch", computeRec.Architecture) d.Set("chipset", computeRec.Chipset) d.Set("boot_order", computeRec.BootOrder) @@ -672,6 +676,7 @@ func flattenDataCompute(d *schema.ResourceData, computeRec compute.RecordCompute d.Set("updated_time", computeRec.UpdatedTime) d.Set("user_managed", computeRec.UserManaged) d.Set("userdata", string(userdata)) + d.Set("vnc_password", computeRec.VNCPassword) d.Set("vgpus", computeRec.VGPUs) d.Set("virtual_image_id", computeRec.VirtualImageID) d.Set("virtual_image_name", computeRec.VirtualImageName) diff --git a/internal/service/cloudapi/kvmvm/resource_compute.go b/internal/service/cloudapi/kvmvm/resource_compute.go index 5c106b8..e326ebf 100644 --- a/internal/service/cloudapi/kvmvm/resource_compute.go +++ b/internal/service/cloudapi/kvmvm/resource_compute.go @@ -491,12 +491,26 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf req := compute.PinToStackRequest{ ComputeID: computeId, } + req.AutoStart = d.Get("auto_start_w_node").(bool) _, err := c.CloudAPI().Compute().PinToStack(ctx, req) if err != nil { warnings.Add(err) } } + if !d.Get("pin_to_stack").(bool) && d.Get("auto_start_w_node").(bool) { + req := compute.UpdateRequest{ + ComputeID: computeId, + AutoStart: d.Get("auto_start_w_node").(bool), + CPUPin: d.Get("cpu_pin").(bool), + HPBacked: d.Get("hp_backed").(bool), + } + _, err := c.CloudAPI().Compute().Update(ctx, req) + if err != nil { + warnings.Add(err) + } + } + if d.Get("pause").(bool) { req := compute.PauseRequest{ ComputeID: computeId, @@ -619,7 +633,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf } if !hasRG { - return diag.Errorf("resourceComputeUpdate: can't update Compute bacause rgID %d not allowed or does not exist", d.Get("rg_id").(int)) + return diag.Errorf("resourceComputeUpdate: can't update Compute because rgID %d not allowed or does not exist", d.Get("rg_id").(int)) } hasImage, err := existImageId(ctx, d, m) @@ -628,7 +642,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf } if !hasImage { - return diag.Errorf("resourceComputeUpdate: can't update Compute bacause imageID %d not allowed or does not exist", d.Get("image_id").(int)) + return diag.Errorf("resourceComputeUpdate: can't update Compute because imageID %d not allowed or does not exist", d.Get("image_id").(int)) } if disks, ok := d.GetOk("disks"); ok { @@ -862,7 +876,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf } } - if d.HasChanges("description", "name", "numa_affinity", "cpu_pin", "hp_backed") { + if d.HasChanges("description", "name", "numa_affinity", "cpu_pin", "hp_backed", "chipset", "auto_start_w_node") { req := compute.UpdateRequest{ ComputeID: computeRec.ID, } @@ -876,21 +890,17 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf if d.HasChange("numa_affinity") { req.NumaAffinity = d.Get("numa_affinity").(string) } - if d.HasChange("cpu_pin") { - req.CPUPin = d.Get("cpu_pin").(bool) - } - if d.HasChange("hp_backed") { - req.HPBacked = d.Get("hp_backed").(bool) - } - if d.HasChange("chipset") { req.Chipset = d.Get("chipset").(string) } + req.CPUPin = d.Get("cpu_pin").(bool) + req.HPBacked = d.Get("hp_backed").(bool) + req.AutoStart = d.Get("auto_start_w_node").(bool) // Note bene: numa_affinity, cpu_pin and hp_backed are not allowed to be changed for compute in STARTED tech status. // If STARTED, we need to stop it before update var isStopRequired bool - if d.HasChanges("numa_affinity", "cpu_pin", "hp_backed") && d.Get("started").(bool) { + if d.HasChanges("numa_affinity", "cpu_pin", "hp_backed", "chipset") && d.Get("started").(bool) { isStopRequired = true } if isStopRequired { @@ -1481,7 +1491,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf req := compute.PinToStackRequest{ ComputeID: computeRec.ID, } - + req.AutoStart = d.Get("auto_start_w_node").(bool) _, err := c.CloudAPI().Compute().PinToStack(ctx, req) if err != nil { return diag.FromErr(err) @@ -2123,6 +2133,12 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema { Optional: true, Default: false, }, + "auto_start_w_node": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Flag for start compute after node exits from MAINTENANCE state", + }, "auto_start": { Type: schema.TypeBool, Optional: true, @@ -2411,6 +2427,10 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema { Type: schema.TypeBool, Computed: true, }, + "vnc_password": { + Type: schema.TypeString, + Computed: true, + }, "vgpus": { Type: schema.TypeList, Computed: true, @@ -2444,11 +2464,14 @@ func ResourceCompute() *schema.Resource { }, CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, i interface{}) error { - if diff.HasChanges() || diff.HasChanges("network", "affinity_rules", "anti_affinity_rules", + if diff.HasChanges() || diff.HasChanges("chipset", "pin_to_stack", "auto_start_w_node", "network", "affinity_rules", "anti_affinity_rules", "disks", "extra_disks", "tags", "port_forwarding", "user_access", "snapshot", "pci_devices") { diff.SetNewComputed("updated_time") diff.SetNewComputed("updated_by") } + if diff.HasChanges("pin_to_stack") { + diff.SetNewComputed("pinned") + } return nil }, diff --git a/internal/service/cloudapi/vins/data_source_vins.go b/internal/service/cloudapi/vins/data_source_vins.go index 8bb1bff..3f946d6 100644 --- a/internal/service/cloudapi/vins/data_source_vins.go +++ b/internal/service/cloudapi/vins/data_source_vins.go @@ -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": { diff --git a/internal/service/cloudapi/vins/flattens.go b/internal/service/cloudapi/vins/flattens.go index ce2483b..633e3b9 100644 --- a/internal/service/cloudapi/vins/flattens.go +++ b/internal/service/cloudapi/vins/flattens.go @@ -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) } diff --git a/internal/service/cloudapi/vins/resource_static_route.go b/internal/service/cloudapi/vins/resource_static_route.go index 48333df..781f2db 100644 --- a/internal/service/cloudapi/vins/resource_static_route.go +++ b/internal/service/cloudapi/vins/resource_static_route.go @@ -1,277 +1,194 @@ -/* -Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved. -Authors: -Petr Krutov, -Stanislav Solovev, -Kasim Baybikov, - -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, +Stanislav Solovev, +Kasim Baybikov, + +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(), + } +} diff --git a/internal/service/cloudbroker/extnet/data_source_extnet_reserved_ip.go b/internal/service/cloudbroker/extnet/data_source_extnet_reserved_ip.go new file mode 100644 index 0000000..714bcc4 --- /dev/null +++ b/internal/service/cloudbroker/extnet/data_source_extnet_reserved_ip.go @@ -0,0 +1,71 @@ +/* +Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved. +Authors: +Petr Krutov, +Stanislav Solovev, +Kasim Baybikov, +Tim Tkachev, + +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(), + } +} diff --git a/internal/service/cloudbroker/extnet/flattens.go b/internal/service/cloudbroker/extnet/flattens.go index 61a16f4..bfa7309 100644 --- a/internal/service/cloudbroker/extnet/flattens.go +++ b/internal/service/cloudbroker/extnet/flattens.go @@ -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) -} \ No newline at end of file +} + +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 +} diff --git a/internal/service/cloudbroker/extnet/resource_extnet.go b/internal/service/cloudbroker/extnet/resource_extnet.go index 5a84aff..1eb63af 100644 --- a/internal/service/cloudbroker/extnet/resource_extnet.go +++ b/internal/service/cloudbroker/extnet/resource_extnet.go @@ -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(), } } diff --git a/internal/service/cloudbroker/extnet/schema.go b/internal/service/cloudbroker/extnet/schema.go index 3637947..7e91bf8 100644 --- a/internal/service/cloudbroker/extnet/schema.go +++ b/internal/service/cloudbroker/extnet/schema.go @@ -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 +} diff --git a/internal/service/cloudbroker/extnet/utility_extnet_reserved_ip.go b/internal/service/cloudbroker/extnet/utility_extnet_reserved_ip.go new file mode 100644 index 0000000..68c1207 --- /dev/null +++ b/internal/service/cloudbroker/extnet/utility_extnet_reserved_ip.go @@ -0,0 +1,61 @@ +/* +Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved. +Authors: +Petr Krutov, +Stanislav Solovev, +Kasim Baybikov, + +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 +} diff --git a/internal/service/cloudbroker/extnet/utility_extnet_resource.go b/internal/service/cloudbroker/extnet/utility_extnet_resource.go index 4cec4f5..991467d 100644 --- a/internal/service/cloudbroker/extnet/utility_extnet_resource.go +++ b/internal/service/cloudbroker/extnet/utility_extnet_resource.go @@ -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 +} diff --git a/internal/service/cloudbroker/grid/data_source_grid_get_post_diagnosis.go b/internal/service/cloudbroker/grid/data_source_grid_get_post_diagnosis.go index 8327c4c..f4cbf65 100644 --- a/internal/service/cloudbroker/grid/data_source_grid_get_post_diagnosis.go +++ b/internal/service/cloudbroker/grid/data_source_grid_get_post_diagnosis.go @@ -34,61 +34,59 @@ package grid import ( "context" - "strconv" + "os" + "github.com/google/uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + log "github.com/sirupsen/logrus" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants" ) func dataSourceGridGetDiagnosisRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - diagnosis, err := utilityGridGetDiagnosisCheckPresence(ctx, d, m) + filePath := "diagnosis.tar.gz" + if userPath, ok := d.GetOk("file_path"); ok { + filePath = userPath.(string) + } + + log.Debugf("dataSourceGridGetDiagnosisRead: create file with name: %s", filePath) + file, err := os.Create(filePath) + defer file.Close() if err != nil { - d.SetId("") + d.SetId("") // ensure ID is empty in this case return diag.FromErr(err) } - d.SetId(strconv.Itoa(d.Get("gid").(int))) - d.Set("diagnosis", diagnosis) - return nil -} -func DataSourceGridGetDiagnosis() *schema.Resource { - return &schema.Resource{ - SchemaVersion: 1, - - ReadContext: dataSourceGridGetDiagnosisRead, - - Timeouts: &schema.ResourceTimeout{ - Read: &constants.Timeout30s, - Default: &constants.Timeout60s, - }, - - Schema: dataSourceGridGetDiagnosisSchemaMake(), + diagnosis, err := utilityGridGetDiagnosisCheckPresence(ctx, d, m) + if err != nil { + d.SetId("") + return diag.FromErr(err) } -} -func dataSourceGridPostDiagnosisRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - diagnosis, err := utilityGridPostDiagnosisCheckPresence(ctx, d, m) + log.Debugf("dataSourceGridGetDiagnosisRead: write data to file with name: %s", filePath) + _, err = file.WriteString(diagnosis) if err != nil { - d.SetId("") + d.SetId("") // ensure ID is empty in this case return diag.FromErr(err) } - d.SetId(strconv.Itoa(d.Get("gid").(int))) - d.Set("diagnosis", diagnosis) + + id := uuid.New() + d.SetId(id.String()) + return nil } -func DataSourceGridPostDiagnosis() *schema.Resource { +func DataSourceGridGetDiagnosis() *schema.Resource { return &schema.Resource{ SchemaVersion: 1, - ReadContext: dataSourceGridPostDiagnosisRead, + ReadContext: dataSourceGridGetDiagnosisRead, Timeouts: &schema.ResourceTimeout{ Read: &constants.Timeout30s, Default: &constants.Timeout60s, }, - Schema: dataSourceGridPostDiagnosisSchemaMake(), + Schema: dataSourceGridGetDiagnosisSchemaMake(), } } diff --git a/internal/service/cloudbroker/grid/schema.go b/internal/service/cloudbroker/grid/schema.go index 693bc1a..5b866d7 100644 --- a/internal/service/cloudbroker/grid/schema.go +++ b/internal/service/cloudbroker/grid/schema.go @@ -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, - }, } } diff --git a/internal/service/cloudbroker/grid/utility_grid_get_post_diagnosis.go b/internal/service/cloudbroker/grid/utility_grid_get_post_diagnosis.go index 4c8e172..137b7b0 100644 --- a/internal/service/cloudbroker/grid/utility_grid_get_post_diagnosis.go +++ b/internal/service/cloudbroker/grid/utility_grid_get_post_diagnosis.go @@ -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 -} diff --git a/internal/service/cloudbroker/image/flattens.go b/internal/service/cloudbroker/image/flattens.go index 9a0d346..7210c21 100644 --- a/internal/service/cloudbroker/image/flattens.go +++ b/internal/service/cloudbroker/image/flattens.go @@ -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) } diff --git a/internal/service/cloudbroker/image/schema.go b/internal/service/cloudbroker/image/schema.go index 849f299..3dc731f 100644 --- a/internal/service/cloudbroker/image/schema.go +++ b/internal/service/cloudbroker/image/schema.go @@ -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, diff --git a/internal/service/cloudbroker/kvmvm/flattens.go b/internal/service/cloudbroker/kvmvm/flattens.go index 934563c..f1bbc27 100644 --- a/internal/service/cloudbroker/kvmvm/flattens.go +++ b/internal/service/cloudbroker/kvmvm/flattens.go @@ -34,6 +34,7 @@ func flattenCompute(d *schema.ResourceData, computeRec *compute.RecordCompute, p d.Set("affinity_rules", flattenAffinityRules(computeRec.AffinityRules)) d.Set("anti_affinity_rules", flattenAffinityRules(computeRec.AntiAffinityRules)) d.Set("arch", computeRec.Arch) + d.Set("auto_start_w_node", computeRec.AutoStart) d.Set("boot_order", computeRec.BootOrder) d.Set("boot_disk_id", bootDisk.ID) // we intentionally use the SizeMax field, do not change it until the BootDiskSize field is fixed on the platform @@ -92,6 +93,7 @@ func flattenCompute(d *schema.ResourceData, computeRec *compute.RecordCompute, p d.Set("updated_time", computeRec.UpdatedTime) d.Set("user_data", string(userData)) d.Set("user_managed", computeRec.UserManaged) + d.Set("vnc_password", computeRec.VNCPassword) d.Set("vgpus", computeRec.VGPUs) d.Set("virtual_image_id", computeRec.VirtualImageID) d.Set("virtual_image_name", computeRec.VirtualImageName) @@ -294,6 +296,7 @@ func flattenComputeList(computes *compute.ListComputes) []map[string]interface{} "affinity_weight": computeItem.AffinityWeight, "anti_affinity_rules": flattenListRules(computeItem.AntiAffinityRules), "arch": computeItem.Arch, + "auto_start_w_node": computeItem.AutoStart, "chipset": computeItem.Chipset, "cd_image_id": computeItem.CdImageId, "boot_order": computeItem.BootOrder, @@ -613,6 +616,7 @@ func flattenDataCompute(d *schema.ResourceData, compFacts *compute.RecordCompute d.Set("affinity_weight", compFacts.AffinityWeight) d.Set("anti_affinity_rules", flattenAffinityRules(compFacts.AntiAffinityRules)) d.Set("arch", compFacts.Arch) + d.Set("auto_start_w_node", compFacts.AutoStart) d.Set("boot_order", compFacts.BootOrder) d.Set("chipset", compFacts.Chipset) d.Set("cd_image_id", compFacts.CdImageId) @@ -671,6 +675,7 @@ func flattenDataCompute(d *schema.ResourceData, compFacts *compute.RecordCompute d.Set("updated_time", compFacts.UpdatedTime) d.Set("user_data", string(userData)) d.Set("user_managed", compFacts.UserManaged) + d.Set("vnc_password", compFacts.VNCPassword) d.Set("vgpus", compFacts.VGPUs) d.Set("virtual_image_id", compFacts.VirtualImageID) d.Set("virtual_image_name", compFacts.VirtualImageName) diff --git a/internal/service/cloudbroker/kvmvm/resource_compute.go b/internal/service/cloudbroker/kvmvm/resource_compute.go index deb38ce..1eea0a3 100644 --- a/internal/service/cloudbroker/kvmvm/resource_compute.go +++ b/internal/service/cloudbroker/kvmvm/resource_compute.go @@ -484,12 +484,29 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf req.Force = force } + if autoStart, ok := d.Get("auto_start_w_node").(bool); ok { + req.AutoStart = autoStart + } + _, err := c.CloudBroker().Compute().PinToStack(ctx, req) if err != nil { warnings.Add(err) } } + if !d.Get("pin_to_stack").(bool) && d.Get("auto_start_w_node").(bool) { + req := compute.UpdateRequest{ + ComputeID: computeId, + AutoStart: d.Get("auto_start_w_node").(bool), + CPUPin: d.Get("cpu_pin").(bool), + HPBacked: d.Get("hp_backed").(bool), + } + _, err := c.CloudBroker().Compute().Update(ctx, req) + if err != nil { + warnings.Add(err) + } + } + if d.Get("pause").(bool) { req := compute.PauseRequest{ ComputeID: computeId, @@ -686,7 +703,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf } } - if d.HasChanges("description", "name", "numa_affinity", "cpu_pin", "hp_backed") { + if d.HasChanges("description", "name", "numa_affinity", "cpu_pin", "hp_backed", "chipset", "auto_start_w_node") { if err := utilityComputeUpdate(ctx, d, m); err != nil { return diag.FromErr(err) } @@ -839,11 +856,14 @@ func ResourceCompute() *schema.Resource { SchemaVersion: 1, CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, i interface{}) error { - if diff.HasChanges() || diff.HasChanges("libvirt_settings", "network", "affinity_rules", "anti_affinity_rules", + if diff.HasChanges() || diff.HasChanges("chipset", "pin_to_stack", "auto_start_w_node", "libvirt_settings", "network", "affinity_rules", "anti_affinity_rules", "disks", "extra_disks", "tags", "port_forwarding", "user_access", "snapshot", "pci_devices") { diff.SetNewComputed("updated_time") diff.SetNewComputed("updated_by") } + if diff.HasChanges("pin_to_stack") { + diff.SetNewComputed("pinned") + } return nil }, diff --git a/internal/service/cloudbroker/kvmvm/schema.go b/internal/service/cloudbroker/kvmvm/schema.go index 23ecd36..c1a1ef5 100644 --- a/internal/service/cloudbroker/kvmvm/schema.go +++ b/internal/service/cloudbroker/kvmvm/schema.go @@ -134,6 +134,10 @@ func dataSourceComputeSchemaMake() map[string]*schema.Schema { Type: schema.TypeString, Computed: true, }, + "auto_start_w_node": { + Type: schema.TypeBool, + Computed: true, + }, "boot_order": { Type: schema.TypeList, Computed: true, @@ -902,6 +906,10 @@ func dataSourceComputeSchemaMake() map[string]*schema.Schema { Type: schema.TypeBool, Computed: true, }, + "vnc_password": { + Type: schema.TypeString, + Computed: true, + }, "vgpus": { Type: schema.TypeList, Computed: true, @@ -990,6 +998,11 @@ func dataSourceComputeListSchemaMake() map[string]*schema.Schema { Optional: true, Description: "Find by image ID", }, + "cd_image_id": { + Type: schema.TypeInt, + Optional: true, + Description: "Find by CD image ID", + }, "extnet_name": { Type: schema.TypeString, Optional: true, @@ -1145,6 +1158,10 @@ func dataSourceComputeListSchemaMake() map[string]*schema.Schema { Type: schema.TypeString, Computed: true, }, + "auto_start_w_node": { + Type: schema.TypeBool, + Computed: true, + }, "boot_order": { Type: schema.TypeList, Computed: true, @@ -1802,6 +1819,10 @@ func dataSourceComputeListDeletedSchemaMake() map[string]*schema.Schema { Type: schema.TypeString, Computed: true, }, + "auto_start_w_node": { + Type: schema.TypeBool, + Computed: true, + }, "boot_order": { Type: schema.TypeList, Computed: true, @@ -3375,6 +3396,11 @@ func resourceComputeSchemaMake() map[string]*schema.Schema { Optional: true, Default: false, }, + "auto_start_w_node": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, "target_stack_id": { Type: schema.TypeInt, Optional: true, @@ -3906,6 +3932,10 @@ func resourceComputeSchemaMake() map[string]*schema.Schema { Type: schema.TypeBool, Computed: true, }, + "vnc_password": { + Type: schema.TypeString, + Computed: true, + }, "vgpus": { Type: schema.TypeList, Computed: true, diff --git a/internal/service/cloudbroker/kvmvm/utility_compute.go b/internal/service/cloudbroker/kvmvm/utility_compute.go index e87292b..2360dcf 100644 --- a/internal/service/cloudbroker/kvmvm/utility_compute.go +++ b/internal/service/cloudbroker/kvmvm/utility_compute.go @@ -852,21 +852,17 @@ func utilityComputeUpdate(ctx context.Context, d *schema.ResourceData, m interfa if d.HasChange("numa_affinity") { req.NumaAffinity = d.Get("numa_affinity").(string) } - if d.HasChange("cpu_pin") { - req.CPUPin = d.Get("cpu_pin").(bool) - } - if d.HasChange("hp_backed") { - req.HPBacked = d.Get("hp_backed").(bool) - } - if d.HasChange("chipset") { req.Chipset = d.Get("chipset").(string) } + req.CPUPin = d.Get("cpu_pin").(bool) + req.HPBacked = d.Get("hp_backed").(bool) + req.AutoStart = d.Get("auto_start_w_node").(bool) // Note bene: numa_affinity, cpu_pin and hp_backed are not allowed to be changed for compute in STARTED tech status. // If STARTED, we need to stop it before update var isStopRequired bool - if d.HasChanges("numa_affinity", "cpu_pin", "hp_backed") && d.Get("started").(bool) { + if d.HasChanges("numa_affinity", "cpu_pin", "hp_backed", "chipset") && d.Get("started").(bool) { isStopRequired = true } if isStopRequired { @@ -1434,6 +1430,11 @@ func utilityComputePinToStack(ctx context.Context, d *schema.ResourceData, m int if force, ok := d.Get("force_pin").(bool); ok { req.Force = force } + + if autoStart, ok := d.Get("auto_start_w_node").(bool); ok { + req.AutoStart = autoStart + } + _, err := c.CloudBroker().Compute().PinToStack(ctx, req) if err != nil { return err diff --git a/internal/service/cloudbroker/kvmvm/utility_compute_list.go b/internal/service/cloudbroker/kvmvm/utility_compute_list.go index 0a15535..2ec634a 100644 --- a/internal/service/cloudbroker/kvmvm/utility_compute_list.go +++ b/internal/service/cloudbroker/kvmvm/utility_compute_list.go @@ -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) } diff --git a/internal/service/cloudbroker/node/flattens.go b/internal/service/cloudbroker/node/flattens.go index b493b02..9fa21fb 100644 --- a/internal/service/cloudbroker/node/flattens.go +++ b/internal/service/cloudbroker/node/flattens.go @@ -51,6 +51,7 @@ func flattenNode(d *schema.ResourceData, item *node.RecordNode) { d.Set("isolated_cpus", flattenNodeItem(item.IsolatedCpus)) d.Set("name", item.Name) d.Set("need_reboot", item.NeedReboot) + d.Set("net_addr", flattenGetNetAddr(item.NetAddr)) d.Set("nic_info", flattenNicInfo(item.NicInfo)) d.Set("numa_topology", flattenNumaTopology(item.NumaTopology)) d.Set("reserved_cpus", flattenNodeItem(item.ReservedCPUs)) @@ -205,9 +206,9 @@ func flattenVFList(vfList []interface{}) []map[string]interface{} { return res } -func flattenNetAddr(adresses node.ListNetAddr) []map[string]interface{} { - res := make([]map[string]interface{}, 0, len(adresses)) - for _, item := range adresses { +func flattenNetAddr(addresses node.ListNetAddr) []map[string]interface{} { + res := make([]map[string]interface{}, 0, len(addresses)) + for _, item := range addresses { temp := map[string]interface{}{ "cidr": item.CIDR, "index": item.Index, @@ -221,6 +222,16 @@ func flattenNetAddr(adresses node.ListNetAddr) []map[string]interface{} { return res } +func flattenGetNetAddr(address node.NetAddr) []map[string]interface{} { + res := make([]map[string]interface{}, 1) + temp := map[string]interface{}{ + "ip": address.IP, + "name": address.Name, + } + res[0] = temp + return res +} + func flattenCpuInfo(info node.CpuInfo) []map[string]interface{} { res := make([]map[string]interface{}, 1) temp := map[string]interface{}{ diff --git a/internal/service/cloudbroker/node/schema.go b/internal/service/cloudbroker/node/schema.go index 2af9791..4579470 100644 --- a/internal/service/cloudbroker/node/schema.go +++ b/internal/service/cloudbroker/node/schema.go @@ -131,6 +131,25 @@ func dataSourceNodeSchemaMake() map[string]*schema.Schema { Type: schema.TypeBool, Computed: true, }, + "net_addr": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, "nic_info": { Type: schema.TypeList, Computed: true, diff --git a/internal/service/cloudbroker/vins/flattens.go b/internal/service/cloudbroker/vins/flattens.go index ed9626f..7d46edd 100644 --- a/internal/service/cloudbroker/vins/flattens.go +++ b/internal/service/cloudbroker/vins/flattens.go @@ -150,6 +150,7 @@ func flattenVinsVNFDev(vd vins.VNFDev) []map[string]interface{} { "status": vd.Status, "tech_status": vd.TechStatus, "type": vd.Type, + "vnc_password": vd.VNCPassword, "vins": vd.VINS, } res = append(res, temp) @@ -371,14 +372,12 @@ func flattenVinsListReservations(li vins.ListReservations) []map[string]interfac res := make([]map[string]interface{}, 0, len(li)) for _, v := range li { temp := map[string]interface{}{ - "client_type": v.ClientType, - "description": v.Description, - "domain_name": v.DomainName, - "host_name": v.Hostname, - "ip": v.IP, - "mac": v.MAC, - "type": v.Type, - "vm_id": v.VMID, + //TODO + //"account_id": v.AccountID, + "ip": v.IP, + "mac": v.MAC, + "type": v.Type, + "vm_id": v.VMID, } res = append(res, temp) } diff --git a/internal/service/cloudbroker/vins/resource_vins_static_route.go b/internal/service/cloudbroker/vins/resource_vins_static_route.go index c8d7905..dfb2ae0 100644 --- a/internal/service/cloudbroker/vins/resource_vins_static_route.go +++ b/internal/service/cloudbroker/vins/resource_vins_static_route.go @@ -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 { diff --git a/internal/service/cloudbroker/vins/schema.go b/internal/service/cloudbroker/vins/schema.go index 31beb90..5d6fe1e 100644 --- a/internal/service/cloudbroker/vins/schema.go +++ b/internal/service/cloudbroker/vins/schema.go @@ -341,6 +341,10 @@ func dataSourceVinsSchemaMake() map[string]*schema.Schema { Computed: true, Description: "type", }, + "vnc_password": { + Type: schema.TypeString, + Computed: true, + }, "vins": { Type: schema.TypeList, Computed: true, @@ -2509,6 +2513,10 @@ func resourceVinsSchemaMake() map[string]*schema.Schema { Computed: true, Description: "type", }, + "vnc_password": { + Type: schema.TypeString, + Computed: true, + }, "vins": { Type: schema.TypeList, Computed: true, @@ -3389,7 +3397,6 @@ func resourceStaticRouteSchemaMake() map[string]*schema.Schema { "compute_ids": { Type: schema.TypeList, Computed: true, - Optional: true, Elem: &schema.Schema{ Type: schema.TypeInt, }, diff --git a/samples/README.md b/samples/README.md index ae896fc..19d8cac 100644 --- a/samples/README.md +++ b/samples/README.md @@ -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 diff --git a/samples/cloudbroker/grid/decort_cb_grid_post_diagnosis/main.tf b/samples/cloudapi/extnet/data_extnet_reserved_ip_list/main.tf similarity index 58% rename from samples/cloudbroker/grid/decort_cb_grid_post_diagnosis/main.tf rename to samples/cloudapi/extnet/data_extnet_reserved_ip_list/main.tf index 75c61bd..25db22e 100644 --- a/samples/cloudbroker/grid/decort_cb_grid_post_diagnosis/main.tf +++ b/samples/cloudapi/extnet/data_extnet_reserved_ip_list/main.tf @@ -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 } diff --git a/samples/cloudapi/kvmvm/resource_kvmvm/main.tf b/samples/cloudapi/kvmvm/resource_kvmvm/main.tf index 300c6de..62670e6 100644 --- a/samples/cloudapi/kvmvm/resource_kvmvm/main.tf +++ b/samples/cloudapi/kvmvm/resource_kvmvm/main.tf @@ -396,6 +396,11 @@ resource "decort_kvmvm" "comp" { #тип - булев pin_to_stack = true + #флаг для старта компьюта при рестарте ноды + #опциональный параметр + #тип - булев + auto_start_w_node = true + #флаг доступности компьюта для проведения с ним операций #опциональный параметр #тип - булев diff --git a/samples/cloudapi/vins/resource_vins_static_route/main.tf b/samples/cloudapi/vins/resource_vins_static_route/main.tf index c431d1f..2378e2c 100644 --- a/samples/cloudapi/vins/resource_vins_static_route/main.tf +++ b/samples/cloudapi/vins/resource_vins_static_route/main.tf @@ -52,12 +52,6 @@ resource "decort_vins_static_route" "sr" { #обязательный параметр #тип - строка gateway = "192.168.201.40" - - #список виртуальных машин, которым будет предоставлен доступ к роуту - #опциональный параметр - #тип - массив целых чисел - compute_ids = [111, 222] - } output "sr" { diff --git a/samples/cloudbroker/extnet/data_extnet_reserved_ip_list/main.tf b/samples/cloudbroker/extnet/data_extnet_reserved_ip_list/main.tf new file mode 100644 index 0000000..5341a8d --- /dev/null +++ b/samples/cloudbroker/extnet/data_extnet_reserved_ip_list/main.tf @@ -0,0 +1,43 @@ +/* +Пример использования +Получение информации о зарезервированных IP адресах или пуле адресов +*/ + +#Расскомментируйте этот код, +#и внесите необходимые правки в версию и путь, +#чтобы работать с установленным вручную (не через hashicorp provider registry) провайдером +/* +terraform { + required_providers { + decort = { + source = "basis/decort/decort" + version = "" + } + } +} +*/ + +provider "decort" { + authenticator = "decs3o" + #controller_url = + controller_url = "https://ds1.digitalenergy.online" + #oauth2_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 +} diff --git a/samples/cloudbroker/extnet/resource_extnet/main.tf b/samples/cloudbroker/extnet/resource_extnet/main.tf index 4d6c1e1..69462a7 100644 --- a/samples/cloudbroker/extnet/resource_extnet/main.tf +++ b/samples/cloudbroker/extnet/resource_extnet/main.tf @@ -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 на который происходит миграция #опциональный параметр #тип - целое число diff --git a/samples/cloudbroker/grid/decort_cb_grid_get_diagnosis/main.tf b/samples/cloudbroker/grid/decort_cb_grid_get_diagnosis/main.tf index a1db4d6..ca473da 100644 --- a/samples/cloudbroker/grid/decort_cb_grid_get_diagnosis/main.tf +++ b/samples/cloudbroker/grid/decort_cb_grid_get_diagnosis/main.tf @@ -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" { diff --git a/samples/cloudbroker/kvmvm/data_kvmvm_list/main.tf b/samples/cloudbroker/kvmvm/data_kvmvm_list/main.tf index fa10f0e..bfadf31 100644 --- a/samples/cloudbroker/kvmvm/data_kvmvm_list/main.tf +++ b/samples/cloudbroker/kvmvm/data_kvmvm_list/main.tf @@ -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 #опциональный параметр #тип - строка diff --git a/samples/cloudbroker/kvmvm/resource_kvmvm/main.tf b/samples/cloudbroker/kvmvm/resource_kvmvm/main.tf index 1749f2f..1e88672 100644 --- a/samples/cloudbroker/kvmvm/resource_kvmvm/main.tf +++ b/samples/cloudbroker/kvmvm/resource_kvmvm/main.tf @@ -409,6 +409,11 @@ resource "decort_cb_kvmvm" "comp" { #тип - булев #pin_to_stack = true + #флаг для старта компьюта при рестарте ноды + #опциональный параметр + #тип - булев + #auto_start_w_node = true + #id stack для добавления компьюта на этот стэк #опциональный параметр #тип - целое число diff --git a/samples/cloudbroker/vins/resource_vins_static_route/main.tf b/samples/cloudbroker/vins/resource_vins_static_route/main.tf index 8d23d67..6011e80 100644 --- a/samples/cloudbroker/vins/resource_vins_static_route/main.tf +++ b/samples/cloudbroker/vins/resource_vins_static_route/main.tf @@ -51,12 +51,6 @@ resource "decort_cb_vins_static_route" "sr" { #обязательный параметр #тип - строка gateway = "192.168.201.40" - - #список виртуальных машин, которым будет предоставлен доступ к роуту - #опциональный параметр - #тип - массив целых чисел - #compute_ids = [111,222] - } output "sr" { diff --git a/wiki/4.8.0/01.-Введение.md b/wiki/4.8.0/01.-Введение.md new file mode 100644 index 0000000..c200626 --- /dev/null +++ b/wiki/4.8.0/01.-Введение.md @@ -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. diff --git a/wiki/4.8.0/02.-Пример-работы.md b/wiki/4.8.0/02.-Пример-работы.md new file mode 100644 index 0000000..1461d55 --- /dev/null +++ b/wiki/4.8.0/02.-Пример-работы.md @@ -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 = "<>" # specify correct DECORT controller URL, e.g. "https://ds1.digitalenergy.online" + oauth2_url = "<>" # specify corresponding DECORT OAUTH2 URL, e.g. "https://sso.digitalenergy.online" + app_id = "<>" # application secret to access DECORT cloud API in 'decs3o' and 'bvs' authentication mode, e.g. "ewqfrvea7s890avw804389qwguf234h0otfi3w4eiu" + 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 = # Specify account ID +} + +# 3. Load OS image to use for VM deployment +data "decort_image" "os_image" { + 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 (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 (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 = "<>" # 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 = <> # specify external network ID to use, consult your DECORT platform admin for correct IDs + # ip_address = "<>" # you may optionally request a specific IP address + } +} +``` diff --git a/wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT.md b/wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT.md new file mode 100644 index 0000000..938223a --- /dev/null +++ b/wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT.md @@ -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. diff --git a/wiki/4.8.0/04.-Начало-работы-с-terraform-провайдером-DECORT.md b/wiki/4.8.0/04.-Начало-работы-с-terraform-провайдером-DECORT.md new file mode 100644 index 0000000..edaa664 --- /dev/null +++ b/wiki/4.8.0/04.-Начало-работы-с-terraform-провайдером-DECORT.md @@ -0,0 +1,6 @@ +Данный раздел описывает: +- Системные требования +- Установку провайдера +- Инициализацию провайдера +- Переключение режима работы между разными группами API +- Получение gid/grid_id площадки diff --git a/wiki/4.8.0/04.01-Установка-Terraform-провайдера-DECORT.md b/wiki/4.8.0/04.01-Установка-Terraform-провайдера-DECORT.md new file mode 100644 index 0000000..c01246b --- /dev/null +++ b/wiki/4.8.0/04.01-Установка-Terraform-провайдера-DECORT.md @@ -0,0 +1,150 @@ +## Системные требования + +Для запуска провайдера вам потребуется машина, на которой установлен Terraform. + +Кроме того, в связи с тем, что начиная с версии 0.12 Terraform изменил алгоритм поиска и инициализации локальных провайдеров, настройка данного провайдера для работы с Terraform 0.12 или более новыми версиями потребует выполнения ряда дополнительных действий. Подробнее см. [8.3 Настройка локального провайдера для работы с новыми версиями Terraform](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/08.-Полезные-советы#user-content-8-3-настройка-локального-провайдера-для-работы-с-новыми-версиями-terraform.md). + +## Установка +Начиная с версии провайдера `4.3.0` в релизном архиве находятся скрипты-инсталляторы. +Чтобы выполнить установку, необходимо: +1. Перейти по адресу: https://repository.basistech.ru/BASIS/terraform-provider-decort/releases +2. Выбрать необходимую версию провайдера подходящую под операционную систему. +3. Скачать архив. +4. Распаковать архив. +5. Выполнить скрипт установщика, `install.sh` или `install.bat` для Windows.
+*Для запуска `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` указывается версия провайдера. +
+**ВНИМАНИЕ: Версии в блоке и в пути к исполняемому файлу провайдера должны совпадать!** + +В поле `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 инициализирует провайдер и будет готов к дальнейшей работе. diff --git a/wiki/4.8.0/04.02-Инициализация-Terraform-провайдера-DECORT.md b/wiki/4.8.0/04.02-Инициализация-Terraform-провайдера-DECORT.md new file mode 100644 index 0000000..85346e3 --- /dev/null +++ b/wiki/4.8.0/04.02-Инициализация-Terraform-провайдера-DECORT.md @@ -0,0 +1,64 @@ +## Список аргументов для инициализации +Перед началом использования любой Terraform провайдер должен быть инициализирован. + +В процессе инициализации Terraform провайдера DECORT проверяется корректность переданных аргументов и выполняется авторизация в указанном контроллере облачной инфраструктуры. Подробнее о способах авторизации в платформе DECORT смотри соответствующий [раздел](https://repository.basistech.ru/BASIS/terraform-provider-decort/src/branch/main/wiki/4.8.0/03.-Обзор-облачной-платформы-DECORT#user-content-способы-авторизации.md). + +При инициализации Terraform провайдера DECORT используются следующие аргументы: + +| Аргумент | Переменная окружения | Описание | +| --- | --- | --- | +| allow_unverified_ssl | - | Если данный аргумент явно установлен в `true`, то провайдер **не будет** проверять SSL сертификаты при взаимодействии с авторизационным сервисом OAuth2 и контроллером облачной платформы.
Отключение проверок может быть полезным при работе в доверенной среде, использующей самоподписанные SSL сертификаты. Однако, так как отключение проверок несёт потенциальные риски безопасности, данную настройку следует использовать с осторожностью.
Разрешённые значения: `false` (значение по умолчанию) и `true`. | +| app_id | DECORT_APP_ID | Идентификатор приложения (клиента) для авторизации в контроллере облачной платформы в режиме `decs3o` или `bvs`.
Аргументы `app_id` и `app_secret` являются обязательными для режимов авторизации `authenticator=decs3o` и `authenticator=bvs`.
Если `app_id` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_APP_ID`. | +| app_secret | DECORT_APP_SECRET | Секретный код приложения (клиента) для авторизации в контроллере облачной платформы в режиме `decs3o` или `bvs`.
Аргументы `app_id` и `app_secret` являются обязательными для режимов авторизации `authenticator=decs3o` и `authenticator=bvs`.
Если `app_secret` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_APP_SECRET`. | +| authenticator | - | Режим авторизации при подключении к контроллеру облачной платформы.
Доступные режимы: `decs3o`, `legacy`, `jwt` или `bvs`.
Данный аргумент является обязательным. | +| bvs_user | DECORT_BVS_USER | Имя пользователя для авторизации в контроллере облачной платформы в режиме `bvs`.
Аргументы `bvs_password` и `bvs_user` являются обязательными для режима авторизации `authenticator=bvs`.
Если `bvs_user` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_BVS_USER`. | +| bvs_password | DECORT_BVS_PASSWORD | Пароль пользователя для авторизации в контроллере облачной платформы в режиме `bvs`.
Аргументы `bvs_user` и `bvs_password` являются обязательными для режима авторизации `authenticator=bvs`.
Если `bvs_password` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_BVS_PASSWORD`. | +| domain | DECORT_DOMAIN | Имя домена в контроллере облачной платформы в режиме `bvs`.
Данный аргумент является обязательным.
Если `domain` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_DOMAIN`. | +| controller_url | DECORT_CONTROLLER_URL | URL контроллера облачной платформы, через который будет осуществляться управление облачными ресурсами.
Данный аргумент является обязательным. | +| jwt | DECORT_JWT | JSON Web Token (JWT), который используется для авторизации в контроллере облачной платформы в режиме `jwt`.
Данный аргумент является обязательным для режима авторизации `authenticator=jwt`.
Если `jwt` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_JWT` | +| oauth2_url | DECORT_OAUTH2_URL | URL авторизационного сервиса OAuth2, который используется для управления доступом пользователей (или программных клиентов) к контроллеру облачной платформы.
Данный аргумент является обязательным для режимов авторизации `authenticator=decs3o`, `authenticator=bvs` и `authenticator=jwt`.
Если `oauth2_url` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_OAUTH2_URL` | +| password | DECORT_PASSWORD | Пароль для авторизации в контроллере облачной платформы в режиме `legacy`.
Аргументы `password` и `user` являются обязательными для режима авторизации `authenticator=legacy`.
Если `password` не задан в tf-файле, то провайдер будет использовать значение из переменной окружения `DECORT_PASSWORD`. | +| user | DECORT_USER | Имя пользователя для авторизации в контроллере облачной платформы в режиме `legacy`.
Аргументы `user` и `password` являются обязательными для режима авторизации `authenticator=legacy`.
Если `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. diff --git a/wiki/4.8.0/04.03-Переключение-между-группами-API.md b/wiki/4.8.0/04.03-Переключение-между-группами-API.md new file mode 100644 index 0000000..fb722ac --- /dev/null +++ b/wiki/4.8.0/04.03-Переключение-между-группами-API.md @@ -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 +``` +**ОБРАТИТЕ ВНИМАНИЕ** +Переменные окружения создаются для терминальной сессии. В сл. раз их придется задавать еще раз, если требуется режим, отличный от пользовательского. diff --git a/wiki/4.8.0/04.04-Получение-gid-или-grid_id.md b/wiki/4.8.0/04.04-Получение-gid-или-grid_id.md new file mode 100644 index 0000000..4b316ac --- /dev/null +++ b/wiki/4.8.0/04.04-Получение-gid-или-grid_id.md @@ -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 +} + +``` +В файл состояния будет сохранен результат, где можно посмотреть доступные для работы площадки. diff --git a/wiki/4.8.0/04.05-Сборка-terraform-провайдера-в-образ.md b/wiki/4.8.0/04.05-Сборка-terraform-провайдера-в-образ.md new file mode 100644 index 0000000..02bc8b7 --- /dev/null +++ b/wiki/4.8.0/04.05-Сборка-terraform-провайдера-в-образ.md @@ -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 провайдер. diff --git a/wiki/4.8.0/05.-Работа-с-terraform.md b/wiki/4.8.0/05.-Работа-с-terraform.md new file mode 100644 index 0000000..675f2ea --- /dev/null +++ b/wiki/4.8.0/05.-Работа-с-terraform.md @@ -0,0 +1,4 @@ +Раздел описывает некоторые практики работы с terraform, которые могут быть полезны пользователю. +Раздел включает в себя следующие статьи: +- Импортирование ресурсов +- Работа с таймаутами diff --git a/wiki/4.8.0/05.01-Импортирование-ресурсов.md b/wiki/4.8.0/05.01-Импортирование-ресурсов.md new file mode 100644 index 0000000..8a419d3 --- /dev/null +++ b/wiki/4.8.0/05.01-Импортирование-ресурсов.md @@ -0,0 +1,75 @@ +Импортирование ресурсов в terraform позволяет привести в соответствие состояние terraform (.tfstate) к состоянию ресурса в платформе. +Необходимость такого приведения возникает в нескольких случаях: +- Ресурс был создан через портал платформы, работа продолжается через terraform провайдер, +- Ресурс был создан через terraform провайдер, однако был изменен через портал платформы, +- Ресурс был создан через terraform провайдер, однако был изменен другим пользователем через terraform провайдер, +- И так далее + +Такие расхождения в состоянии ресурсов нередки, путей их решения несколько: +- Использовать импортирование ресурсов, +- Использовать общие файлы состояний ресурсов, к которым будут иметь доступ все участники, занятые в работе с платформой. +В текущем разделе рассматривается первый вариант. + +## Импортирование ресурсов +Импортирование ресурсов позволяет совершить запрос к платформе, чтобы сформировать файл состояния. +Чтобы совершить импортирование ресурсов необходимо ввести сл. команду: +```bash +terraform import . +``` +## Пример +Предположим, что у нас ресурс, описывающий диск: +```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: : required field is not set +``` +Где - наименование поля. +Ошибка возникает в том случае, если в описании ресурса отсутствует обязательное поле. +Например: +```terraform +resource "decort_disk" "disk" { + account_id = 121212 + gid = 3333 + size_max = 100500 +} +``` +В приведенном выше описании отсутствует поле disk_name, поэтому, при попытке импортирования возникнет ошибка. +Для ее устранения, необходимо выполнить запрос на получение списка дисков, найти недостающее поле, после чего добавить его в описание ресурса. +После этого повторить попытку импортирования. + +## Общий алгоритм устранения ошибок +1. Выполнить запрос импортирования +2. В случае ошибки - внести недостающие поля. +3. Повторить п.1. + + diff --git a/wiki/4.8.0/05.02-Работа-с-таймаутами.md b/wiki/4.8.0/05.02-Работа-с-таймаутами.md new file mode 100644 index 0000000..9a739b4 --- /dev/null +++ b/wiki/4.8.0/05.02-Работа-с-таймаутами.md @@ -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 - сокращенная запись значения временного отрезка. + +Таблица с временными отрезками: + +| Отрезок | Значение | +| --- | --- | +| 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