From 825b1a0a0042a6863c195746cc247cfc18073975 Mon Sep 17 00:00:00 2001 From: asteam Date: Fri, 29 Aug 2025 12:51:25 +0300 Subject: [PATCH] v1.12.2 --- CHANGELOG.md | 170 +++++++++++++- README.md | 32 ++- client.go | 92 +++++++- client_bvs.go | 66 ++++++ interfaces/caller.go | 3 + internal/constants/constants.go | 18 +- internal/validators/custom.go | 51 ++-- internal/validators/messages.go | 37 +-- internal/validators/validator.go | 30 +-- internal/validators/values.go | 7 +- legacy-client.go | 42 ++++ pkg/cloudapi/account/list.go | 5 + pkg/cloudapi/account/models.go | 17 +- pkg/cloudapi/audit/models.go | 3 + pkg/cloudapi/bservice/group_add.go | 10 +- pkg/cloudapi/bservice/list.go | 5 + pkg/cloudapi/compute/audits.go | 44 +++- pkg/cloudapi/compute/change_secutity_group.go | 50 ++++ .../compute/create_template_from_blank.go | 4 + pkg/cloudapi/compute/disk_add.go | 4 + pkg/cloudapi/compute/filter_test.go | 2 + pkg/cloudapi/compute/list.go | 5 + pkg/cloudapi/compute/models.go | 26 +- pkg/cloudapi/compute/net_attach.go | 14 +- pkg/cloudapi/compute/redeploy.go | 4 + .../disks/change_disk_storage_policy.go | 42 ++++ pkg/cloudapi/disks/create.go | 4 + pkg/cloudapi/disks/from_platform_disk.go | 5 - pkg/cloudapi/disks/models.go | 12 + pkg/cloudapi/disks/replicate.go | 6 +- pkg/cloudapi/dpdknet/models.go | 6 + pkg/cloudapi/extnet/list.go | 5 + pkg/cloudapi/extnet/models.go | 3 + pkg/cloudapi/image/change_storage_policy.go | 41 ++++ pkg/cloudapi/image/create.go | 9 +- pkg/cloudapi/image/create_virtual.go | 5 + pkg/cloudapi/image/models.go | 3 + pkg/cloudapi/k8ci/list.go | 8 - pkg/cloudapi/k8ci/list_deleted.go | 8 - pkg/cloudapi/k8s/create.go | 4 + pkg/cloudapi/k8s/list.go | 5 + pkg/cloudapi/k8s/workers_group_add.go | 4 + pkg/cloudapi/kvmx86/create.go | 24 +- pkg/cloudapi/kvmx86/create_blank.go | 8 +- pkg/cloudapi/lb/list.go | 5 + pkg/cloudapi/rg/create.go | 12 +- pkg/cloudapi/rg/models.go | 9 + pkg/cloudapi/rg/update.go | 7 +- pkg/cloudapi/security_group/create.go | 46 ++++ pkg/cloudapi/security_group/create_rule.go | 63 +++++ pkg/cloudapi/security_group/delete.go | 36 +++ pkg/cloudapi/security_group/delete_rule.go | 40 ++++ pkg/cloudapi/security_group/filter.go | 80 +++++++ pkg/cloudapi/security_group/filter_test.go | 87 +++++++ pkg/cloudapi/security_group/get.go | 43 ++++ pkg/cloudapi/security_group/list.go | 86 +++++++ pkg/cloudapi/security_group/models.go | 43 ++++ pkg/cloudapi/security_group/security_group.go | 15 ++ pkg/cloudapi/security_group/sorting.go | 41 ++++ pkg/cloudapi/security_group/update.go | 51 ++++ pkg/cloudapi/securitygroup.go | 10 + pkg/cloudapi/storage_policy/get.go | 43 ++++ pkg/cloudapi/storage_policy/list.go | 90 +++++++ pkg/cloudapi/storage_policy/models.go | 40 ++++ pkg/cloudapi/storage_policy/storage_policy.go | 15 ++ pkg/cloudapi/storagepolicy.go | 10 + pkg/cloudapi/trunk/list.go | 3 + pkg/cloudapi/vins/list.go | 5 + pkg/cloudapi/vins/models.go | 3 + pkg/cloudapi/zone/models.go | 21 ++ pkg/cloudbroker/account/add_storage_policy.go | 46 ++++ pkg/cloudbroker/account/create.go | 12 +- pkg/cloudbroker/account/del_storage_policy.go | 42 ++++ pkg/cloudbroker/account/list.go | 5 + pkg/cloudbroker/account/models.go | 10 +- pkg/cloudbroker/account/update.go | 7 +- pkg/cloudbroker/audit/models.go | 6 + pkg/cloudbroker/bservice/group_add.go | 10 +- pkg/cloudbroker/bservice/list.go | 5 + pkg/cloudbroker/compute/audits.go | 44 +++- .../compute/change_secutity_group.go | 50 ++++ .../compute/create_template_from_blank.go | 4 + pkg/cloudbroker/compute/disk_add.go | 4 + pkg/cloudbroker/compute/list.go | 5 + pkg/cloudbroker/compute/migrate.go | 6 +- pkg/cloudbroker/compute/models.go | 22 +- pkg/cloudbroker/compute/net_attach.go | 14 +- pkg/cloudbroker/compute/redeploy.go | 4 + .../disks/change_disk_storage_policy.go | 42 ++++ pkg/cloudbroker/disks/create.go | 4 + pkg/cloudbroker/disks/from_platform_disk.go | 5 - pkg/cloudbroker/disks/models.go | 6 + pkg/cloudbroker/disks/replicate.go | 6 +- pkg/cloudbroker/dpdknet/models.go | 6 + pkg/cloudbroker/dpdknet/update.go | 4 + pkg/cloudbroker/extnet/list.go | 5 + pkg/cloudbroker/extnet/models.go | 6 + pkg/cloudbroker/extnet/update.go | 4 + .../image/change_storage_policy.go | 41 ++++ pkg/cloudbroker/image/create_cdrom_image.go | 9 +- pkg/cloudbroker/image/create_image.go | 9 +- pkg/cloudbroker/image/create_virtual.go | 5 + pkg/cloudbroker/image/models.go | 6 + pkg/cloudbroker/k8ci/create.go | 14 -- pkg/cloudbroker/k8ci/filter_test.go | 6 - pkg/cloudbroker/k8ci/list.go | 8 - pkg/cloudbroker/k8ci/list_deleted.go | 8 - pkg/cloudbroker/k8ci/models.go | 20 +- pkg/cloudbroker/k8s/create.go | 4 + pkg/cloudbroker/k8s/list.go | 5 + pkg/cloudbroker/k8s/workers_group_add.go | 4 + pkg/cloudbroker/kvmx86/create.go | 24 +- pkg/cloudbroker/kvmx86/create_blank.go | 8 +- pkg/cloudbroker/kvmx86/mass_create.go | 4 + pkg/cloudbroker/lb/list.go | 5 + pkg/cloudbroker/node/models.go | 3 + pkg/cloudbroker/rg/add_storage_policy.go | 46 ++++ pkg/cloudbroker/rg/create.go | 12 +- pkg/cloudbroker/rg/del_storage_policy.go | 42 ++++ pkg/cloudbroker/rg/models.go | 6 + pkg/cloudbroker/rg/update.go | 7 +- pkg/cloudbroker/security_group/create.go | 46 ++++ pkg/cloudbroker/security_group/create_rule.go | 63 +++++ pkg/cloudbroker/security_group/delete.go | 36 +++ pkg/cloudbroker/security_group/delete_rule.go | 40 ++++ pkg/cloudbroker/security_group/filter.go | 80 +++++++ pkg/cloudbroker/security_group/filter_test.go | 87 +++++++ pkg/cloudbroker/security_group/get.go | 43 ++++ pkg/cloudbroker/security_group/list.go | 86 +++++++ pkg/cloudbroker/security_group/models.go | 43 ++++ .../security_group/security_group.go | 15 ++ pkg/cloudbroker/security_group/sorting.go | 41 ++++ pkg/cloudbroker/security_group/update.go | 51 ++++ pkg/cloudbroker/securitygroup.go | 10 + pkg/cloudbroker/storage_policy/add_pool.go | 51 ++++ pkg/cloudbroker/storage_policy/create.go | 63 +++++ pkg/cloudbroker/storage_policy/delete.go | 36 +++ pkg/cloudbroker/storage_policy/delete_pool.go | 51 ++++ pkg/cloudbroker/storage_policy/disable.go | 36 +++ pkg/cloudbroker/storage_policy/enable.go | 36 +++ pkg/cloudbroker/storage_policy/filter.go | 71 ++++++ pkg/cloudbroker/storage_policy/filter_test.go | 110 +++++++++ pkg/cloudbroker/storage_policy/get.go | 43 ++++ pkg/cloudbroker/storage_policy/list.go | 90 +++++++ pkg/cloudbroker/storage_policy/models.go | 51 ++++ .../storage_policy/storage_policy.go | 15 ++ pkg/cloudbroker/storage_policy/update.go | 56 +++++ pkg/cloudbroker/storagepolicy.go | 10 + pkg/cloudbroker/trunk/list.go | 3 + pkg/cloudbroker/user/delete_users.go | 5 +- pkg/cloudbroker/vins/list.go | 5 + pkg/cloudbroker/vins/mass_delete.go | 10 +- pkg/cloudbroker/vins/mass_disable.go | 10 +- pkg/cloudbroker/vins/mass_enable.go | 10 +- pkg/cloudbroker/vins/models.go | 6 + pkg/cloudbroker/vins/update.go | 51 ++++ pkg/cloudbroker/zone/models.go | 21 ++ pkg/sdn/access_groups.go | 10 + pkg/sdn/acsgroups/access_groups.go | 18 ++ pkg/sdn/acsgroups/create.go | 45 ++++ pkg/sdn/acsgroups/delete.go | 39 +++ pkg/sdn/acsgroups/filter.go | 42 ++++ pkg/sdn/acsgroups/filter_test.go | 89 +++++++ pkg/sdn/acsgroups/ids.go | 19 ++ pkg/sdn/acsgroups/list.go | 80 +++++++ pkg/sdn/acsgroups/models.go | 49 ++++ pkg/sdn/acsgroups/path.go | 49 ++++ pkg/sdn/acsgroups/user_add.go | 41 ++++ pkg/sdn/acsgroups/user_delete.go | 37 +++ pkg/sdn/acsgroups/user_list.go | 113 +++++++++ pkg/sdn/acsgroups/user_update_role.go | 41 ++++ pkg/sdn/sdn.go | 16 ++ tests/platform_upgrade/cloud_test.go | 131 ++++++++++- tests/platform_upgrade/request_map.go | 222 +++++++++++------- tests/platform_upgrade/utils_get_list.go | 29 ++- tests/platform_upgrade/utils_requests.go | 81 ++++++- tests/platform_upgrade/utils_urls.go | 7 +- 177 files changed, 4819 insertions(+), 347 deletions(-) create mode 100644 pkg/cloudapi/compute/change_secutity_group.go create mode 100644 pkg/cloudapi/disks/change_disk_storage_policy.go create mode 100644 pkg/cloudapi/image/change_storage_policy.go create mode 100644 pkg/cloudapi/security_group/create.go create mode 100644 pkg/cloudapi/security_group/create_rule.go create mode 100644 pkg/cloudapi/security_group/delete.go create mode 100644 pkg/cloudapi/security_group/delete_rule.go create mode 100644 pkg/cloudapi/security_group/filter.go create mode 100644 pkg/cloudapi/security_group/filter_test.go create mode 100644 pkg/cloudapi/security_group/get.go create mode 100644 pkg/cloudapi/security_group/list.go create mode 100644 pkg/cloudapi/security_group/models.go create mode 100644 pkg/cloudapi/security_group/security_group.go create mode 100644 pkg/cloudapi/security_group/sorting.go create mode 100644 pkg/cloudapi/security_group/update.go create mode 100644 pkg/cloudapi/securitygroup.go create mode 100644 pkg/cloudapi/storage_policy/get.go create mode 100644 pkg/cloudapi/storage_policy/list.go create mode 100644 pkg/cloudapi/storage_policy/models.go create mode 100644 pkg/cloudapi/storage_policy/storage_policy.go create mode 100644 pkg/cloudapi/storagepolicy.go create mode 100644 pkg/cloudbroker/account/add_storage_policy.go create mode 100644 pkg/cloudbroker/account/del_storage_policy.go create mode 100644 pkg/cloudbroker/compute/change_secutity_group.go create mode 100644 pkg/cloudbroker/disks/change_disk_storage_policy.go create mode 100644 pkg/cloudbroker/image/change_storage_policy.go create mode 100644 pkg/cloudbroker/rg/add_storage_policy.go create mode 100644 pkg/cloudbroker/rg/del_storage_policy.go create mode 100644 pkg/cloudbroker/security_group/create.go create mode 100644 pkg/cloudbroker/security_group/create_rule.go create mode 100644 pkg/cloudbroker/security_group/delete.go create mode 100644 pkg/cloudbroker/security_group/delete_rule.go create mode 100644 pkg/cloudbroker/security_group/filter.go create mode 100644 pkg/cloudbroker/security_group/filter_test.go create mode 100644 pkg/cloudbroker/security_group/get.go create mode 100644 pkg/cloudbroker/security_group/list.go create mode 100644 pkg/cloudbroker/security_group/models.go create mode 100644 pkg/cloudbroker/security_group/security_group.go create mode 100644 pkg/cloudbroker/security_group/sorting.go create mode 100644 pkg/cloudbroker/security_group/update.go create mode 100644 pkg/cloudbroker/securitygroup.go create mode 100644 pkg/cloudbroker/storage_policy/add_pool.go create mode 100644 pkg/cloudbroker/storage_policy/create.go create mode 100644 pkg/cloudbroker/storage_policy/delete.go create mode 100644 pkg/cloudbroker/storage_policy/delete_pool.go create mode 100644 pkg/cloudbroker/storage_policy/disable.go create mode 100644 pkg/cloudbroker/storage_policy/enable.go create mode 100644 pkg/cloudbroker/storage_policy/filter.go create mode 100644 pkg/cloudbroker/storage_policy/filter_test.go create mode 100644 pkg/cloudbroker/storage_policy/get.go create mode 100644 pkg/cloudbroker/storage_policy/list.go create mode 100644 pkg/cloudbroker/storage_policy/models.go create mode 100644 pkg/cloudbroker/storage_policy/storage_policy.go create mode 100644 pkg/cloudbroker/storage_policy/update.go create mode 100644 pkg/cloudbroker/storagepolicy.go create mode 100644 pkg/cloudbroker/vins/update.go create mode 100644 pkg/sdn/access_groups.go create mode 100644 pkg/sdn/acsgroups/access_groups.go create mode 100644 pkg/sdn/acsgroups/create.go create mode 100644 pkg/sdn/acsgroups/delete.go create mode 100644 pkg/sdn/acsgroups/filter.go create mode 100644 pkg/sdn/acsgroups/filter_test.go create mode 100644 pkg/sdn/acsgroups/ids.go create mode 100644 pkg/sdn/acsgroups/list.go create mode 100644 pkg/sdn/acsgroups/models.go create mode 100644 pkg/sdn/acsgroups/path.go create mode 100644 pkg/sdn/acsgroups/user_add.go create mode 100644 pkg/sdn/acsgroups/user_delete.go create mode 100644 pkg/sdn/acsgroups/user_list.go create mode 100644 pkg/sdn/acsgroups/user_update_role.go create mode 100644 pkg/sdn/sdn.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 763d6e9..ec814d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,183 @@ -## Version 1.12.1 +## Version 1.12.2 ### Добавлено +#### общие изменения +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-525 | Поддержка работы с различными сontent-type | +| BGOS-514 | Пакет SDN со структурой для SDN запросов | +| BGOS-587 | Проверка срока действия и обновления JWT токена для `DecortClient`, в связи с добавлением срока действия токена | + #### account | Идентификатор
задачи | Описание | | --- | --- | -| BGOS-559 | В структуру ответа `RecordACL` добавлено поле `Emails` в cloudapi/account | +| BGOS-572 | Поля `StoragePolicyIDs` в структуре ответа `RecordAccount` в cloudapi/account и в `InfoAccount` cloudbroker/account | +| BGOS-572 | Поля `StoragePolicies` в структуре ответа `ResourceLimits` в cloudapi/account и в cloudbroker/account | +| BGOS-572 | Методы `AddStoragePolicy`, `DelStoragePolicyRequest` и структуры запросов `AddStoragePolicyRequest`, `DelStoragePolicyRequest` в cloudbroker/account | +| BGOS-572 | Обязательное поле `StoragePolicies` в структуру запроса `CreateRequest` в cloudbroker/account | +| BGOS-572 | Опциональное поле `StoragePolicies` в структуру запроса `UpdateRequest` в cloudbroker/account | +| BGOS-585 | Опциональное поле `ZoneID` в структуру запроса `ListRequest` в cloudapi/account и в cloudbroker/account | + +#### audit +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-595 | Поле `CorrelationID` в структуры ответа `RecordAudit` в cloudapi/audit и в `RecordAudit` и `ItemAudit` в cloudbroker/audit | + +#### bservice +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-576 | Опциональное поле `StoragePolicyID` в структуру запроса `GroupAddRequest` в cloudapi/bservice и в структуру запроса `GroupAddRequest` в cloudbroker/bservice | +| BGOS-585 | Опциональное поле `ZoneID` в структуру запроса `ListRequest` в cloudapi/bservice и в cloudbroker/bservice | #### compute | Идентификатор
задачи | Описание | | --- | --- | -| BGOS-566 | Поле `TrunkTags` в структуру `ItemVNFInterface` в структуре ответа `RecordCompute` в cloudapi/compute и в структуру `ItemInterface` в структуре ответа `RecordCompute` в cloudbroker/compute | -| BGOS-492 | Метод `MigrateAbort` и структура запроса `MigrateAbortRequest` в cloudbroker/compute | +| BGOS-569 | Опциональные поля `TimestampAT`, `TimestampTO`, `User`, `Call`, `SortBy`, `Page`, `Size`, `MinStatusCode`, `MaxStatusCode` в структуру запроса `AuditsRequest` в cloudapi/compute и в cloudbroker/compute | +| BGOS-575 | Обязательное поле `StoragePolicyID` в структуру запроса `CreateTemplateFromBlankRequest`, `DiskAddRequest`, `RedeployRequest` в cloudapi/compute и в cloudbroker/compute | +| BGOS-575 | Поле `StoragePolicyID` в структуру ответа `ItemComputeDisk` в cloudapi/compute и в структуру ответа `ItemDisk` в cloudbroker/compute | +| BGOS-580 | Поле `ZoneID` в структуру ответа `ItemCompute` в cloudapi/compute | +| BGOS-583 | Опциональные поля `SecGroups`, `EnableSecGroups` в структуру запроса `NetAttachRequest` в cloudapi/compute и в cloudbroker/compute | +| BGOS-583 | Поля `SecGroups`, `EnableSecGroups` в структуру ответа `ItemVNFInterface` в cloudapi/compute и в `ItemInterface` cloudbroker/compute | +| BGOS-585 | Опциональное поле `ZoneID` в структуру запроса `ListRequest` в cloudapi/compute и в cloudbroker/compute | +| BGOS-592 | Опциональное поле `Enabled` в структуру запроса `NetAttachRequest` в cloudapi/compute и в cloudbroker/compute | +| BGOS-593 | Поле `ToClean` в структурах ответа `ItemComputeDisk` в cloudapi/compute и `ItemDisk` cloudbroker/compute | + +#### disks +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-574 | Поля `StoragePolicyID` в структуры ответа `RecordDisk` и `ItemDisk` в cloudapi/disks и в `InfoDisk` cloudbroker/disks | +| BGOS-574 | Метод `ChangeDiskStoragePolicy` и структура запроса `ChangeDiskStoragePolicyRequest` в cloudapi/disks и в cloudbroker/disks | +| BGOS-574 | Обязательное поле `StoragePolicyID` в структуры запроса `CreateRequest` и `ReplicateRequest` в cloudapi/disks и в cloudbroker/disks | +| BGOS-593 | Поле `ToClean` в структурах ответа `ItemDisk`, `RecordDisk` в cloudapi/disks и `InfoDisk` cloudbroker/disks | + +#### dpdknet +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-584 | Опциональное поле `EnableSecGroups` в структуру запроса `UpdateRequest` в cloudbroker/dpdknet | +| BGOS-584 | Поле `EnableSecGroups` в структуры ответа `ItemDPDKNet`, `RecordDPDKNet` в cloudapi/dpdknet и в cloudbroker/dpdknet | + +#### extnet +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-585 | Опциональное поле `ZoneID` в структуру запроса `ListRequest` в cloudapi/extnet и в cloudbroker/extnet | +| BGOS-584 | Опциональное поле `EnableSecGroups` в структуру запроса `UpdateRequest` в cloudbroker/extnet | +| BGOS-584 | Поле `EnableSecGroups` в структуру ответа `ItemExtNet` в cloudbroker/extnet | +| BGOS-584 | Поле `EnableSecGroups` в структуру ответа `RecordExtNet` в cloudapi/extnet и в cloudbroker/extnet | + +#### image +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-578 | Обязательное поле `StoragePolicyID` в структуру запроса `CreateRequest` в cloudapi/image и в структуры запроса `CreateRequest` и `CreateCDROMImageRequest` в cloudbroker/image | +| BGOS-578 | Поле `StoragePolicyID` в структуру ответа `RecordImage` в cloudapi/image и в структуры ответа `RecordImage` и `ItemImage` в cloudbroker/image | +| BGOS-578 | Метод `ChangeStoragePolicy` и структура запроса `ChangeStoragePolicyRequest` в cloudapi/image и в cloudbroker/image | + +#### k8s +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-577 | Обязательное поле `StoragePolicyID` в структуры запроса `CreateRequest` и `WorkersGroupAddRequest` в cloudapi/k8s и в структуры запроса `CreateRequest` и `WorkersGroupAddRequest` в cloudbroker/k8s | +| BGOS-585 | Опциональное поле `ZoneID` в структуру запроса `ListRequest` в cloudapi/k8s и в cloudbroker/k8s | + +#### kvmx86 +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-575 | Обязательное поле `StoragePolicyID` в структуры запросов `CreateRequest`, `DataDisk`, `CreateBlankRequest` в cloudapi/kvmx86 и cloudbroker/kvmx86 и `MassCreateRequest` в cloudbroker/kvmx86 | +| BGOS-583 | Опциональные поля `SecGroups`, `EnableSecGroups` в структуру запроса `Interface` в cloudapi/kvmx86 и в cloudbroker/kvmx86 | +| BGOS-592 | Опциональное поле `Enabled` в структуру запроса `Interface` в cloudapi/kvmx86 и в cloudbroker/kvmx86 | + +#### lb +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-585 | Опциональное поле `ZoneID` в структуру запроса `ListRequest` в cloudapi/lb и в cloudbroker/lb | + +#### node +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-597 | Поле `VCPU` в структуру ответа `FreeResourcesInfo` в cloudbroker/node | + +#### rg +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-573 | Поля `StoragePolicyIDs` в структуре ответа `RecordResourceGroup` в cloudapi/rg и в `ItemRG` cloudbroker/rg | +| BGOS-573 | Поля `StoragePolicies` в структуре ответа `ResourceLimits` в cloudapi/rg и в cloudbroker/rg | +| BGOS-573 | Методы `AddStoragePolicy`, `DelStoragePolicyRequest` и структуры запросов `AddStoragePolicyRequest`, `DelStoragePolicyRequest` в cloudbroker/rg | +| BGOS-573 | Опциональное поле `StoragePolicies` в структуры запроса `CreateRequest`, `UpdateRequest` в cloudapi/rg и в cloudbroker/rg | + +#### security group +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-582 | Группа ручек `security_group` в cloudapi и в cloudbroker | + +#### storage policy +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-571 | Группа ручек `storage_policy` в cloudapi и в cloudbroker | + +#### trunk +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-565 | Опциональное поле `Status` в структуру запроса `ListRequest` в cloudapi/trunk и в cloudbroker/trunk | + +#### user +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-562 | Опциональное поле `AccountID` в структуру запроса `CreateVirtualRequest` в cloudapi/image и в cloudbroker/image | + +#### vins +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-584 | Метод `Update` и структура запроса `UpdateRequest` в cloudbroker/vins | +| BGOS-584 | Поле `EnableSecGroups` в структуру ответа `ItemVINS` в cloudbroker/vins | +| BGOS-584 | Поле `EnableSecGroups` в структуру ответа `RecordVINS` в cloudapi/vins и в cloudbroker/vins | + +#### SDN access groups +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-514 | Группа api access_groups | ### Исправлено -#### accounts +#### compute | Идентификатор
задачи | Описание | | --- | --- | -| BGOS-559 | Структура ответа `ItemAccount` использует структуру `ListRecordACL` в поле `ACL` в cloudapi/account | +| BGOS-569 | Изменена структура ответа с `ListAudits` на `*ListAudits`, содержащую поля `Data` и `EntryCount` в методе `Audits` в cloudapi/compute | +| BGOS-569 | Изменена структура ответа с `ListDetailedAudits` на `*ListDetailedAudits`, содержащую поля `Data` и `EntryCount` в методе `Audits` в cloudbroker/compute | + +#### user +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-561 | Изменен тип поля `UserIDs` с stirng на []string в структуре запроса `DeleteUsersRequest` в cloudbroker/user | + +#### vins +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-560 | Изменен тип возвращаемого значения методов `MassDelete`, `MassDisable`, `MassEnable` c bool на string в cloudbroker/vins| + +### Удалено + +#### disks +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-563 | Опциональное поле `Drivers` в структуре запроса `FromPlatformDiskRequest` в cloudapi/disks и cloudbroker/disks | + +#### compute +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-580 | Поле `ZoneID` в структуре ответа `ItemComputeDisk` в cloudapi/compute | #### image | Идентификатор
задачи | Описание | | --- | --- | -| BGOS-564 | Загрузка образов в cloudbroker/image | +| BGOS-563 | Опциональное поле `Drivers` в структуре запроса `CreateRequest` в cloudapi/image и cloudbroker/image | +| BGOS-563 | Опциональное поле `Drivers` в структуре запроса `CreateCDROMImageRequest` в cloudbroker/image | +#### k8ci +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-563 | Опциональные поля `MasterDriver` и `WorkerDriver` в структурах запроса `ListRequest` и `ListDeletedRequest` в cloudapi/k8ci и cloudbroker/k8ci | +| BGOS-563 | Опциональные поля `MasterDriver` и `WorkerDriver` в структуре запроса `CreateRequest` в cloudbroker/k8ci | + +#### kvmx86 +| Идентификатор
задачи | Описание | +| --- | --- | +| BGOS-563 | Опциональное поле `Driver` в структурах запроса `CreateRequest` и `CreateBlankRequest` в cloudapi/kvmx86 и cloudbroker/kvmx86 | \ No newline at end of file diff --git a/README.md b/README.md index ce6b218..cdc5fed 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,3 @@ -# Внимание -Данная версия предназначена только для версии платформы 4.4.0 build 963! - # Decort SDK Decort SDK - это библиотека, написанная на языке GO, позволяющая взаимодействовать с API облачной платформы **DECORT**. Библиотека содержит в себе структуры и методы, необходимые для отправки запросов. Decort SDK имеет встроенный http-клиент и поддерживает разные способы авторизации на платформе. Библиотека так же содержит в себе модели ответов от платформы. @@ -100,6 +97,7 @@ go get -u repository.basistech.ru/BASIS/decort-golang-sdk - `cloudapi` - пользовательская группа, которая позволяет воспользоваться всем стардартным функционалом платформы; - `cloudbroker` - административная группа, которая позволяет воспользоваться всем стандартным функционалом платформы и расширенными возможностями, включающими в себя управление пользователями, ресурсами, платформами размещения ресурсов и т.д. +- `sdn` - группа для работы с SDN; ### Cloudapi @@ -122,8 +120,10 @@ go get -u repository.basistech.ru/BASIS/decort-golang-sdk - `Locations` - получение информации о grid площадки; - `Prometheus` - получение статистики prometheus; - `RG` - управление ресурсными группами аккаунта; +- `Security group` – управление группами безопасности; - `SEP` - управление storage endpoint (sep); - `Stack` - получение информации о вычислительных узлах; +- `Storage policy` – получение информации о политиках хранения; - `Tasks` - получение информации о ходе выполнения асинхронных задач (например, создание кластера); - `Trunk` - получение информации о транковых портах; - `VFPool` - управление пулом виртуальных сетевых функций; @@ -157,8 +157,10 @@ go get -u repository.basistech.ru/BASIS/decort-golang-sdk - `Prometheus` - получение статистики prometheus; - `Resmon` - получение статистики resource monitoring; - `RG` - управление ресурсными группами аккаунта; +- `Security group` – управление группами безопасности; - `SEP` - управление storage endpoint (sep); - `Stack` - получение информации о вычислительных узлах; +- `Storage policy` – управление политиками хранения; - `Tasks` - получение информации о ходе выполнения асинхронных задач (например, создание кластера); - `Trunk` - управление транковыми портами; - `User` - управление пользователями (индивидуально); @@ -167,6 +169,13 @@ go get -u repository.basistech.ru/BASIS/decort-golang-sdk - `VINS` - управление виртуальными изолированными сетями. - `Zone` - управление зонами. +### SDN + +`SDN` позволяет выполнять запросы к группе пользовательских конечных точек +Данная группа ручек позволяет выполнять следующие операции в платформе: + +- `AccessGroup` - управление группами доступа + ## Работа с библиотекой Алгоритм работы с библиотекой выглядит следующим образом: @@ -293,6 +302,7 @@ func main() { - `pkg/cloudapi` - для `cloudapi` - `pkg/cloudbroker` - для `cloudbroker` +- `pkg/sdn` - для `sdn` В каждом пакете находятся пакеты групп API: @@ -313,8 +323,10 @@ func main() { - `pkg/cloudapi/locations` - для `Locations` - `pkg/cloudapi/prometheus` - для `Prometheus` - `pkg/cloudapi/rg` - для `RG` + - `pkg/cloudapi/security_group` - для `Security group` - `pkg/cloudapi/sep` - для `SEP` - `pkg/cloudapi/stack` - для `Stack` + - `pkg/cloudapi/storage_policy` - для `Storage policy` - `pkg/cloudapi/tasks` - для `Tasks` - `pkg/cloudapi/trunk` - для `Trunk` - `pkg/cloudapi/vfpool` - для `VFPool` @@ -343,8 +355,10 @@ func main() { - `pkg/cloudbroker/prometheus` - для `Prometheus` - `pkg/cloudbroker/resmon` - для `Resmon` - `pkg/cloudbroker/rg` - для `RG` + - `pkg/cloudbroker/security_group` - для `Security group` - `pkg/cloudbroker/sep` - для `SEP` - `pkg/cloudbroker/stack` - для `Stack` + - `pkg/cloudbroker/storage_policy` - для `Storage policy` - `pkg/cloudbroker/tasks` - для `Tasks` - `pkg/cloudbroker/trunk` - для `Trunk` - `pkg/cloudbroker/user` - для `User` @@ -352,6 +366,8 @@ func main() { - `pkg/cloudbroker/vfpool` - для `VFPool` - `pkg/cloudbroker/vins` - для `VINS` - `pkg/cloudbroker/zone` - для `Zone` + - **sdn**: + - `pkg/sdn/access_groups` - для `AccessGroups` Все поля структуры имеют описание, в которых содержится: @@ -485,7 +501,7 @@ func main() { Чтобы выполнить запрос, необходимо: -1. Вызвать у клиента метод, отвечаеющий за определение группы API для взаимодействия, это может быть `.CloudAPI()`, либо `.CloudBroker()`. Данные методы возвращаеют соответствующие структуры, с помощью которых можно совершать запросы. +1. Вызвать у клиента метод, отвечающий за определение группы API для взаимодействия, это может быть `.CloudAPI()`, `.CloudBroker()` или `.SDN()`. Данные методы возвращают соответствующие структуры, с помощью которых можно совершать запросы. 2. Вызвать у возвращенной структуры метод, определяющий группу ручек для взаимодействия. Доступные методы для `.CloudAPI()`: @@ -506,8 +522,10 @@ func main() { - `.Locations()` - для работы с `Locations` - `.Prometheus()` - для работы с `Prometheus` - `.RG()` - для работы с `RG` + - `.SecurityGroup()` - для работы с `Security Group` - `.SEP()` - для работы с `SEP` - `.Stack()` - для работы с `Stack` + - `.StoragePolicy()` - для работы с `Storage Policy` - `.Tasks()` - для работы с `Tasks` - `.Trunk()` - для работы с `Trunk` - `.VFPool()` - для работы с `VFPool` @@ -538,8 +556,10 @@ func main() { - `.Prometheus()` - для работы с `Prometheus` - `.Resmon()` - для работы с `Resmon` - `.RG()` - для работы с `RG` + - `.SecurityGroup()` - для работы с `Security Group` - `.SEP()` - для работы с `SEP` - `.Stack()` - для работы с `Stack` + - `.StoragePolicy()` - для работы с `Storage Policy` - `.Tasks()` - для работы с `Tasks` - `.Trunk()` - для работы с `Trunk` - `.User()` - для работы с `User` @@ -548,6 +568,10 @@ func main() { - `.VINS()` - для работы с `VINS` - `.Zone()` - для работы с `Zone` + Доступные методы для `.SDN()`: + + - `.AccessGroup()` - для работы с `AccessGroup` + 3. Вызвать метод, отвечающий за выполнение запроса и передать в него: - контекст; diff --git a/client.go b/client.go index e0df530..d68e035 100644 --- a/client.go +++ b/client.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/tls" + "encoding/base64" "encoding/json" "fmt" "io" @@ -21,6 +22,7 @@ import ( "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/sdn" ) // DecortClient is HTTP-client for platform @@ -38,12 +40,6 @@ func New(cfg config.Config) *DecortClient { cfg.Retries = 5 } - var expiryTime time.Time - - if cfg.Token != "" { - expiryTime = time.Now().AddDate(0, 0, 1) - } - return &DecortClient{ decortURL: cfg.DecortURL, client: &http.Client{ @@ -54,9 +50,8 @@ func New(cfg config.Config) *DecortClient { }, }, }, - cfg: trimConfig(&cfg), - expiryTime: expiryTime, - mutex: &sync.Mutex{}, + cfg: trimConfig(&cfg), + mutex: &sync.Mutex{}, } } @@ -70,6 +65,11 @@ func (dc *DecortClient) CloudBroker() *cloudbroker.CloudBroker { return cloudbroker.New(dc) } +// SDN builder +func (dc *DecortClient) SDN() *sdn.SDN { + return sdn.New(dc) +} + // DecortApiCall method for sending requests to the platform func (dc *DecortClient) DecortApiCall(ctx context.Context, method, url string, params interface{}) ([]byte, error) { @@ -107,6 +107,47 @@ func (dc *DecortClient) DecortApiCall(ctx context.Context, method, url string, p return respBytes, err } +// DecortApiCallCtype method for sending requests to the platform with content type +func (dc *DecortClient) DecortApiCallCtype(ctx context.Context, method, url, ctype string, params interface{}) ([]byte, error) { + + var body *bytes.Buffer + + switch ctype { + case constants.MIMESTREAM: + body = bytes.NewBuffer(params.([]byte)) + case constants.MIMEJSON: + jsonBody, err := json.Marshal(params) + if err != nil { + return nil, err + } + body = bytes.NewBuffer(jsonBody) + default: + ctype = constants.MIMEPOSTForm + values, err := query.Values(params) + if err != nil { + return nil, err + } + body = bytes.NewBufferString(values.Encode()) + } + + req, err := http.NewRequestWithContext(ctx, method, dc.decortURL+constants.RESTMACHINE+url, body) + if err != nil { + return nil, err + } + + // get token + if err = dc.getToken(ctx); err != nil { + return nil, err + } + // perform request + respBytes, err := dc.do(req, ctype) + if err != nil { + return nil, err + } + + return respBytes, err +} + // DecortApiCallMP method for sending requests to the platform func (dc *DecortClient) DecortApiCallMP(ctx context.Context, method, url string, params interface{}) ([]byte, error) { body, ctype, err := multiPartReq(params) @@ -170,8 +211,13 @@ func (dc *DecortClient) getToken(ctx context.Context) error { // save token in config token := string(tokenBytes) + expiryTime, err := getTokenExp(token) + if err != nil { + return fmt.Errorf("cannot get expiry time: %w", err) + } + dc.cfg.Token = token - dc.expiryTime = time.Now().AddDate(0, 0, 1) + dc.expiryTime = expiryTime return nil } @@ -375,3 +421,29 @@ func trimConfig(cfg *config.Config) config.Config { cfg.DecortURL = strings.TrimSuffix(cfg.DecortURL, "/") return *cfg } + +func getTokenExp(token string) (time.Time, error) { + parts := strings.Split(token, ".") + if len(parts) != 3 { + return time.Time{}, fmt.Errorf("invalid token format") + } + + payload, err := base64.RawURLEncoding.DecodeString(parts[1]) + if err != nil { + return time.Time{}, fmt.Errorf("error decode payload from token: %w", err) + } + + var claims map[string]interface{} + if err := json.Unmarshal(payload, &claims); err != nil { + return time.Time{}, err + } + + exp, ok := claims["exp"] + if !ok { + return time.Time{}, fmt.Errorf("exp time bot found") + } + + expTime := time.Unix(int64(exp.(float64)), 0) + + return expTime, nil +} diff --git a/client_bvs.go b/client_bvs.go index 347d273..31c2cb1 100644 --- a/client_bvs.go +++ b/client_bvs.go @@ -131,6 +131,72 @@ func (bdc *BVSDecortClient) DecortApiCall(ctx context.Context, method, url strin return respBytes, err } +// DecortApiCallCtype method for sending requests to the platform with content type +func (bdc *BVSDecortClient) DecortApiCallCtype(ctx context.Context, method, url, ctype string, params interface{}) ([]byte, error) { + var body *bytes.Buffer + + switch ctype { + case constants.MIMESTREAM: + body = bytes.NewBuffer(params.([]byte)) + case constants.MIMEJSON: + jsonBody, err := json.Marshal(params) + if err != nil { + return nil, err + } + body = bytes.NewBuffer(jsonBody) + default: + ctype = constants.MIMEPOSTForm + values, err := query.Values(params) + if err != nil { + return nil, err + } + body = bytes.NewBufferString(values.Encode()) + } + + req, err := http.NewRequestWithContext(ctx, method, bdc.decortURL+constants.RESTMACHINE+url, body) + if err != nil { + return nil, err + } + + // get token + if bdc.cfg.Token.AccessToken == "" { + if _, err = bdc.GetToken(ctx); err != nil { + return nil, err + } + } + + // refresh token + if bdc.cfg.Token.RefreshToken != "" && bdc.cfg.Token.Expiry.Add(-time.Duration(bdc.cfg.TimeToRefresh)*time.Minute).Before(time.Now()) { + if _, err := bdc.RefreshToken(ctx); err != nil { + if _, err = bdc.GetToken(ctx); err != nil { + return nil, err + } + } + } + + // perform request + reqCopy := req.Clone(ctx) + respBytes, err := bdc.do(req, ctype) + if err == nil { + return respBytes, nil + } + + // get token and retry in case of access denied + if err.Error() == "access is denied" { + _, err = bdc.GetToken(ctx) + if err != nil { + return nil, err + } + + respBytes, err = bdc.do(reqCopy, "") + if err != nil { + return nil, err + } + } + + return respBytes, err +} + func (bdc *BVSDecortClient) DecortApiCallMP(ctx context.Context, method, url string, params interface{}) ([]byte, error) { body, ctype, err := multiPartReq(params) if err != nil { diff --git a/interfaces/caller.go b/interfaces/caller.go index c40b0ba..026ac22 100644 --- a/interfaces/caller.go +++ b/interfaces/caller.go @@ -7,6 +7,9 @@ type Caller interface { // DecortApiCall method for sending requests to the platform DecortApiCall(ctx context.Context, method, url string, params interface{}) ([]byte, error) + // DecortApiCallCtype method for sending requests to the platform + DecortApiCallCtype(ctx context.Context, method, url, ctype string, params interface{}) ([]byte, error) + // DecortApiCallMP method for sending requests to the platform DecortApiCallMP(ctx context.Context, method, url string, params interface{}) ([]byte, error) } diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 4ebc2e3..831511b 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -2,9 +2,23 @@ package constants const ( RESTMACHINE = "/restmachine" +) - // RAM_DIVISIBILITY sets divisibility of RAM value - RAM_DIVISIBILITY uint64 = 128 +const ( + MIMEJSON = "application/json" + MIMEHTML = "text/html" + MIMEXML = "application/xml" + MIMEXML2 = "text/xml" + MIMEPlain = "text/plain" + MIMEPOSTForm = "application/x-www-form-urlencoded" + MIMEMultipartPOSTForm = "multipart/form-data" + MIMEPROTOBUF = "application/x-protobuf" + MIMEMSGPACK = "application/x-msgpack" + MIMEMSGPACK2 = "application/msgpack" + MIMEYAML = "application/x-yaml" + MIMEYAML2 = "application/yaml" + MIMETOML = "application/toml" + MIMESTREAM = "application/octet-stream" ) var FileName = map[string]string{ diff --git a/internal/validators/custom.go b/internal/validators/custom.go index b8d9306..13a0ace 100644 --- a/internal/validators/custom.go +++ b/internal/validators/custom.go @@ -14,13 +14,6 @@ import ( "repository.basistech.ru/BASIS/decort-golang-sdk/internal/multierror" ) -// computeDriverValidator is used to validate Driver field in kvmx86 create. -func computeDriverValidator(fe validator.FieldLevel) bool { - fieldValue := fe.Field().String() - - return IsInSlice(fieldValue, computeDriverValues) -} - // protoValidator is used to validate Proto fields. func protoValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() @@ -58,13 +51,6 @@ func resTypesValidator(fe validator.FieldLevel) bool { return true } -// driverValidator is used to validate Driver fields. -func driverValidator(fe validator.FieldLevel) bool { - fieldValue := fe.Field().String() - - return IsInSlice(fieldValue, driverValues) -} - // accountCUTypeValidator is used to validate CUType field. func accountCUTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() @@ -121,6 +107,27 @@ func computex86NetTypeValidator(fe validator.FieldLevel) bool { return IsInSlice(fieldValue, computex86NetTypeValues) } +// securityGroupDirectionValidator is used to validate Direction field +func securityGroupDirectionValidator(fe validator.FieldLevel) bool { + fieldValue := fe.Field().String() + + return IsInSlice(fieldValue, securityGroupDirectionValues) +} + +// securityGroupEthertypeValidator is used to validate Ethertype field +func securityGroupEthertypeValidator(fe validator.FieldLevel) bool { + fieldValue := fe.Field().String() + + return IsInSlice(fieldValue, securityGroupEthertypeValues) +} + +// securityGroupProtocolValidator is used to validate Protocol field +func securityGroupProtocolValidator(fe validator.FieldLevel) bool { + fieldValue := fe.Field().String() + + return IsInSlice(fieldValue, securityGroupProtocolValues) +} + // computeOrderValidator is used to validate Order field. func computeOrderValidator(fe validator.FieldLevel) bool { fieldSlice, ok := fe.Field().Interface().([]string) @@ -207,22 +214,6 @@ func imageTypeValidator(fe validator.FieldLevel) bool { return IsInSlice(fieldValue, imageTypeValues) } -// imageDriversValidator is used to validate Drivers field. -func imageDriversValidator(fe validator.FieldLevel) bool { - fieldSlice, ok := fe.Field().Interface().([]string) - if !ok { - return false - } - - for _, item := range fieldSlice { - if !IsInSlice(item, imageDriversValues) { - return false - } - } - - return true -} - // imageArchitectureValidator is used to validate Architecture field. func imageArchitectureValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() diff --git a/internal/validators/messages.go b/internal/validators/messages.go index 2fa8436..09d1a77 100644 --- a/internal/validators/messages.go +++ b/internal/validators/messages.go @@ -28,12 +28,6 @@ func errorMessage(fe validator.FieldError) string { case "isBool": return fmt.Sprintf("%s %s: must be bool type", prefix, fe.Field()) - case "driver": - return fmt.Sprintf("%s %s must be one of the following: %s", - prefix, - fe.Field(), - joinValues(driverValues)) - case "accessType": return fmt.Sprintf("%s %s must be one of the following: %s", prefix, @@ -128,12 +122,6 @@ func errorMessage(fe validator.FieldError) string { fe.Field(), joinValues(computeDataDisksValues)) - case "computeDriver": - return fmt.Sprintf("%s %s must be one of the following: %s", - prefix, - fe.Field(), - joinValues(computeDriverValues)) - // Disk Validators case "diskType": return fmt.Sprintf("%s %s must be one of the following: %s", @@ -201,12 +189,6 @@ func errorMessage(fe validator.FieldError) string { fe.Field(), joinValues(imageTypeValues)) - case "imageDrivers": - return fmt.Sprintf("%s %s must contain only the following: %s", - prefix, - fe.Field(), - joinValues(imageDriversValues)) - case "imageArchitecture": return fmt.Sprintf("%s %s must be one of the following: %s", prefix, @@ -341,6 +323,25 @@ func errorMessage(fe validator.FieldError) string { fe.Field(), joinValues(userProviders)) + // security group validators + case "securityGroupDirection": + return fmt.Sprintf("%s %s must be one of the following: %s", + prefix, + fe.Field(), + joinValues(securityGroupDirectionValues)) + + case "securityGroupEthertype": + return fmt.Sprintf("%s %s must be one of the following: %s", + prefix, + fe.Field(), + joinValues(securityGroupEthertypeValues)) + + case "securityGroupProtocol": + return fmt.Sprintf("%s %s must be one of the following: %s", + prefix, + fe.Field(), + joinValues(securityGroupProtocolValues)) + // trunk tags validator case "trunkTags": return fmt.Sprintf("%s %s must be in range from 1 to 4095", diff --git a/internal/validators/validator.go b/internal/validators/validator.go index aaae78e..9a21cc6 100644 --- a/internal/validators/validator.go +++ b/internal/validators/validator.go @@ -31,11 +31,6 @@ func registerAllValidators(validate *validator.Validate) error { return err } - err = validate.RegisterValidation("computeDriver", computeDriverValidator) - if err != nil { - return err - } - err = validate.RegisterValidation("apiGroup", apiGroupValidator) if err != nil { return err @@ -51,11 +46,6 @@ func registerAllValidators(validate *validator.Validate) error { return err } - err = validate.RegisterValidation("driver", driverValidator) - if err != nil { - return err - } - err = validate.RegisterValidation("imageBootType", imageBootTypeValidator) if err != nil { return err @@ -66,11 +56,6 @@ func registerAllValidators(validate *validator.Validate) error { return err } - err = validate.RegisterValidation("imageDrivers", imageDriversValidator) - if err != nil { - return err - } - err = validate.RegisterValidation("imageArchitecture", imageArchitectureValidator) if err != nil { return err @@ -301,5 +286,20 @@ func registerAllValidators(validate *validator.Validate) error { return err } + err = validate.RegisterValidation("securityGroupDirection", securityGroupDirectionValidator) + if err != nil { + return err + } + + err = validate.RegisterValidation("securityGroupEthertype", securityGroupEthertypeValidator) + if err != nil { + return err + } + + err = validate.RegisterValidation("securityGroupProtocol", securityGroupProtocolValidator) + if err != nil { + return err + } + return nil } diff --git a/internal/validators/values.go b/internal/validators/values.go index 029309a..5e1802e 100644 --- a/internal/validators/values.go +++ b/internal/validators/values.go @@ -3,7 +3,6 @@ package validators var ( apiGroupValues = []string{"cloudapi", "cloudbroker", "system"} - driverValues = []string{"KVM_X86"} accessTypeValues = []string{"R", "RCX", "ARCXDU"} resTypesValues = []string{"compute", "vins", "k8s", "openshift", "lb", "flipgroup"} protoValues = []string{"tcp", "udp"} @@ -20,7 +19,6 @@ var ( computex86NetTypeValues = []string{"EXTNET", "VINS", "VFNIC", "DPDK", "SDN", "EMPTY", "TRUNK"} computeOrderValues = []string{"cdrom", "network", "hd"} computeDataDisksValues = []string{"KEEP", "DETACH", "DESTROY"} - computeDriverValues = []string{"KVM_X86"} diskTypeValues = []string{"B", "T", "D"} @@ -38,7 +36,6 @@ var ( imageBootTypeValues = []string{"uefi", "bios"} imageTypeValues = []string{"windows", "linux", "unknown"} - imageDriversValues = []string{"KVM_X86"} imageArchitectureValues = []string{"X86_64"} sepFieldTypeValues = []string{"int", "str", "bool", "list", "dict"} @@ -76,6 +73,10 @@ var ( userProviders = []string{"bvs", "decs3o"} deviceValues = []string{"primary", "secondary"} + + securityGroupDirectionValues = []string{"inbound", "outbound"} + securityGroupEthertypeValues = []string{"IPv4", "IPv6"} + securityGroupProtocolValues = []string{"icmp", "tcp", "udp"} ) const ( diff --git a/legacy-client.go b/legacy-client.go index f605788..9103e1a 100644 --- a/legacy-client.go +++ b/legacy-client.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/tls" + "encoding/json" "fmt" "io" "net/http" @@ -102,6 +103,47 @@ func (ldc *LegacyDecortClient) DecortApiCall(ctx context.Context, method, url st return respBytes, err } +// DecortApiCallCtype method for sending requests to the platform with content type +func (ldc *LegacyDecortClient) DecortApiCallCtype(ctx context.Context, method, url, ctype string, params interface{}) ([]byte, error) { + // get token + if err := ldc.getToken(ctx); err != nil { + return nil, err + } + + var body *bytes.Buffer + + switch ctype { + case constants.MIMESTREAM: + body = bytes.NewBuffer(params.([]byte)) + case constants.MIMEJSON: + jsonBody, err := json.Marshal(params) + if err != nil { + return nil, err + } + body = bytes.NewBuffer(jsonBody) + default: + ctype = constants.MIMEPOSTForm + values, err := query.Values(params) + if err != nil { + return nil, err + } + body = bytes.NewBufferString(values.Encode() + fmt.Sprintf("&authkey=%s", ldc.cfg.Token)) + } + + req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+constants.RESTMACHINE+url, body) + if err != nil { + return nil, err + } + + // perform request + respBytes, err := ldc.do(req, ctype) + if err != nil { + return nil, err + } + + return respBytes, err +} + func (ldc *LegacyDecortClient) DecortApiCallMP(ctx context.Context, method, url string, params interface{}) ([]byte, error) { body, ctype, err := multiPartReq(params) if err != nil { diff --git a/pkg/cloudapi/account/list.go b/pkg/cloudapi/account/list.go index 81d355a..07ce97b 100644 --- a/pkg/cloudapi/account/list.go +++ b/pkg/cloudapi/account/list.go @@ -30,6 +30,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudapi/account/models.go b/pkg/cloudapi/account/models.go index 091ba28..16c14a9 100644 --- a/pkg/cloudapi/account/models.go +++ b/pkg/cloudapi/account/models.go @@ -73,6 +73,15 @@ type ResourceLimits struct { // Number of graphics cores GPUUnits float64 `json:"gpu_units"` + + // Storage policy + StoragePolicy []StoragePolicyItem `json:"storage_policy"` +} + +type StoragePolicyItem struct { + ID uint64 `json:"id"` + + Limit int `json:"limit"` } // Main information in one of if the list of accounts @@ -103,6 +112,9 @@ type ItemAccount struct { // Updated time UpdatedTime uint64 `json:"updatedTime"` + + // Zones + ZoneIDs []uint64 `json:"zoneIds"` } // List of accounts @@ -275,6 +287,9 @@ type RecordAccount struct { // Status Status string `json:"status"` + // Storage policy ids + StoragePolicyIDs []uint64 `json:"storage_policy_ids"` + // UniqPools UniqPools []interface{} `json:"uniqPools"` @@ -291,7 +306,7 @@ type RecordAccount struct { VINSes uint64 `json:"vinses"` // Zone - ZoneIDs []ZoneID + ZoneIDs []ZoneID `json:"zoneIds"` // Zones DefaultZoneID uint64 `json:"defaultZoneId"` diff --git a/pkg/cloudapi/audit/models.go b/pkg/cloudapi/audit/models.go index 8bb0ef0..1e9faff 100644 --- a/pkg/cloudapi/audit/models.go +++ b/pkg/cloudapi/audit/models.go @@ -12,6 +12,9 @@ type RecordAudit struct { // GUID GUID string `json:"guid"` + // Correlation ID + CorrelationID string `json:"correlation_id"` + // Kwargs Kwargs string `json:"kwargs"` diff --git a/pkg/cloudapi/bservice/group_add.go b/pkg/cloudapi/bservice/group_add.go index 5b5630e..38ca0e8 100644 --- a/pkg/cloudapi/bservice/group_add.go +++ b/pkg/cloudapi/bservice/group_add.go @@ -38,11 +38,9 @@ type GroupAddRequest struct { // Required: true ImageID uint64 `url:"imageId" json:"imageId" validate:"required"` - // Compute driver - // should be one of: - // - KVM_X86 + // Compute driver like a KVM_X86, etc. // Required: true - Driver string `url:"driver" json:"driver" validate:"driver"` + Driver string `url:"driver" json:"driver" validate:"required"` // Storage endpoint provider ID // Required: false @@ -75,6 +73,10 @@ type GroupAddRequest struct { //Chipset "i440fx" or "Q35 //Required: false Chipset string `url:"chipset,omitempty" json:"chipset,omitempty" validate:"chipset,omitempty"` + + // ID of the chosen storage policy + // Required: false + StoragePolicyID uint64 `url:"storage_policy_id,omitempty" json:"storage_policy_id,omitempty"` } // GetRAM returns RAM field values diff --git a/pkg/cloudapi/bservice/list.go b/pkg/cloudapi/bservice/list.go index 31734c7..6bc4910 100644 --- a/pkg/cloudapi/bservice/list.go +++ b/pkg/cloudapi/bservice/list.go @@ -46,6 +46,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudapi/compute/audits.go b/pkg/cloudapi/compute/audits.go index 9c42fa7..e69bdf8 100644 --- a/pkg/cloudapi/compute/audits.go +++ b/pkg/cloudapi/compute/audits.go @@ -12,11 +12,47 @@ import ( type AuditsRequest struct { // ID of the compute // Required: true - ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + ComputeID uint64 `url:"compute_id" json:"compute_id" validate:"required"` + + // Find all audits after point in time + // Required: false + TimestampAT uint64 `url:"timestamp_at,omitempty" json:"timestamp_at,omitempty"` + + // Find all audits before point in time + // Required: false + TimestampTO uint64 `url:"timestamp_to,omitempty" json:"timestamp_to,omitempty"` + + // Find by user + // Required: false + User string `url:"user,omitempty" json:"user,omitempty"` + + // Find by api endpoints + // Required: false + Call string `url:"call,omitempty" json:"call,omitempty"` + + // Sort by one of supported fields, format ± + // Required: false + SortBy string `url:"sort_by,omitempty" json:"sort_by,omitempty"` + + // Page number + // Required: false + Page uint64 `url:"page,omitempty" json:"page,omitempty"` + + // Page size + // Required: false + Size uint64 `url:"size,omitempty" json:"size,omitempty"` + + // Find by HTTP min status code + // Required: false + MinStatusCode uint64 `url:"min_status_code,omitempty" json:"min_status_code,omitempty"` + + // Find by HTTP max status code + // Required: false + MaxStatusCode uint64 `url:"max_status_code,omitempty" json:"max_status_code,omitempty"` } // Audits gets audit records for the specified compute object -func (c Compute) Audits(ctx context.Context, req AuditsRequest) (ListAudits, error) { +func (c Compute) Audits(ctx context.Context, req AuditsRequest) (*ListAudits, error) { err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) @@ -24,7 +60,7 @@ func (c Compute) Audits(ctx context.Context, req AuditsRequest) (ListAudits, err url := "/cloudapi/compute/audits" - res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := c.client.DecortApiCall(ctx, http.MethodGet, url, req) if err != nil { return nil, err } @@ -36,5 +72,5 @@ func (c Compute) Audits(ctx context.Context, req AuditsRequest) (ListAudits, err return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/compute/change_secutity_group.go b/pkg/cloudapi/compute/change_secutity_group.go new file mode 100644 index 0000000..4122bf2 --- /dev/null +++ b/pkg/cloudapi/compute/change_secutity_group.go @@ -0,0 +1,50 @@ +package compute + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ChangeSecGroupsRequest struct to change security groups for compute +type ChangeSecGroupsRequest struct { + // Identifier compute + // Required: true + ComputeID uint64 `url:"compute_id" json:"compute_id" validate:"required"` + + // Interface name or MAC address + // Required: true + Interface string `url:"interface" json:"interface" validate:"required"` + + // List of security group IDs to assign to this interface + // Required: false + SecGroups []uint64 `url:"security_groups,omitempty" json:"security_groups,omitempty"` + + // Flag indicating whether security groups are enabled for this interface + // Required: false + EnableSecGroups bool `url:"enable_secgroups,omitempty" json:"enable_secgroups,omitempty"` +} + +// ChangeSecGroups changes security groups for compute +func (c Compute) ChangeSecGroups(ctx context.Context, req ChangeSecGroupsRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/compute/change_security_groups" + + res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudapi/compute/create_template_from_blank.go b/pkg/cloudapi/compute/create_template_from_blank.go index a1c0be7..11d6940 100644 --- a/pkg/cloudapi/compute/create_template_from_blank.go +++ b/pkg/cloudapi/compute/create_template_from_blank.go @@ -27,6 +27,10 @@ type CreateTemplateFromBlankRequest struct { // Required: true ImageType string `url:"imagetype" json:"imagetype" validate:"imageType"` + // Storage policy id of disk. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Username for the image // Required: false Username string `url:"username,omitempty" json:"username,omitempty"` diff --git a/pkg/cloudapi/compute/disk_add.go b/pkg/cloudapi/compute/disk_add.go index 3b958ce..fafe9ea 100644 --- a/pkg/cloudapi/compute/disk_add.go +++ b/pkg/cloudapi/compute/disk_add.go @@ -22,6 +22,10 @@ type DiskAddRequest struct { // Required: true Size uint64 `url:"size" json:"size" validate:"required"` + // Storage policy id of disk. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Type of the disk // Should be one of: // - D diff --git a/pkg/cloudapi/compute/filter_test.go b/pkg/cloudapi/compute/filter_test.go index 513d2a9..34095bf 100644 --- a/pkg/cloudapi/compute/filter_test.go +++ b/pkg/cloudapi/compute/filter_test.go @@ -83,6 +83,7 @@ var computes = ListComputes{ VGPUs: []uint64{}, VINSConnected: 0, VirtualImageID: 0, + ZoneID: 1, }, { ACL: ListACL{}, @@ -145,6 +146,7 @@ var computes = ListComputes{ VGPUs: []uint64{}, VINSConnected: 0, VirtualImageID: 0, + ZoneID: 5, }, }, EntryCount: 2, diff --git a/pkg/cloudapi/compute/list.go b/pkg/cloudapi/compute/list.go index 6ec6b84..284cf47 100644 --- a/pkg/cloudapi/compute/list.go +++ b/pkg/cloudapi/compute/list.go @@ -58,6 +58,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudapi/compute/models.go b/pkg/cloudapi/compute/models.go index 50b00c1..68e1a6a 100644 --- a/pkg/cloudapi/compute/models.go +++ b/pkg/cloudapi/compute/models.go @@ -238,7 +238,13 @@ type ItemAudit struct { } // List Detailed audits -type ListAudits []ItemAudit +type ListAudits struct { + // Data + Data []ItemAudit `json:"data"` + + // Entry count + EntryCount uint64 `json:"entryCount"` +} // Short information about audit type ItemShortAudit struct { @@ -661,6 +667,9 @@ type ItemVNFInterface struct { // Enabled Enabled bool `json:"enabled"` + // Enable security groups + EnableSecGroups bool `json:"enable_secgroups"` + // FLIPGroup ID FLIPGroupID uint64 `json:"flipgroupId"` @@ -703,6 +712,9 @@ type ItemVNFInterface struct { // QOS QOS QOS `json:"qos"` + // List of security groups + SecGroups []uint64 `json:"security_groups"` + // SDN interface ID SDNInterfaceID string `json:"sdn_interface_id"` @@ -848,17 +860,20 @@ type ItemComputeDisk struct { // Status Status string `json:"status"` + // Storage policy id of compute. + StoragePolicyID uint64 `json:"storage_policy_id"` + // Tech status TechStatus string `json:"techStatus"` + // Need to clean before destroy + ToClean bool `json:"to_clean"` + // Type Type string `json:"type"` // Updated by UpdatedBy string `json:"updatedBy"` - - // Zone ID - ZoneID uint64 `json:"zoneId"` } type ItemReplication struct { @@ -1161,6 +1176,9 @@ type ItemCompute struct { // Virtual image ID VirtualImageID uint64 `json:"virtualImageId"` + + // Zone ID + ZoneID uint64 `json:"zoneId"` } // ListInfoDisks diff --git a/pkg/cloudapi/compute/net_attach.go b/pkg/cloudapi/compute/net_attach.go index 854a316..0f3ccce 100644 --- a/pkg/cloudapi/compute/net_attach.go +++ b/pkg/cloudapi/compute/net_attach.go @@ -42,12 +42,24 @@ type NetAttachRequest struct { // Used only for EXTNET and DPDK // For DPDK must be 1-9216 // For EXTNET must be 1500-9216 - // Required: false + // Required: false MTU uint64 `url:"mtu,omitempty" json:"mtu,omitempty" validate:"omitempty,mtu"` // Unique identifier of logical port on SDN side // Required: false SDNInterfaceID string `url:"sdn_interface_id,omitempty" json:"sdn_interface_id,omitempty" validate:"omitempty"` + + // List of security group IDs to assign to this interface + // Required: false + SecGroups []uint64 `url:"security_groups,omitempty" json:"security_groups,omitempty"` + + // Flag indicating whether security groups are enabled for this interface + // Required: false + EnableSecGroups bool `url:"enable_secgroups,omitempty" json:"enable_secgroups,omitempty"` + + // Flag indicating whether this interface is enabled (only for VINS, EXTNET, DPDK, SDN, TRUNK) + // Required: false + Enabled interface{} `url:"enabled,omitempty" json:"enabled,omitempty" validate:"omitempty,isBool"` } // NetAttach attaches network to compute and gets info about network diff --git a/pkg/cloudapi/compute/redeploy.go b/pkg/cloudapi/compute/redeploy.go index 22ee5fa..a170b5b 100644 --- a/pkg/cloudapi/compute/redeploy.go +++ b/pkg/cloudapi/compute/redeploy.go @@ -14,6 +14,10 @@ type RedeployRequest struct { // Required: true ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + // Storage policy id of compute. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // ID of the new OS image, if image change is required // Required: false ImageID uint64 `url:"imageId,omitempty" json:"imageId,omitempty"` diff --git a/pkg/cloudapi/disks/change_disk_storage_policy.go b/pkg/cloudapi/disks/change_disk_storage_policy.go new file mode 100644 index 0000000..4221a4e --- /dev/null +++ b/pkg/cloudapi/disks/change_disk_storage_policy.go @@ -0,0 +1,42 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ChangeDiskStoragePolicyRequest struct to change storage policy for disk +type ChangeDiskStoragePolicyRequest struct { + // ID of the disk + // Required: true + DiskID uint64 `url:"disk_id" json:"disk_id" validate:"required"` + + // ID of the storage policy to which to connect for disk + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +// ChangeDiskStoragePolicy changes storage policy for disk +func (d Disks) ChangeDiskStoragePolicy(ctx context.Context, req ChangeDiskStoragePolicyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/disks/change_disk_storage_policy" + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudapi/disks/create.go b/pkg/cloudapi/disks/create.go index ab894cb..ffbce52 100644 --- a/pkg/cloudapi/disks/create.go +++ b/pkg/cloudapi/disks/create.go @@ -18,6 +18,10 @@ type CreateRequest struct { // Required: true Name string `url:"name" json:"name" validate:"required"` + // ID of the storage policy under the disk will be created + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Description of disk // Required: false Description string `url:"description,omitempty" json:"description,omitempty"` diff --git a/pkg/cloudapi/disks/from_platform_disk.go b/pkg/cloudapi/disks/from_platform_disk.go index a69fd6a..41b1d69 100644 --- a/pkg/cloudapi/disks/from_platform_disk.go +++ b/pkg/cloudapi/disks/from_platform_disk.go @@ -43,11 +43,6 @@ type FromPlatformDiskRequest struct { // Required: false PoolName string `url:"poolName,omitempty" json:"poolName,omitempty"` - // List of types of compute suitable for image - // Example: [ "KVM_X86" ] - // Required: true - Drivers []string `url:"drivers" json:"drivers" validate:"required"` - // Does this machine supports hot resize // Required: false HotResize bool `url:"hotresize" json:"hotresize"` diff --git a/pkg/cloudapi/disks/models.go b/pkg/cloudapi/disks/models.go index 026b78e..db67195 100644 --- a/pkg/cloudapi/disks/models.go +++ b/pkg/cloudapi/disks/models.go @@ -119,9 +119,15 @@ type ItemDisk struct { // Status Status string `json:"status"` + // Storage policy ID + StoragePolicyID uint64 `json:"storage_policy_id"` + // Tech status TechStatus string `json:"techStatus"` + // Need to clean before destroy + ToClean bool `json:"to_clean"` + // Type Type string `json:"type"` @@ -477,9 +483,15 @@ type RecordDisk struct { // Status Status string `json:"status"` + // Storage policy ID + StoragePolicyID uint64 `json:"storage_policy_id"` + // Tech status TechStatus string `json:"techStatus"` + // Need to clean before destroy + ToClean bool `json:"to_clean"` + // Type Type string `json:"type"` diff --git a/pkg/cloudapi/disks/replicate.go b/pkg/cloudapi/disks/replicate.go index 3e2496e..0af3af9 100644 --- a/pkg/cloudapi/disks/replicate.go +++ b/pkg/cloudapi/disks/replicate.go @@ -25,9 +25,13 @@ type ReplicateRequest struct { // Pool name to create slave disk in // Required: true PoolName string `url:"poolName" json:"poolName" validate:"required"` + + // ID of the storage policy under the disk will be created + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` } -// Create an empty disk in chosen SEP and pool combination. +// Replicate create an empty disk in chosen SEP and pool combination. // Starts replication between chosen disk and newly created disk // Note: only TATLIN type SEP are supported for replications between func (d Disks) Replicate(ctx context.Context, req ReplicateRequest) (uint64, error) { diff --git a/pkg/cloudapi/dpdknet/models.go b/pkg/cloudapi/dpdknet/models.go index 7bcf84d..ebcca93 100644 --- a/pkg/cloudapi/dpdknet/models.go +++ b/pkg/cloudapi/dpdknet/models.go @@ -14,6 +14,9 @@ type RecordDPDKNet struct { // Description Description string `json:"description"` + // Enable Security Groups + EnableSecGroups bool `json:"enable_secgroups"` + // Grid ID GID uint64 `json:"gid"` @@ -63,6 +66,9 @@ type ItemDPDKNet struct { // Description Description string `json:"description"` + // Enable Security Groups + EnableSecGroups bool `json:"enable_secgroups"` + // Grid ID GID uint64 `json:"gid"` diff --git a/pkg/cloudapi/extnet/list.go b/pkg/cloudapi/extnet/list.go index e14d313..8af3884 100644 --- a/pkg/cloudapi/extnet/list.go +++ b/pkg/cloudapi/extnet/list.go @@ -42,6 +42,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudapi/extnet/models.go b/pkg/cloudapi/extnet/models.go index 0350823..b7a7e9d 100644 --- a/pkg/cloudapi/extnet/models.go +++ b/pkg/cloudapi/extnet/models.go @@ -172,6 +172,9 @@ type RecordExtNet struct { // Excluded Excluded []Excluded `json:"excluded"` + // Enable Security Groups + EnableSecGroups bool `json:"enable_secgroups"` + // Free IPs FreeIPs int64 `json:"free_ips"` diff --git a/pkg/cloudapi/image/change_storage_policy.go b/pkg/cloudapi/image/change_storage_policy.go new file mode 100644 index 0000000..4a34293 --- /dev/null +++ b/pkg/cloudapi/image/change_storage_policy.go @@ -0,0 +1,41 @@ +package image + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type ChangeStoragePolicyRequest struct { + // ID of the image to change the storage policy + // Required: true + ImageID uint64 `url:"image_id" json:"image_id" validate:"required"` + + // ID of the storage policy to move the image to + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +// ChangeStoragePolicy changes the storage policy of the image chosen +func (i Image) ChangeStoragePolicy(ctx context.Context, req ChangeStoragePolicyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/image/change_storage_policy" + + res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudapi/image/create.go b/pkg/cloudapi/image/create.go index f3a94a5..9d21bc8 100644 --- a/pkg/cloudapi/image/create.go +++ b/pkg/cloudapi/image/create.go @@ -35,6 +35,10 @@ type CreateRequest struct { // Required: true AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` + // ID of the chosen storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Select a network interface naming pattern for your Linux machine. eth - onboard, ens - pci slot naming // Should be: // - eth @@ -69,11 +73,6 @@ type CreateRequest struct { // Pool for image create // Required: false Pool string `url:"poolName,omitempty" json:"poolName,omitempty"` - - // List of types of compute suitable for image - // Example: [ "KVM_X86" ] - // Required: true - Drivers []string `url:"drivers" json:"drivers" validate:"min=1,max=2,imageDrivers"` } type asyncWrapperCreateRequest struct { diff --git a/pkg/cloudapi/image/create_virtual.go b/pkg/cloudapi/image/create_virtual.go index 1f56441..629130d 100644 --- a/pkg/cloudapi/image/create_virtual.go +++ b/pkg/cloudapi/image/create_virtual.go @@ -17,6 +17,11 @@ type CreateVirtualRequest struct { // ID of real image to link this virtual image to upon creation // Required: true TargetID uint64 `url:"targetId" json:"targetId" validate:"required"` + + // AccountID to make the virtual image exclusive + // Required: false + // Default: 0 + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` } // CreateVirtual creates virtual image diff --git a/pkg/cloudapi/image/models.go b/pkg/cloudapi/image/models.go index fe455e2..c4150ca 100644 --- a/pkg/cloudapi/image/models.go +++ b/pkg/cloudapi/image/models.go @@ -191,6 +191,9 @@ type RecordImage struct { // Status Status string `json:"status"` + // Storage policy ID + StoragePolicyID uint64 `json:"storage_policy_id"` + // Tech status TechStatus string `json:"techStatus"` diff --git a/pkg/cloudapi/k8ci/list.go b/pkg/cloudapi/k8ci/list.go index dc16d57..c875096 100644 --- a/pkg/cloudapi/k8ci/list.go +++ b/pkg/cloudapi/k8ci/list.go @@ -22,14 +22,6 @@ type ListRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` - // Find by worker driver - // Required: false - WorkerDriver string `url:"workerDriver,omitempty" json:"workerDriver,omitempty"` - - // Find by master driver - // Required: false - MasterDriver string `url:"masterDriver,omitempty" json:"masterDriver,omitempty"` - // Find by network plugin // Required: false NetworkPlugins string `url:"netPlugins,omitempty" json:"netPlugins,omitempty"` diff --git a/pkg/cloudapi/k8ci/list_deleted.go b/pkg/cloudapi/k8ci/list_deleted.go index 3fdb485..1561372 100644 --- a/pkg/cloudapi/k8ci/list_deleted.go +++ b/pkg/cloudapi/k8ci/list_deleted.go @@ -18,14 +18,6 @@ type ListDeletedRequest struct { // Required: false Name string `url:"name,omitempty" json:"name,omitempty"` - // Find by worker driver - // Required: false - WorkerDriver string `url:"workerDriver,omitempty" json:"workerDriver,omitempty"` - - // Find by master driver - // Required: false - MasterDriver string `url:"masterDriver,omitempty" json:"masterDriver,omitempty"` - // Find by network plugin // Required: false NetworkPlugins string `url:"netPlugins,omitempty" json:"netPlugins,omitempty"` diff --git a/pkg/cloudapi/k8s/create.go b/pkg/cloudapi/k8s/create.go index a98ba8b..4e3f01f 100644 --- a/pkg/cloudapi/k8s/create.go +++ b/pkg/cloudapi/k8s/create.go @@ -31,6 +31,10 @@ type CreateRequest struct { // Required: true NetworkPlugin string `url:"networkPlugin" json:"networkPlugin" validate:"required,networkPlugin"` + // ID of the chosen storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // ID of SEP to create boot disks for master nodes. Uses images SEP ID if not set // Required: false MasterSEPID uint64 `url:"masterSepId,omitempty" json:"masterSepId,omitempty"` diff --git a/pkg/cloudapi/k8s/list.go b/pkg/cloudapi/k8s/list.go index 9afe205..904f9d4 100644 --- a/pkg/cloudapi/k8s/list.go +++ b/pkg/cloudapi/k8s/list.go @@ -46,6 +46,11 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Sort by one of supported fields, format +|-(field) // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` diff --git a/pkg/cloudapi/k8s/workers_group_add.go b/pkg/cloudapi/k8s/workers_group_add.go index 79f6245..31be135 100644 --- a/pkg/cloudapi/k8s/workers_group_add.go +++ b/pkg/cloudapi/k8s/workers_group_add.go @@ -17,6 +17,10 @@ type WorkersGroupAddRequest struct { // Required: true Name string `url:"name" json:"name" validate:"required"` + // ID of the chosen storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // ID of SEP to create boot disks for default worker nodes group. Uses images SEP ID if not set // Required: false WorkerSEPID uint64 `url:"workerSepId,omitempty" json:"workerSepId,omitempty"` diff --git a/pkg/cloudapi/kvmx86/create.go b/pkg/cloudapi/kvmx86/create.go index d2640d5..48c7c2b 100644 --- a/pkg/cloudapi/kvmx86/create.go +++ b/pkg/cloudapi/kvmx86/create.go @@ -42,6 +42,18 @@ type Interface struct { // SDN interface id // Required: false SDNInterfaceID string `url:"sdn_interface_id,omitempty" json:"sdn_interface_id,omitempty"` + + // List of security group IDs to assign to this interface + // Required: false + SecGroups []uint64 `url:"security_groups,omitempty" json:"security_groups,omitempty"` + + // Flag indicating whether security groups are enabled for this interface + // Required: false + EnableSecGroups bool `url:"enable_secgroups,omitempty" json:"enable_secgroups,omitempty"` + + // Flag indicating whether this interface is enabled (only for VINS, EXTNET, DPDK, SDN, TRUNK) + // Required: false + Enabled interface{} `url:"enabled,omitempty" json:"enabled,omitempty" validate:"omitempty,isBool"` } // DataDisk detailed struct for DataDisks field in CreateRequest and CreateBlankRequest @@ -54,6 +66,10 @@ type DataDisk struct { // Required: true Size uint64 `url:"size" json:"size" validate:"required"` + // Storage policy id of disk. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Storage endpoint provider ID // By default the same with boot disk // Required: false @@ -92,6 +108,10 @@ type CreateRequest struct { // Required: true RAM uint64 `url:"ram" json:"ram" validate:"required"` + // Storage policy id of сompute. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // If True, the imageId, bootDisk, sepId, pool parameters are ignored and the compute is created without a boot disk in the stopped state // Required: false WithoutBootDisk bool `url:"withoutBootDisk" json:"withoutBootDisk"` @@ -150,10 +170,6 @@ type CreateRequest struct { // Required: false CustomFields string `url:"customFields,omitempty" json:"customFields,omitempty"` - // Type of compute Stateful (KVM_X86) - // Required: false - Driver string `url:"driver,omitempty" json:"driver,omitempty" validate:"omitempty,computeDriver"` - // Rule for VM placement with NUMA affinity. // Possible values - none (placement without NUMA affinity), // strict (strictly with NUMA affinity, if not possible - do not start VM), diff --git a/pkg/cloudapi/kvmx86/create_blank.go b/pkg/cloudapi/kvmx86/create_blank.go index ca51757..44f3898 100644 --- a/pkg/cloudapi/kvmx86/create_blank.go +++ b/pkg/cloudapi/kvmx86/create_blank.go @@ -28,6 +28,10 @@ type CreateBlankRequest struct { // Required: true RAM uint64 `url:"ram" json:"ram" validate:"required"` + // Storage policy id of compute. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // If True, the imageId, bootDisk, sepId, pool parameters are ignored and the compute is created without a boot disk in the stopped state // Required: false WithoutBootDisk bool `url:"withoutBootDisk" json:"withoutBootDisk"` @@ -57,10 +61,6 @@ type CreateBlankRequest struct { // Required: false Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"` - // Type of compute Stateful (KVM_X86) - // Required: false - Driver string `url:"driver,omitempty" json:"driver,omitempty" validate:"omitempty,computeDriver"` - // Type of the emulated system, Q35 or i440fx // Required: false Chipset string `url:"chipset,omitempty" json:"chipset,omitempty" validate:"omitempty,chipset"` diff --git a/pkg/cloudapi/lb/list.go b/pkg/cloudapi/lb/list.go index e9c8432..17fbdc0 100644 --- a/pkg/cloudapi/lb/list.go +++ b/pkg/cloudapi/lb/list.go @@ -50,6 +50,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudapi/rg/create.go b/pkg/cloudapi/rg/create.go index dad9add..b76fe7d 100644 --- a/pkg/cloudapi/rg/create.go +++ b/pkg/cloudapi/rg/create.go @@ -5,6 +5,7 @@ import ( "net/http" "strconv" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) @@ -22,6 +23,10 @@ type CreateRequest struct { // Required: true Name string `url:"name" json:"name" validate:"required,min=2"` + // Storage policies + // Required: false + StoragePolicies []StoragePolicy `url:"storage_policies" json:"storage_policies"` + // Max size of memory in MB // Required: false MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"` @@ -77,6 +82,11 @@ type CreateRequest struct { SDNAccessGroupID string `url:"sdn_access_group_id,omitempty" json:"sdn_access_group_id,omitempty"` } +type StoragePolicy struct { + ID int64 `url:"id" json:"id"` + Limit int `url:"limit" json:"limit"` +} + // Create creates resource group func (r RG) Create(ctx context.Context, req CreateRequest) (uint64, error) { err := validators.ValidateRequest(req) @@ -86,7 +96,7 @@ func (r RG) Create(ctx context.Context, req CreateRequest) (uint64, error) { url := "/cloudapi/rg/create" - res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := r.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) if err != nil { return 0, err } diff --git a/pkg/cloudapi/rg/models.go b/pkg/cloudapi/rg/models.go index a8311cf..ce81b38 100644 --- a/pkg/cloudapi/rg/models.go +++ b/pkg/cloudapi/rg/models.go @@ -134,6 +134,9 @@ type RecordResourceGroup struct { // List of resource types ResTypes []string `json:"resourceTypes"` + // Storage policy ids + StoragePolicyIDs []uint64 `json:"storage_policy_ids"` + // SDN access group id SDNAccessGroupID string `json:"sdn_access_group_id"` @@ -233,6 +236,9 @@ type ItemResourceGroup struct { // SDN access group id SDNAccessGroupID string `json:"sdn_access_group_id"` + // Storage policy ids + StoragePolicyIDs []uint64 `json:"storage_policy_ids"` + // Secret Secret string `json:"secret"` @@ -308,6 +314,9 @@ type ResourceLimits struct { // GPU units GPUUnits float64 `json:"gpu_units"` + + // Storage policies + StoragePolicies []StoragePolicy `json:"storage_policy"` } // Main information about affinity group diff --git a/pkg/cloudapi/rg/update.go b/pkg/cloudapi/rg/update.go index 21448ac..79ab888 100644 --- a/pkg/cloudapi/rg/update.go +++ b/pkg/cloudapi/rg/update.go @@ -5,6 +5,7 @@ import ( "net/http" "strconv" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) @@ -50,6 +51,10 @@ type UpdateRequest struct { // Default: false // Required: false ClearUniqPools bool `url:"clearUniqPools" json:"clearUniqPools"` + + // Storage policies + // Required: false + StoragePolicies []StoragePolicy `url:"-" json:"storage_policies,omitempty"` } // Update updates resource group @@ -61,7 +66,7 @@ func (r RG) Update(ctx context.Context, req UpdateRequest) (bool, error) { url := "/cloudapi/rg/update" - res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := r.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) if err != nil { return false, err } diff --git a/pkg/cloudapi/security_group/create.go b/pkg/cloudapi/security_group/create.go new file mode 100644 index 0000000..1bab28a --- /dev/null +++ b/pkg/cloudapi/security_group/create.go @@ -0,0 +1,46 @@ +package securitygroup + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type CreateRequest struct { + // Account ID that owns security group + // Required: true + AccountID uint64 `url:"account_id" json:"account_id" validate:"required"` + + // Security group name + // Required: true + Name string `url:"name" json:"name" validate:"required"` + + // Security group description + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` +} + +func (sg SecurityGroup) Create(ctx context.Context, req CreateRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/security_group/create" + + res, err := sg.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) + if err != nil { + return 0, err + } + + result, err := strconv.ParseUint(string(res), 10, 64) + if err != nil { + return 0, err + } + + return result, nil + +} diff --git a/pkg/cloudapi/security_group/create_rule.go b/pkg/cloudapi/security_group/create_rule.go new file mode 100644 index 0000000..1d56db4 --- /dev/null +++ b/pkg/cloudapi/security_group/create_rule.go @@ -0,0 +1,63 @@ +package securitygroup + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type CreateRuleRequest struct { + // Security group ID + // Required: true + SecurityGroupID uint64 `url:"security_group_id" json:"security_group_id" validate:"required"` + + // Traffic direction (inbound/outbound) + // Required: true + Direction string `url:"direction" json:"direction" validate:"required,securityGroupDirection"` + + // IP protocol version + // Default: IPv4 + // Required: false + Ethertype string `url:"ethertype,omitempty" json:"ethertype,omitempty" validate:"omitempty,securityGroupEthertype"` + + // Network protocol, available values : icmp, tcp, udp + // Required: false + Protocol string `url:"protocol,omitempty" json:"protocol,omitempty" validate:"omitempty,securityGroupProtocol"` + + // Start port number (for TCP/UDP) + // Required: false + PortRangeMin uint64 `url:"port_range_min,omitempty" json:"port_range_min,omitempty"` + + // End port number (for TCP/UDP) + // Required: false + PortRangeMax uint64 `url:"port_range_max,omitempty" json:"port_range_max,omitempty"` + + // Remote IP prefix in CIDR notation + // Required: false + RemoteIPPrefix string `url:"remote_ip_prefix,omitempty" json:"remote_ip_prefix,omitempty"` +} + +func (sg SecurityGroup) CreateRule(ctx context.Context, req CreateRuleRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/security_group/create_rule" + + res, err := sg.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) + if err != nil { + return 0, err + } + + result, err := strconv.ParseUint(string(res), 10, 64) + if err != nil { + return 0, err + } + + return result, nil + +} diff --git a/pkg/cloudapi/security_group/delete.go b/pkg/cloudapi/security_group/delete.go new file mode 100644 index 0000000..cd6eea55 --- /dev/null +++ b/pkg/cloudapi/security_group/delete.go @@ -0,0 +1,36 @@ +package securitygroup + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type DeleteRequest struct { + // Security group ID + // Required: true + SecurityGroupID uint64 `url:"security_group_id" json:"security_group_id" validate:"required"` +} + +func (sg SecurityGroup) Delete(ctx context.Context, req DeleteRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/security_group/delete" + + res, err := sg.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudapi/security_group/delete_rule.go b/pkg/cloudapi/security_group/delete_rule.go new file mode 100644 index 0000000..4491900 --- /dev/null +++ b/pkg/cloudapi/security_group/delete_rule.go @@ -0,0 +1,40 @@ +package securitygroup + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type DeleteRuleRequest struct { + // Security group ID + // Required: true + SecurityGroupID uint64 `url:"security_group_id" json:"security_group_id" validate:"required"` + + // Rule ID + // Required: true + RuleID uint64 `url:"rule_id" json:"rule_id" validate:"required"` +} + +func (sg SecurityGroup) DeleteRule(ctx context.Context, req DeleteRuleRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/security_group/delete_rule" + + res, err := sg.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudapi/security_group/filter.go b/pkg/cloudapi/security_group/filter.go new file mode 100644 index 0000000..e95ee28 --- /dev/null +++ b/pkg/cloudapi/security_group/filter.go @@ -0,0 +1,80 @@ +package securitygroup + +// FilterByID returns ListSecurityGroups with specified ID. +func (lsg ListSecurityGroups) FilterByID(id uint64) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.ID == id + } + + return lsg.FilterFunc(predicate) +} + +// FilterByID returns ListSecurityGroups with specified Name. +func (lsg ListSecurityGroups) FilterByName(name string) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.Name == name + } + + return lsg.FilterFunc(predicate) +} + +// FilterByCreatedBy returns ListSecurityGroups with specified CreatedBy. +func (lsg ListSecurityGroups) FilterByCreatedBy(createdBy string) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.CreatedBy == createdBy + } + + return lsg.FilterFunc(predicate) +} + +// FilterByDescription returns ListSecurityGroups with specified Description. +func (lsg ListSecurityGroups) FilterByDescription(description string) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.Description == description + } + + return lsg.FilterFunc(predicate) +} + +// FilterByUpdatedBy returns ListSecurityGroups with specified UpdatedBy. +func (lsg ListSecurityGroups) FilterByUpdatedBy(updatedBy string) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.UpdatedBy == updatedBy + } + + return lsg.FilterFunc(predicate) +} + +// FilterByAccountID returns ListSecurityGroups with specified AccountID. +func (lsg ListSecurityGroups) FilterByAccountID(accountID uint64) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.AccountID == accountID + } + + return lsg.FilterFunc(predicate) +} + +// FilterFunc allows filtering ListSecurityGroups based on a user-specified predicate. +func (lsg ListSecurityGroups) FilterFunc(predicate func(ItemSecurityGroup) bool) ListSecurityGroups { + var result ListSecurityGroups + + for _, item := range lsg.Data { + if predicate(item) { + result.Data = append(result.Data, item) + } + } + + result.EntryCount = uint64(len(result.Data)) + + return result +} + +// FindOne returns first found ItemSecurityGroup +// If none was found, returns an empty struct. +func (lsg ListSecurityGroups) FindOne() ItemSecurityGroup { + if len(lsg.Data) == 0 { + return ItemSecurityGroup{} + } + + return lsg.Data[0] +} diff --git a/pkg/cloudapi/security_group/filter_test.go b/pkg/cloudapi/security_group/filter_test.go new file mode 100644 index 0000000..821f016 --- /dev/null +++ b/pkg/cloudapi/security_group/filter_test.go @@ -0,0 +1,87 @@ +package securitygroup + +import "testing" + +var securityGroups = ListSecurityGroups{ + Data: []ItemSecurityGroup{ + { + ID: 1, + AccountID: 1, + Name: "sg1", + Description: "some desc", + CreatedBy: "user", + }, + { + ID: 3, + AccountID: 3, + Name: "sg3", + Description: "some desc", + CreatedBy: "anotheruser", + }, + { + ID: 5, + AccountID: 3, + Name: "sg5", + Description: "some other desc", + CreatedBy: "anotheruser", + UpdatedBy: "user", + }, + }, + EntryCount: 3, +} + +func TestFilterByID(t *testing.T) { + actual := securityGroups.FilterByID(1).FindOne() + if actual.ID != 1 { + t.Fatal("expected ID 1, found: ", actual.ID) + } +} + +func TestFilterByName(t *testing.T) { + actual := securityGroups.FilterByName("sg3").FindOne() + if actual.Name != "sg3" { + t.Fatal("expected Name sg3, found: ", actual.Name) + } +} + +func TestFilterByDescription(t *testing.T) { + actual := securityGroups.FilterByDescription("some desc") + + if len(actual.Data) != 2 { + t.Fatal("expected 2 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if item.Description != "some desc" { + t.Fatal("expected Description 'some desc', found: ", item.Description) + } + } +} + +func TestFilterByAccountID(t *testing.T) { + actual := securityGroups.FilterByAccountID(1).FindOne() + if actual.AccountID != 1 { + t.Fatal("expected AccountID 1, found: ", actual.AccountID) + } +} + +func TestFilterByCreatedBy(t *testing.T) { + actual := securityGroups.FilterByCreatedBy("anotheruser") + + if len(actual.Data) != 2 { + t.Fatal("expected 2 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if item.CreatedBy != "anotheruser" { + t.Fatal("expected CreatedBy 'anotheruser', found: ", item.CreatedBy) + } + } +} + +func TestFilterByUpdatedBy(t *testing.T) { + actual := securityGroups.FilterByUpdatedBy("user").FindOne() + if actual.UpdatedBy != "user" { + t.Fatal("expected UpdatedBy 'user', found: ", actual.UpdatedBy) + } +} diff --git a/pkg/cloudapi/security_group/get.go b/pkg/cloudapi/security_group/get.go new file mode 100644 index 0000000..318dd6b --- /dev/null +++ b/pkg/cloudapi/security_group/get.go @@ -0,0 +1,43 @@ +package securitygroup + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type GetRequest struct { + // ID of security group + // Required: true + SecurityGroupID uint64 `url:"security_group_id" json:"security_group_id" validate:"required"` +} + +func (sg SecurityGroup) Get(ctx context.Context, req GetRequest) (*RecordSecurityGroup, error) { + res, err := sg.GetRaw(ctx, req) + if err != nil { + return nil, err + } + + info := RecordSecurityGroup{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +func (sg SecurityGroup) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/security_group/get" + + res, err := sg.client.DecortApiCall(ctx, http.MethodGet, url, req) + return res, err +} diff --git a/pkg/cloudapi/security_group/list.go b/pkg/cloudapi/security_group/list.go new file mode 100644 index 0000000..0e5fb37 --- /dev/null +++ b/pkg/cloudapi/security_group/list.go @@ -0,0 +1,86 @@ +package securitygroup + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type ListRequest struct { + // Search by security group id + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Search by account id + // Required: false + AccountID uint64 `url:"account_id,omitempty" json:"account_id,omitempty"` + + // Search by security group name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Search by security group description + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` + + // Search by created after time (unix timestamp) + // Required: false + CreatedMin uint64 `url:"created_min,omitempty" json:"created_min,omitempty"` + + // Search by created before time (unix timestamp) + // Required: false + CreatedMax uint64 `url:"created_max,omitempty" json:"created_max,omitempty"` + + // Search by updated after time (unix timestamp) + // Required: false + UpdatedMin uint64 `url:"updated_min,omitempty" json:"updated_min,omitempty"` + + // Search by updated before time (unix timestamp) + // Required: false + UpdatedMax uint64 `url:"updated_max,omitempty" json:"updated_max,omitempty"` + + // Sort by one of supported fields, format ± + // Required: false + SortBy string `url:"sort_by,omitempty" json:"sort_by,omitempty"` + + // Page number + // Required: false + Page uint64 `url:"page,omitempty" json:"page,omitempty"` + + // Page size + // Required: false + Size uint64 `url:"size,omitempty" json:"size,omitempty"` +} + +// List gets list of security groups as a ListSecurityGroups struct +func (sg SecurityGroup) List(ctx context.Context, req ListRequest) (*ListSecurityGroups, error) { + + res, err := sg.ListRaw(ctx, req) + if err != nil { + return nil, err + } + + list := ListSecurityGroups{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} + +// ListRaw gets list of security groups as an array of bytes +func (sg SecurityGroup) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/security_group/list" + + res, err := sg.client.DecortApiCall(ctx, http.MethodGet, url, req) + return res, err +} diff --git a/pkg/cloudapi/security_group/models.go b/pkg/cloudapi/security_group/models.go new file mode 100644 index 0000000..440e813 --- /dev/null +++ b/pkg/cloudapi/security_group/models.go @@ -0,0 +1,43 @@ +package securitygroup + +type ListSecurityGroups struct { + Data []ItemSecurityGroup `json:"data"` + EntryCount uint64 `json:"entryCount"` +} + +type ItemSecurityGroup struct { + ID uint64 `json:"id"` + AccountID uint64 `json:"account_id"` + Name string `json:"name"` + Description string `json:"description"` + Rules Rules `json:"rules"` + CreatedAt uint64 `json:"created_at"` + UpdatedAt uint64 `json:"updated_at"` + CreatedBy string `json:"created_by"` + UpdatedBy string `json:"updated_by"` +} + +type RecordSecurityGroup struct { + ID uint64 `json:"id"` + AccountID uint64 `json:"account_id"` + Name string `json:"name"` + Description string `json:"description"` + Rules Rules `json:"rules"` + CreatedAt uint64 `json:"created_at"` + UpdatedAt uint64 `json:"updated_at"` + CreatedBy string `json:"created_by"` + UpdatedBy string `json:"updated_by"` +} + +type Rules []Rule + +type Rule struct { + ID uint64 `json:"id"` + Direction string `json:"direction"` + Ethertype string `json:"ethertype"` + Protocol string `json:"protocol"` + PortRangeMin uint64 `json:"port_range_min"` + PortRangeMax uint64 `json:"port_range_max"` + RemoteIPPrefix string `json:"remote_ip_prefix"` + RemoteGroupID uint64 `json:"remote_group_id"` +} diff --git a/pkg/cloudapi/security_group/security_group.go b/pkg/cloudapi/security_group/security_group.go new file mode 100644 index 0000000..35c6a3b --- /dev/null +++ b/pkg/cloudapi/security_group/security_group.go @@ -0,0 +1,15 @@ +package securitygroup + +import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" + +// Structure for creating request to storage policy +type SecurityGroup struct { + client interfaces.Caller +} + +// Builder for stack endpoint +func New(client interfaces.Caller) *SecurityGroup { + return &SecurityGroup{ + client: client, + } +} diff --git a/pkg/cloudapi/security_group/sorting.go b/pkg/cloudapi/security_group/sorting.go new file mode 100644 index 0000000..5a54b53 --- /dev/null +++ b/pkg/cloudapi/security_group/sorting.go @@ -0,0 +1,41 @@ +package securitygroup + +import "sort" + +// SortByCreatedAt sorts ListSecurityGroups by the CreatedAt field in ascending order. +// +// If inverse param is set to true, the order is reversed. +func (lsg ListSecurityGroups) SortByCreatedAt(inverse bool) ListSecurityGroups { + if len(lsg.Data) < 2 { + return lsg + } + + sort.Slice(lsg.Data, func(i, j int) bool { + if inverse { + return lsg.Data[i].CreatedAt > lsg.Data[j].CreatedAt + } + + return lsg.Data[i].CreatedAt < lsg.Data[j].CreatedAt + }) + + return lsg +} + +// SortByUpdatedAt sorts ListSecurityGroups by the UpdatedAt field in ascending order. +// +// If inverse param is set to true, the order is reversed. +func (lsg ListSecurityGroups) SortByUpdatedAt(inverse bool) ListSecurityGroups { + if len(lsg.Data) < 2 { + return lsg + } + + sort.Slice(lsg.Data, func(i, j int) bool { + if inverse { + return lsg.Data[i].UpdatedAt > lsg.Data[j].UpdatedAt + } + + return lsg.Data[i].UpdatedAt < lsg.Data[j].UpdatedAt + }) + + return lsg +} diff --git a/pkg/cloudapi/security_group/update.go b/pkg/cloudapi/security_group/update.go new file mode 100644 index 0000000..c1e373f --- /dev/null +++ b/pkg/cloudapi/security_group/update.go @@ -0,0 +1,51 @@ +package securitygroup + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type UpdateRequest struct { + // Security group ID + // Required: true + SecurityGroupID uint64 `url:"security_group_id" json:"security_group_id" validate:"required"` + + // New security group name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // New security group description + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` +} + +func (sg SecurityGroup) Update(ctx context.Context, req UpdateRequest) (*RecordSecurityGroup, error) { + res, err := sg.UpdateRaw(ctx, req) + if err != nil { + return nil, err + } + + info := RecordSecurityGroup{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +func (sg SecurityGroup) UpdateRaw(ctx context.Context, req UpdateRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/security_group/update" + + res, err := sg.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudapi/securitygroup.go b/pkg/cloudapi/securitygroup.go new file mode 100644 index 0000000..0ae85c6 --- /dev/null +++ b/pkg/cloudapi/securitygroup.go @@ -0,0 +1,10 @@ +package cloudapi + +import ( + securitygroup "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/security_group" +) + +// Accessing the Security Group method group +func (ca *CloudAPI) SecurityGroup() *securitygroup.SecurityGroup { + return securitygroup.New(ca.client) +} diff --git a/pkg/cloudapi/storage_policy/get.go b/pkg/cloudapi/storage_policy/get.go new file mode 100644 index 0000000..5619ed9 --- /dev/null +++ b/pkg/cloudapi/storage_policy/get.go @@ -0,0 +1,43 @@ +package storagepolicy + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type GetRequest struct { + // ID of storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +func (sp StoragePolicy) Get(ctx context.Context, req GetRequest) (*InfoStoragePolicy, error) { + res, err := sp.GetRaw(ctx, req) + if err != nil { + return nil, err + } + + info := InfoStoragePolicy{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +func (sp StoragePolicy) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/storage_policy/get" + + res, err := sp.client.DecortApiCall(ctx, http.MethodGet, url, req) + return res, err +} diff --git a/pkg/cloudapi/storage_policy/list.go b/pkg/cloudapi/storage_policy/list.go new file mode 100644 index 0000000..330afb5 --- /dev/null +++ b/pkg/cloudapi/storage_policy/list.go @@ -0,0 +1,90 @@ +package storagepolicy + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type ListRequest struct { + // ID of account ID + // Required: true + AccountID uint64 `url:"account_id" json:"account_id" validate:"required"` + + // Page number + // Required: false + Page uint64 `url:"page,omitempty" json:"page,omitempty"` + + // Page size + // Required: false + Size uint64 `url:"size,omitempty" json:"size,omitempty"` + + // Search by storage policy ID + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Search by storage policy name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Search by storage policy status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Search by storage policy desc + // Required: false + Desc string `url:"desc,omitempty" json:"desc,omitempty"` + + // Search by storage policy iops limit + // Required: false + LimitIOPS uint64 `url:"limit_iops,omitempty" json:"limit_iops,omitempty"` + + // Sort by one of supported fields, format ± + // Required: false + SortBy string `url:"sort_by,omitempty" json:"sort_by,omitempty"` + + // Search by resgroup id + // Required: false + ResgroupID uint64 `url:"resgroup_id,omitempty" json:"resgroup_id,omitempty"` + + // Search by sep id + // Required: false + SepID uint64 `url:"sep_id,omitempty" json:"sep_id,omitempty"` + + // Search by pool name + // Required: false + PoolName string `url:"pool_name,omitempty" json:"pool_name,omitempty"` +} + +// List gets list of storage policies as a ListStoragePolicies struct +func (sp StoragePolicy) List(ctx context.Context, req ListRequest) (*ListStoragePolicies, error) { + + res, err := sp.ListRaw(ctx, req) + if err != nil { + return nil, err + } + + list := ListStoragePolicies{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} + +// ListRaw gets list of storage policies as an array of bytes +func (sp StoragePolicy) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/storage_policy/list" + + res, err := sp.client.DecortApiCall(ctx, http.MethodGet, url, req) + return res, err +} diff --git a/pkg/cloudapi/storage_policy/models.go b/pkg/cloudapi/storage_policy/models.go new file mode 100644 index 0000000..82d45b8 --- /dev/null +++ b/pkg/cloudapi/storage_policy/models.go @@ -0,0 +1,40 @@ +package storagepolicy + +type ListStoragePolicies struct { + Data []ItemStoragePolicy `json:"data"` + EntryCount uint64 `json:"entryCount"` +} + +type ItemStoragePolicy struct { + ID uint64 `json:"id"` + GUID uint64 `json:"guid"` + Name string `json:"name"` + Description string `json:"description"` + AccessSepPools ListAccessSepPools `json:"access_seps_pools"` + Status string `json:"status"` + LimitIOPS uint64 `json:"limit_iops"` + Usage Usage `json:"usage"` +} + +type InfoStoragePolicy struct { + ID uint64 `json:"id"` + GUID uint64 `json:"guid"` + Name string `json:"name"` + Description string `json:"description"` + AccessSepPools ListAccessSepPools `json:"access_seps_pools"` + Status string `json:"status"` + LimitIOPS uint64 `json:"limit_iops"` + Usage Usage `json:"usage"` +} + +type ListAccessSepPools []AccessSepPool + +type AccessSepPool struct { + SepID uint64 `json:"sep_id"` + PoolNames []string `json:"pool_names"` +} + +type Usage struct { + Accounts []uint64 `json:"accounts"` + Resgroups []uint64 `json:"resgroups"` +} diff --git a/pkg/cloudapi/storage_policy/storage_policy.go b/pkg/cloudapi/storage_policy/storage_policy.go new file mode 100644 index 0000000..42b42a2 --- /dev/null +++ b/pkg/cloudapi/storage_policy/storage_policy.go @@ -0,0 +1,15 @@ +package storagepolicy + +import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" + +// Structure for creating request to storage policy +type StoragePolicy struct { + client interfaces.Caller +} + +// Builder for stack endpoint +func New(client interfaces.Caller) *StoragePolicy { + return &StoragePolicy{ + client: client, + } +} diff --git a/pkg/cloudapi/storagepolicy.go b/pkg/cloudapi/storagepolicy.go new file mode 100644 index 0000000..9f8b288 --- /dev/null +++ b/pkg/cloudapi/storagepolicy.go @@ -0,0 +1,10 @@ +package cloudapi + +import ( + storagepolicy "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/storage_policy" +) + +// Accessing the Storage Policy method group +func (ca *CloudAPI) StoragePolicy() *storagepolicy.StoragePolicy { + return storagepolicy.New(ca.client) +} diff --git a/pkg/cloudapi/trunk/list.go b/pkg/cloudapi/trunk/list.go index 6039949..eeca231 100644 --- a/pkg/cloudapi/trunk/list.go +++ b/pkg/cloudapi/trunk/list.go @@ -27,6 +27,9 @@ type ListRequest struct { // Page size Size uint64 `url:"size,omitempty" json:"size,omitempty"` + + // Status + Status string `url:"status,omitempty" json:"status,omitempty"` } // List gets list of all trunks as a ListTrunks struct diff --git a/pkg/cloudapi/vins/list.go b/pkg/cloudapi/vins/list.go index 631c40a..0879cdc 100644 --- a/pkg/cloudapi/vins/list.go +++ b/pkg/cloudapi/vins/list.go @@ -46,6 +46,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudapi/vins/models.go b/pkg/cloudapi/vins/models.go index 6dfef13..664fc8c 100644 --- a/pkg/cloudapi/vins/models.go +++ b/pkg/cloudapi/vins/models.go @@ -673,6 +673,9 @@ type RecordVINS struct { // Description Description string `json:"desc"` + // Enable Security Groups + EnableSecGroups bool `json:"enable_secgroups"` + // Grid ID GID uint64 `json:"gid"` diff --git a/pkg/cloudapi/zone/models.go b/pkg/cloudapi/zone/models.go index b2340ca..110f9f9 100644 --- a/pkg/cloudapi/zone/models.go +++ b/pkg/cloudapi/zone/models.go @@ -22,12 +22,30 @@ type RecordZone struct { // Name Name string `json:"name"` + // List of associated account IDs + AccountIDs []uint64 `json:"accountIds"` + + // List of associated bservice IDs + BserviceIDs []uint64 `json:"bserviceIds"` + + // List of associated compute IDs + ComputeIDs []uint64 `json:"computeIds"` + // Description Description string `json:"description"` // Deletable flag Deletable bool `json:"deletable"` + // List of associated ExtNet IDs + ExtnetIDs []uint64 `json:"extnetIds"` + + // List of associated K8s IDs + K8SIDs []uint64 `json:"k8sIds"` + + // List of associated LB IDs + LBIDs []uint64 `json:"lbIds"` + // Status Status string `json:"status"` @@ -39,4 +57,7 @@ type RecordZone struct { // List of associated Node IDs NodeIDs []uint64 `json:"nodeIds"` + + // List of associated VINS IDs + VinsIDs []uint64 `json:"vinsIds"` } diff --git a/pkg/cloudbroker/account/add_storage_policy.go b/pkg/cloudbroker/account/add_storage_policy.go new file mode 100644 index 0000000..62a6100 --- /dev/null +++ b/pkg/cloudbroker/account/add_storage_policy.go @@ -0,0 +1,46 @@ +package account + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// AddStoragePolicyRequest struct for adding storage policy to the account +type AddStoragePolicyRequest struct { + // ID of account to add to + // Required: true + AccountID uint64 `url:"account_id" json:"account_id" validate:"required"` + + // ID of the storage policy to which to connect account + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + + // Limit storage resources GB. Or -1 unlimit + // Required: false + Limit int `url:"limit,omitempty" json:"limit,omitempty"` +} + +// AddStoragePolicy add storage policy to the account. +func (a Account) AddStoragePolicy(ctx context.Context, req AddStoragePolicyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/account/add_storage_policy" + + res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/account/create.go b/pkg/cloudbroker/account/create.go index 087211b..fee5f2e 100644 --- a/pkg/cloudbroker/account/create.go +++ b/pkg/cloudbroker/account/create.go @@ -5,6 +5,7 @@ import ( "net/http" "strconv" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) @@ -26,6 +27,10 @@ type CreateRequest struct { // Required: false EmailAddress string `url:"emailaddress,omitempty" json:"emailaddress,omitempty" validate:"omitempty,email"` + // Storage policies + // Required: false + StoragePolicies []StoragePolicy `url:"-" json:"storage_policies" validate:"required"` + // Max size of memory in MB // Required: false MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"` @@ -73,6 +78,11 @@ type CreateRequest struct { ZoneIDs []uint64 `url:"zoneIds,omitempty" json:"zoneIds,omitempty"` } +type StoragePolicy struct { + ID int64 `url:"id" json:"id"` + Limit int `url:"limit" json:"limit"` +} + // Create creates account // Setting a cloud unit maximum to -1 or empty will not put any restrictions on the resource func (a Account) Create(ctx context.Context, req CreateRequest) (uint64, error) { @@ -83,7 +93,7 @@ func (a Account) Create(ctx context.Context, req CreateRequest) (uint64, error) url := "/cloudbroker/account/create" - res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := a.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) if err != nil { return 0, err } diff --git a/pkg/cloudbroker/account/del_storage_policy.go b/pkg/cloudbroker/account/del_storage_policy.go new file mode 100644 index 0000000..e5e7f3d --- /dev/null +++ b/pkg/cloudbroker/account/del_storage_policy.go @@ -0,0 +1,42 @@ +package account + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DelStoragePolicyRequest struct for deleting storage policy to the account +type DelStoragePolicyRequest struct { + // ID of account + // Required: true + AccountID uint64 `url:"account_id" json:"account_id" validate:"required"` + + // ID of the storage policy to which to disconnect account + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +// DelStoragePolicy delete storage policy to the account. +func (a Account) DelStoragePolicy(ctx context.Context, req DelStoragePolicyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/account/del_storage_policy" + + res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/account/list.go b/pkg/cloudbroker/account/list.go index 13548f8..6e33576 100644 --- a/pkg/cloudbroker/account/list.go +++ b/pkg/cloudbroker/account/list.go @@ -30,6 +30,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudbroker/account/models.go b/pkg/cloudbroker/account/models.go index e0a545a..35625b7 100644 --- a/pkg/cloudbroker/account/models.go +++ b/pkg/cloudbroker/account/models.go @@ -133,6 +133,9 @@ type ResourceLimits struct { // GPUUnits GPUUnits float64 `json:"gpu_units"` + + // Storage policies + StoragePolicies []StoragePolicy `json:"storage_policy"` } // Main information about account @@ -200,6 +203,9 @@ type InfoAccount struct { // Status Status string `json:"status"` + // Storage policy ids + StoragePolicyIDs []uint64 `json:"storage_policy_ids"` + // UniqPools UniqPools []string `json:"uniqPools"` @@ -234,7 +240,7 @@ type RecordAccount struct { ACL []ACLWithEmails `json:"acl"` // Zones IDs - ZoneIDs []ZoneID + ZoneIDs []ZoneID `json:"zoneIds"` } // More information about account @@ -249,7 +255,7 @@ type ItemAccount struct { InfoAccount // Zones - ZoneIDs []uint64 + ZoneIDs []uint64 `json:"zoneIds"` } // List of accounts diff --git a/pkg/cloudbroker/account/update.go b/pkg/cloudbroker/account/update.go index 7c4fe5d..afe8843 100644 --- a/pkg/cloudbroker/account/update.go +++ b/pkg/cloudbroker/account/update.go @@ -5,6 +5,7 @@ import ( "net/http" "strconv" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) @@ -46,6 +47,10 @@ type UpdateRequest struct { // Required: false SendAccessEmails bool `url:"sendAccessEmails" json:"sendAccessEmails"` + // Storage policies + // Required: false + StoragePolicies []StoragePolicy `url:"-" json:"storage_policies,omitempty"` + // Limit (positive) or disable (0) GPU resources // Required: false GPUUnits int64 `url:"gpu_units,omitempty" json:"gpu_units,omitempty"` @@ -74,7 +79,7 @@ func (a Account) Update(ctx context.Context, req UpdateRequest) (bool, error) { url := "/cloudbroker/account/update" - res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := a.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) if err != nil { return false, err } diff --git a/pkg/cloudbroker/audit/models.go b/pkg/cloudbroker/audit/models.go index ef9599b..e498014 100644 --- a/pkg/cloudbroker/audit/models.go +++ b/pkg/cloudbroker/audit/models.go @@ -11,6 +11,9 @@ type ItemAudit struct { // GUID GUID string `json:"guid"` + // Correlation ID + CorrelationID string `json:"correlation_id"` + // Kwargs Kwargs string `json:"kwargs"` @@ -60,6 +63,9 @@ type RecordAudit struct { // Call Call string `json:"call"` + // Correlation ID + CorrelationID string `json:"correlation_id"` + // GUID GUID string `json:"guid"` diff --git a/pkg/cloudbroker/bservice/group_add.go b/pkg/cloudbroker/bservice/group_add.go index 618276e..c3e59c9 100644 --- a/pkg/cloudbroker/bservice/group_add.go +++ b/pkg/cloudbroker/bservice/group_add.go @@ -38,11 +38,9 @@ type GroupAddRequest struct { // Required: true ImageID uint64 `url:"imageId" json:"imageId" validate:"required"` - // Compute driver - // should be one of: - // - KVM_X86 + // Compute driver like a KVM_X86, etc. // Required: true - Driver string `url:"driver" json:"driver" validate:"driver"` + Driver string `url:"driver" json:"driver" validate:"required"` // Storage endpoint provider ID // Required: false @@ -75,6 +73,10 @@ type GroupAddRequest struct { //Chipset "i440fx" or "Q35 //Required: false Chipset string `url:"chipset,omitempty" json:"chipset,omitempty" validate:"chipset"` + + // ID of the chosen storage policy + // Required: false + StoragePolicyID uint64 `url:"storage_policy_id,omitempty" json:"storage_policy_id,omitempty"` } // GetRAM returns RAM field values diff --git a/pkg/cloudbroker/bservice/list.go b/pkg/cloudbroker/bservice/list.go index 9f2ee7a..ff4ace7 100644 --- a/pkg/cloudbroker/bservice/list.go +++ b/pkg/cloudbroker/bservice/list.go @@ -42,6 +42,11 @@ type ListRequest struct { // Required: false AccountName string `url:"accountName,omitempty" json:"accountName,omitempty"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Sort by one of supported fields, format +|-(field) // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` diff --git a/pkg/cloudbroker/compute/audits.go b/pkg/cloudbroker/compute/audits.go index 23943e6..6ee690a 100644 --- a/pkg/cloudbroker/compute/audits.go +++ b/pkg/cloudbroker/compute/audits.go @@ -12,11 +12,47 @@ import ( type AuditsRequest struct { // ID of the compute // Required: true - ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + ComputeID uint64 `url:"compute_id" json:"compute_id" validate:"required"` + + // Find all audits after point in time + // Required: false + TimestampAT uint64 `url:"timestamp_at,omitempty" json:"timestamp_at,omitempty"` + + // Find all audits before point in time + // Required: false + TimestampTO uint64 `url:"timestamp_to,omitempty" json:"timestamp_to,omitempty"` + + // Find by user + // Required: false + User string `url:"user,omitempty" json:"user,omitempty"` + + // Find by api endpoints + // Required: false + Call string `url:"call,omitempty" json:"call,omitempty"` + + // Sort by one of supported fields, format ± + // Required: false + SortBy string `url:"sort_by,omitempty" json:"sort_by,omitempty"` + + // Page number + // Required: false + Page uint64 `url:"page,omitempty" json:"page,omitempty"` + + // Page size + // Required: false + Size uint64 `url:"size,omitempty" json:"size,omitempty"` + + // Find by HTTP min status code + // Required: false + MinStatusCode uint64 `url:"min_status_code,omitempty" json:"min_status_code,omitempty"` + + // Find by HTTP max status code + // Required: false + MaxStatusCode uint64 `url:"max_status_code,omitempty" json:"max_status_code,omitempty"` } // Audits gets audit records for the specified compute object -func (c Compute) Audits(ctx context.Context, req AuditsRequest) (ListDetailedAudits, error) { +func (c Compute) Audits(ctx context.Context, req AuditsRequest) (*ListDetailedAudits, error) { err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) @@ -24,7 +60,7 @@ func (c Compute) Audits(ctx context.Context, req AuditsRequest) (ListDetailedAud url := "/cloudbroker/compute/audits" - res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := c.client.DecortApiCall(ctx, http.MethodGet, url, req) if err != nil { return nil, err } @@ -36,5 +72,5 @@ func (c Compute) Audits(ctx context.Context, req AuditsRequest) (ListDetailedAud return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudbroker/compute/change_secutity_group.go b/pkg/cloudbroker/compute/change_secutity_group.go new file mode 100644 index 0000000..eb494a7 --- /dev/null +++ b/pkg/cloudbroker/compute/change_secutity_group.go @@ -0,0 +1,50 @@ +package compute + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ChangeSecGroupsRequest struct to change security groups for compute +type ChangeSecGroupsRequest struct { + // Identifier compute + // Required: true + ComputeID uint64 `url:"compute_id" json:"compute_id" validate:"required"` + + // Interface name or MAC address + // Required: true + Interface string `url:"interface" json:"interface" validate:"required"` + + // List of security group IDs to assign to this interface + // Required: false + SecGroups []uint64 `url:"security_groups,omitempty" json:"security_groups,omitempty"` + + // Flag indicating whether security groups are enabled for this interface + // Required: false + EnableSecGroups bool `url:"enable_secgroups,omitempty" json:"enable_secgroups,omitempty"` +} + +// ChangeSecGroups changes security groups for compute +func (c Compute) ChangeSecGroups(ctx context.Context, req ChangeSecGroupsRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/compute/change_security_groups" + + res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/compute/create_template_from_blank.go b/pkg/cloudbroker/compute/create_template_from_blank.go index 287f906..c63c4a6 100644 --- a/pkg/cloudbroker/compute/create_template_from_blank.go +++ b/pkg/cloudbroker/compute/create_template_from_blank.go @@ -27,6 +27,10 @@ type CreateTemplateFromBlankRequest struct { // Required: true ImageType string `url:"imagetype" json:"imagetype" validate:"imageType"` + // Storage policy id of compute. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Username for the image // Required: false Username string `url:"username,omitempty" json:"username,omitempty"` diff --git a/pkg/cloudbroker/compute/disk_add.go b/pkg/cloudbroker/compute/disk_add.go index 12a3b8a..4fef0de 100644 --- a/pkg/cloudbroker/compute/disk_add.go +++ b/pkg/cloudbroker/compute/disk_add.go @@ -27,6 +27,10 @@ type DiskAddRequest struct { // Required: false SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"` + // Storage policy id of compute. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Type of the disk // Should be one of: // - D diff --git a/pkg/cloudbroker/compute/list.go b/pkg/cloudbroker/compute/list.go index 427245a..80b0ccd 100644 --- a/pkg/cloudbroker/compute/list.go +++ b/pkg/cloudbroker/compute/list.go @@ -74,6 +74,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudbroker/compute/migrate.go b/pkg/cloudbroker/compute/migrate.go index 264ab89..42e521e 100644 --- a/pkg/cloudbroker/compute/migrate.go +++ b/pkg/cloudbroker/compute/migrate.go @@ -25,7 +25,7 @@ type MigrateRequest struct { Force bool `url:"force,omitempty" json:"force,omitempty"` } -type asyncWrapperMigrateRequest struct { +type AsyncWrapperMigrateRequest struct { MigrateRequest SyncMode bool `url:"sync"` } @@ -39,7 +39,7 @@ func (c Compute) Migrate(ctx context.Context, req MigrateRequest) (bool, error) url := "/cloudbroker/compute/migrate" - syncReq := asyncWrapperMigrateRequest{MigrateRequest: req, SyncMode: true} + syncReq := AsyncWrapperMigrateRequest{MigrateRequest: req, SyncMode: true} res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, syncReq) if err != nil { @@ -63,7 +63,7 @@ func (c Compute) AsyncMigrate(ctx context.Context, req MigrateRequest) (string, url := "/cloudbroker/compute/migrate" - asyncReq := asyncWrapperMigrateRequest{MigrateRequest: req, SyncMode: false} + asyncReq := AsyncWrapperMigrateRequest{MigrateRequest: req, SyncMode: false} res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, asyncReq) if err != nil { diff --git a/pkg/cloudbroker/compute/models.go b/pkg/cloudbroker/compute/models.go index 60a7412..a35f205 100644 --- a/pkg/cloudbroker/compute/models.go +++ b/pkg/cloudbroker/compute/models.go @@ -221,8 +221,14 @@ type ItemDetailedAudit struct { User string `json:"user"` } -// List of detailed audit -type ListDetailedAudits []ItemDetailedAudit +// List Detailed audits +type ListDetailedAudits struct { + // Data + Data []ItemDetailedAudit `json:"data"` + + // Entry count + EntryCount uint64 `json:"entryCount"` +} // Main information about port forward type ItemPFW struct { @@ -475,9 +481,15 @@ type ItemDisk struct { // Status Status string `json:"status"` + // Storage policy id of disk. + StoragePolicyID uint64 `json:"storage_policy_id"` + // Tech status TechStatus string `json:"techStatus"` + // Need to clean before destroy + ToClean bool `json:"to_clean"` + // Type Type string `json:"type"` @@ -525,6 +537,9 @@ type ItemInterface struct { // Enabled Enabled bool `json:"enabled"` + // Enable security groups + EnableSecGroups bool `json:"enable_secgroups"` + // FLIPGroup ID FLIPGroupID uint64 `json:"flipgroupId"` @@ -567,6 +582,9 @@ type ItemInterface struct { // QOS QOS QOS `json:"qos"` + // List of security groups + SecGroups []uint64 `json:"security_groups"` + // SDN interface ID SDNInterfaceID string `json:"sdn_interface_id"` diff --git a/pkg/cloudbroker/compute/net_attach.go b/pkg/cloudbroker/compute/net_attach.go index 7975b14..ae6529e 100644 --- a/pkg/cloudbroker/compute/net_attach.go +++ b/pkg/cloudbroker/compute/net_attach.go @@ -42,12 +42,24 @@ type NetAttachRequest struct { // Used only for EXTNET and DPDK // For DPDK must be 1-9216 // For EXTNET must be 1500-9216 - // Required: false + // Required: false MTU uint64 `url:"mtu,omitempty" json:"mtu,omitempty" validate:"omitempty,mtu"` // Unique identifier of logical port on SDN side // Required: false SDNInterfaceID string `url:"sdn_interface_id,omitempty" json:"sdn_interface_id,omitempty" validate:"omitempty"` + + // List of security group IDs to assign to this interface + // Required: false + SecGroups []uint64 `url:"security_groups,omitempty" json:"security_groups,omitempty"` + + // Flag indicating whether security groups are enabled for this interface + // Required: false + EnableSecGroups bool `url:"enable_secgroups,omitempty" json:"enable_secgroups,omitempty"` + + // Flag indicating whether this interface is enabled (only for VINS, EXTNET, DPDK, SDN, TRUNK) + // Required: false + Enabled interface{} `url:"enabled,omitempty" json:"enabled,omitempty" validate:"omitempty,isBool"` } // NetAttach attaches network to compute and gets info about network diff --git a/pkg/cloudbroker/compute/redeploy.go b/pkg/cloudbroker/compute/redeploy.go index 5a74625..e9e43a7 100644 --- a/pkg/cloudbroker/compute/redeploy.go +++ b/pkg/cloudbroker/compute/redeploy.go @@ -18,6 +18,10 @@ type RedeployRequest struct { // Required: false ImageID uint64 `url:"imageId,omitempty" json:"imageId,omitempty"` + // Storage policy id of compute. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // New size for the boot disk in GB, if boot disk size change is required // Required: false DiskSize uint64 `url:"diskSize,omitempty" json:"diskSize,omitempty"` diff --git a/pkg/cloudbroker/disks/change_disk_storage_policy.go b/pkg/cloudbroker/disks/change_disk_storage_policy.go new file mode 100644 index 0000000..3d96fdf --- /dev/null +++ b/pkg/cloudbroker/disks/change_disk_storage_policy.go @@ -0,0 +1,42 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ChangeDiskStoragePolicyRequest struct to change storage policy for disk +type ChangeDiskStoragePolicyRequest struct { + // ID of the disk + // Required: true + DiskID uint64 `url:"disk_id" json:"disk_id" validate:"required"` + + // ID of the storage policy to which to connect account + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +// ChangeDiskStoragePolicy changes storage policy for disk +func (d Disks) ChangeDiskStoragePolicy(ctx context.Context, req ChangeDiskStoragePolicyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/disks/change_disk_storage_policy" + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/disks/create.go b/pkg/cloudbroker/disks/create.go index ae585fd..561a5e1 100644 --- a/pkg/cloudbroker/disks/create.go +++ b/pkg/cloudbroker/disks/create.go @@ -18,6 +18,10 @@ type CreateRequest struct { // Required: true Name string `url:"name" json:"name" validate:"required"` + // ID of the storage policy under the disk will be created + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Description of disk // Required: false Description string `url:"description,omitempty" json:"description,omitempty"` diff --git a/pkg/cloudbroker/disks/from_platform_disk.go b/pkg/cloudbroker/disks/from_platform_disk.go index 1682abd..21bc3ba 100644 --- a/pkg/cloudbroker/disks/from_platform_disk.go +++ b/pkg/cloudbroker/disks/from_platform_disk.go @@ -43,11 +43,6 @@ type FromPlatformDiskRequest struct { // Required: false PoolName string `url:"poolName,omitempty" json:"poolName,omitempty"` - // List of types of compute suitable for image - // Example: [ "KVM_X86" ] - // Required: true - Drivers []string `url:"drivers" json:"drivers" validate:"required"` - // Does this machine supports hot resize // Required: false HotResize bool `url:"hotresize" json:"hotresize"` diff --git a/pkg/cloudbroker/disks/models.go b/pkg/cloudbroker/disks/models.go index d3791d6..aa565aa 100644 --- a/pkg/cloudbroker/disks/models.go +++ b/pkg/cloudbroker/disks/models.go @@ -170,9 +170,15 @@ type InfoDisk struct { // Status Status string `json:"status"` + // Storage policy ID + StoragePolicyID uint64 `json:"storage_policy_id"` + // Tech status TechStatus string `json:"techStatus"` + // Need to clean before destroy + ToClean bool `json:"to_clean"` + // Type Type string `json:"type"` diff --git a/pkg/cloudbroker/disks/replicate.go b/pkg/cloudbroker/disks/replicate.go index 64917bb..ca2ecce 100644 --- a/pkg/cloudbroker/disks/replicate.go +++ b/pkg/cloudbroker/disks/replicate.go @@ -25,9 +25,13 @@ type ReplicateRequest struct { // Pool name to create slave disk in // Required: true PoolName string `url:"poolName" json:"poolName" validate:"required"` + + // ID of the storage policy under the disk will be created + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` } -// Create an empty disk in chosen SEP and pool combination. +// Replicate create an empty disk in chosen SEP and pool combination. // Starts replication between chosen disk and newly created disk // Note: only TATLIN type SEP are supported for replications between func (d Disks) Replicate(ctx context.Context, req ReplicateRequest) (uint64, error) { diff --git a/pkg/cloudbroker/dpdknet/models.go b/pkg/cloudbroker/dpdknet/models.go index 7bcf84d..ebcca93 100644 --- a/pkg/cloudbroker/dpdknet/models.go +++ b/pkg/cloudbroker/dpdknet/models.go @@ -14,6 +14,9 @@ type RecordDPDKNet struct { // Description Description string `json:"description"` + // Enable Security Groups + EnableSecGroups bool `json:"enable_secgroups"` + // Grid ID GID uint64 `json:"gid"` @@ -63,6 +66,9 @@ type ItemDPDKNet struct { // Description Description string `json:"description"` + // Enable Security Groups + EnableSecGroups bool `json:"enable_secgroups"` + // Grid ID GID uint64 `json:"gid"` diff --git a/pkg/cloudbroker/dpdknet/update.go b/pkg/cloudbroker/dpdknet/update.go index 06c3481..eb5c0a1 100644 --- a/pkg/cloudbroker/dpdknet/update.go +++ b/pkg/cloudbroker/dpdknet/update.go @@ -37,6 +37,10 @@ type UpdateRequest struct { // Name of OVS Bridge to use for DPDK network // Required: true OVSBridge string `url:"ovsBridge,omitempty" json:"ovsBridge,omitempty"` + + // Flag indicating whether security groups are enabled for this network + // Required: false + EnableSecGroups interface{} `url:"enable_secgroups,omitempty" json:"enable_secgroups,omitempty" validate:"omitempty,isBool"` } // Update updates a DPDK networks diff --git a/pkg/cloudbroker/extnet/list.go b/pkg/cloudbroker/extnet/list.go index 0f44c49..7983493 100644 --- a/pkg/cloudbroker/extnet/list.go +++ b/pkg/cloudbroker/extnet/list.go @@ -42,6 +42,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudbroker/extnet/models.go b/pkg/cloudbroker/extnet/models.go index fcc44b9..a84c7f6 100644 --- a/pkg/cloudbroker/extnet/models.go +++ b/pkg/cloudbroker/extnet/models.go @@ -58,6 +58,9 @@ type ItemExtNet struct { // CKey CKey string `json:"_ckey"` + // Enable Security Groups + EnableSecGroups bool `json:"enable_secgroups"` + // Meta Meta []interface{} `json:"_meta"` @@ -166,6 +169,9 @@ type RecordExtNet struct { // List excludes Excluded ListReservations `json:"excluded"` + // Enable Security Groups + EnableSecGroups bool `json:"enable_secgroups"` + // Free IPs number FreeIPs int64 `json:"free_ips"` diff --git a/pkg/cloudbroker/extnet/update.go b/pkg/cloudbroker/extnet/update.go index 7c35cb0..5bac323 100644 --- a/pkg/cloudbroker/extnet/update.go +++ b/pkg/cloudbroker/extnet/update.go @@ -26,6 +26,10 @@ type UpdateRequest struct { // Default: 1500 // Required: false MTU uint64 `url:"mtu,omitempty" json:"mtu,omitempty"` + + // Flag indicating whether security groups are enabled for this network + // Required: false + EnableSecGroups interface{} `url:"enable_secgroups,omitempty" json:"enable_secgroups,omitempty" validate:"omitempty,isBool"` } // Update updates external network parameters diff --git a/pkg/cloudbroker/image/change_storage_policy.go b/pkg/cloudbroker/image/change_storage_policy.go new file mode 100644 index 0000000..5a9bf3c --- /dev/null +++ b/pkg/cloudbroker/image/change_storage_policy.go @@ -0,0 +1,41 @@ +package image + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type ChangeStoragePolicyRequest struct { + // ID of the image to change the storage policy + // Required: true + ImageID uint64 `url:"image_id" json:"image_id" validate:"required"` + + // ID of the storage policy to move the image to + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +// ChangeStoragePolicy changes the storage policy of the image chosen +func (i Image) ChangeStoragePolicy(ctx context.Context, req ChangeStoragePolicyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/image/change_storage_policy" + + res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/image/create_cdrom_image.go b/pkg/cloudbroker/image/create_cdrom_image.go index b7946af..e5a4221 100644 --- a/pkg/cloudbroker/image/create_cdrom_image.go +++ b/pkg/cloudbroker/image/create_cdrom_image.go @@ -18,6 +18,10 @@ type CreateCDROMImageRequest struct { // Required: true URL string `url:"url" json:"url" validate:"required,url"` + // ID of the chosen storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Account ID to make the image exclusive // Required: false AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` @@ -37,11 +41,6 @@ type CreateCDROMImageRequest struct { // Password for remote media download // Required: false PasswordDl string `url:"passwordDL,omitempty" json:"passwordDL,omitempty"` - - // List of types of compute suitable for image. - // Example: [ "KVM_X86" ] - // Required: false - Drivers []string `url:"drivers,omitempty" json:"drivers,omitempty" validate:"max=2,imageDrivers"` } // CreateCDROMImage creates CD-ROM image from an ISO identified by URL diff --git a/pkg/cloudbroker/image/create_image.go b/pkg/cloudbroker/image/create_image.go index 79d5efe..b9042c2 100644 --- a/pkg/cloudbroker/image/create_image.go +++ b/pkg/cloudbroker/image/create_image.go @@ -34,6 +34,10 @@ type CreateRequest struct { // Required: true ImageType string `url:"imagetype" json:"imagetype" validate:"required,imageType"` + // ID of the chosen storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Select a network interface naming pattern for your Linux machine. eth - onboard, ens - pci slot naming // Should be: // - eth @@ -73,11 +77,6 @@ type CreateRequest struct { // Required: false PoolName string `url:"poolName,omitempty" json:"poolName,omitempty"` - // List of types of compute suitable for image - // Example: [ "KVM_X86" ] - // Required: required - Drivers []string `url:"drivers" json:"drivers" validate:"min=1,max=2,imageDrivers"` - // Bootable image or not // Required: false Bootable bool `url:"bootable,omitempty" json:"bootable,omitempty"` diff --git a/pkg/cloudbroker/image/create_virtual.go b/pkg/cloudbroker/image/create_virtual.go index df5685a..e1509a8 100644 --- a/pkg/cloudbroker/image/create_virtual.go +++ b/pkg/cloudbroker/image/create_virtual.go @@ -17,6 +17,11 @@ type CreateVirtualRequest struct { // ID of real image to link this virtual image to upon creation // Required: true TargetID uint64 `url:"targetId" json:"targetId" validate:"required"` + + // AccountID to make the virtual image exclusive + // Required: false + // Default: 0 + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` } // CreateVirtual creates virtual image diff --git a/pkg/cloudbroker/image/models.go b/pkg/cloudbroker/image/models.go index fd4aaa8..c094a9d 100644 --- a/pkg/cloudbroker/image/models.go +++ b/pkg/cloudbroker/image/models.go @@ -110,6 +110,9 @@ type RecordImage struct { // Status Status string `json:"status"` + // Storage policy ID + StoragePolicyID uint64 `json:"storage_policy_id"` + // Tech status TechStatus string `json:"techStatus"` @@ -236,6 +239,9 @@ type ItemImage struct { // Status Status string `json:"status"` + // Storage policy ID + StoragePolicyID uint64 `json:"storage_policy_id"` + // Tech status TechStatus string `json:"techStatus"` diff --git a/pkg/cloudbroker/k8ci/create.go b/pkg/cloudbroker/k8ci/create.go index 3e19f96..09dd07e 100644 --- a/pkg/cloudbroker/k8ci/create.go +++ b/pkg/cloudbroker/k8ci/create.go @@ -26,24 +26,10 @@ type CreateRequest struct { // Required: true MasterImageID uint64 `url:"masterImageId" json:"masterImageId" validate:"required"` - // Compute driver - // Should be one of: - // - KVM_X86 - // - etc - // Required: true - MasterDriver string `url:"masterDriver" json:"masterDriver" validate:"driver"` - // Image ID for worker K8S node // Required: true WorkerImageID uint64 `url:"workerImageId" json:"workerImageId" validate:"required"` - // Compute driver - // Should be one of - // - KVM_X86 - // - etc - // Required: true - WorkerDriver string `url:"workerDriver" json:"workerDriver" validate:"driver"` - // List of account IDs, which have access to this item. // If empty, any account has access // Required: false diff --git a/pkg/cloudbroker/k8ci/filter_test.go b/pkg/cloudbroker/k8ci/filter_test.go index fbaa6d4..5df0376 100644 --- a/pkg/cloudbroker/k8ci/filter_test.go +++ b/pkg/cloudbroker/k8ci/filter_test.go @@ -12,7 +12,6 @@ var k8ciItems = ListK8CI{ GUID: 1, ID: 1, LBImageID: 5, - MasterDriver: "KVM_X86", MasterImageID: 120, MaxMasterCount: 2, MaxWorkerCount: 3, @@ -20,7 +19,6 @@ var k8ciItems = ListK8CI{ SharedWith: []uint64{}, Status: "ENABLED", Version: "1", - WorkerDriver: "KVM_X86", WorkerImageID: 120, }, }, @@ -32,7 +30,6 @@ var k8ciItems = ListK8CI{ GUID: 2, ID: 2, LBImageID: 10, - MasterDriver: "KVM_X86", MasterImageID: 121, MaxMasterCount: 3, MaxWorkerCount: 5, @@ -40,7 +37,6 @@ var k8ciItems = ListK8CI{ SharedWith: []uint64{}, Status: "DISABLED", Version: "2", - WorkerDriver: "KVM_X86", WorkerImageID: 121, }, }, @@ -52,7 +48,6 @@ var k8ciItems = ListK8CI{ GUID: 3, ID: 3, LBImageID: 12, - MasterDriver: "KVM_X86", MasterImageID: 98, MaxMasterCount: 5, MaxWorkerCount: 9, @@ -60,7 +55,6 @@ var k8ciItems = ListK8CI{ SharedWith: []uint64{}, Status: "ENABLED", Version: "3", - WorkerDriver: "KVM_X86", WorkerImageID: 98, }, }, diff --git a/pkg/cloudbroker/k8ci/list.go b/pkg/cloudbroker/k8ci/list.go index 538e3fb..68c9651 100644 --- a/pkg/cloudbroker/k8ci/list.go +++ b/pkg/cloudbroker/k8ci/list.go @@ -22,14 +22,6 @@ type ListRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` - // Find by worker driver - // Required: false - WorkerDriver string `url:"workerDriver,omitempty" json:"workerDriver,omitempty"` - - // Find by master driver - // Required: false - MasterDriver string `url:"masterDriver,omitempty" json:"masterDriver,omitempty"` - // Find by network plugin // Required: false NetworkPlugins string `url:"netPlugins,omitempty" json:"masterDrnetPluginsiver,omitempty"` diff --git a/pkg/cloudbroker/k8ci/list_deleted.go b/pkg/cloudbroker/k8ci/list_deleted.go index ee66bda..1aef4b1 100644 --- a/pkg/cloudbroker/k8ci/list_deleted.go +++ b/pkg/cloudbroker/k8ci/list_deleted.go @@ -18,14 +18,6 @@ type ListDeletedRequest struct { // Required: false Name string `url:"name,omitempty" json:"name,omitempty"` - // Find by worker driver - // Required: false - WorkerDriver string `url:"workerDriver,omitempty" json:"workerDriver,omitempty"` - - // Find by master driver - // Required: false - MasterDriver string `url:"masterDriver,omitempty" json:"masterDriver,omitempty"` - // Find by network plugin // Required: false NetworkPlugins string `url:"netPlugins,omitempty" json:"netPlugins,omitempty"` diff --git a/pkg/cloudbroker/k8ci/models.go b/pkg/cloudbroker/k8ci/models.go index 647956b..cdeb03b 100644 --- a/pkg/cloudbroker/k8ci/models.go +++ b/pkg/cloudbroker/k8ci/models.go @@ -34,9 +34,6 @@ type RecordK8CIList struct { // Load balancer image ID LBImageID uint64 `json:"lbImageId"` - // Master driver - MasterDriver string `json:"masterDriver"` - // Master image ID MasterImageID uint64 `json:"masterImageId"` @@ -58,14 +55,11 @@ type RecordK8CIList struct { // Version Version string `json:"version"` - // Worker driver - WorkerDriver string `json:"workerDriver"` - // Worker image ID WorkerImageID uint64 `json:"workerImageId"` } -// Detailed information about K8CI +// Detailed information about K8CI type RecordK8CI struct { // Description Description string `json:"desc"` @@ -82,12 +76,12 @@ type RecordK8CI struct { // Load balancer image ID LBImageID uint64 `json:"lbImageId"` - // Master driver - MasterDriver string `json:"masterDriver"` - // Master image ID MasterImageID uint64 `json:"masterImageId"` + // Master driver + MasterDriver string `json:"masterDriver"` + // Max master count MaxMasterCount uint64 `json:"maxMasterCount"` @@ -112,9 +106,9 @@ type RecordK8CI struct { // Version Version string `json:"version"` - // Worker driver - WorkerDriver string `json:"workerDriver"` - // Worker image ID WorkerImageID uint64 `json:"workerImageId"` + + // Worker driver + WorkerDriver string `json:"workerDriver"` } diff --git a/pkg/cloudbroker/k8s/create.go b/pkg/cloudbroker/k8s/create.go index c30cf81..5c07c28 100644 --- a/pkg/cloudbroker/k8s/create.go +++ b/pkg/cloudbroker/k8s/create.go @@ -31,6 +31,10 @@ type CreateRequest struct { // Required: true NetworkPlugin string `url:"networkPlugin" json:"networkPlugin" validate:"required,networkPlugin"` + // ID of the chosen storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // ID of SEP to create boot disks for master nodes. // Uses images SEP ID if not set // Required: false diff --git a/pkg/cloudbroker/k8s/list.go b/pkg/cloudbroker/k8s/list.go index a677d84..8a088b8 100644 --- a/pkg/cloudbroker/k8s/list.go +++ b/pkg/cloudbroker/k8s/list.go @@ -50,6 +50,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudbroker/k8s/workers_group_add.go b/pkg/cloudbroker/k8s/workers_group_add.go index 3fad133..5ae6334 100644 --- a/pkg/cloudbroker/k8s/workers_group_add.go +++ b/pkg/cloudbroker/k8s/workers_group_add.go @@ -18,6 +18,10 @@ type WorkersGroupAddRequest struct { // Required: true Name string `url:"name" json:"name" validate:"required"` + // ID of the chosen storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // ID of SEP to create boot disks for default worker nodes group. // Uses images SEP ID if not set // Required: false diff --git a/pkg/cloudbroker/kvmx86/create.go b/pkg/cloudbroker/kvmx86/create.go index 999bcdf..44138e1 100644 --- a/pkg/cloudbroker/kvmx86/create.go +++ b/pkg/cloudbroker/kvmx86/create.go @@ -42,6 +42,18 @@ type Interface struct { // SDN interface id // Required: false SDNInterfaceID string `url:"sdn_interface_id,omitempty" json:"sdn_interface_id,omitempty"` + + // List of security group IDs to assign to this interface + // Required: false + SecGroups []uint64 `url:"security_groups,omitempty" json:"security_groups,omitempty"` + + // Flag indicating whether security groups are enabled for this interface + // Required: false + EnableSecGroups bool `url:"enable_secgroups,omitempty" json:"enable_secgroups,omitempty"` + + // Flag indicating whether this interface is enabled (only for VINS, EXTNET, DPDK, SDN, TRUNK) + // Required: false + Enabled interface{} `url:"enabled,omitempty" json:"enabled,omitempty" validate:"omitempty,isBool"` } // DataDisk detailed struct for DataDisks field in CreateRequest, CreateBlankRequest and MassCreateRequest @@ -54,6 +66,10 @@ type DataDisk struct { // Required: true Size uint64 `url:"size" json:"size" validate:"required"` + // Storage policy id of disk. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // Storage endpoint provider ID // By default the same with boot disk // Required: false @@ -92,6 +108,10 @@ type CreateRequest struct { // Required: true RAM uint64 `url:"ram" json:"ram" validate:"required"` + // Storage policy id of сompute. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // If True, the imageId, bootDisk, sepId, pool parameters are ignored and the compute is created without a boot disk in the stopped state // Required: false WithoutBootDisk bool `url:"withoutBootDisk" json:"withoutBootDisk"` @@ -154,10 +174,6 @@ type CreateRequest struct { // Required: false CustomField string `url:"customFields,omitempty" json:"customFields,omitempty"` - //Type of compute Stateful (KVM_X86) - // Required: false - Driver string `url:"driver,omitempty" json:"driver,omitempty"` - // Rule for VM placement with NUMA affinity. // Possible values - none (placement without NUMA affinity), // strict (strictly with NUMA affinity, if not possible - do not start VM), diff --git a/pkg/cloudbroker/kvmx86/create_blank.go b/pkg/cloudbroker/kvmx86/create_blank.go index ab4f54b..ca87665 100644 --- a/pkg/cloudbroker/kvmx86/create_blank.go +++ b/pkg/cloudbroker/kvmx86/create_blank.go @@ -28,6 +28,10 @@ type CreateBlankRequest struct { // Required: true RAM uint64 `url:"ram" json:"ram" validate:"required"` + // Storage policy id of сompute. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // If True, the imageId, bootDisk, sepId, pool parameters are ignored and the compute is created without a boot disk in the stopped state // Required: false WithoutBootDisk bool `url:"withoutBootDisk" json:"withoutBootDisk"` @@ -61,10 +65,6 @@ type CreateBlankRequest struct { // Required: false Description string `url:"desc,omitempty" json:"desc,omitempty"` - //Type of compute Stateful (KVM_X86) - // Required: false - Driver string `url:"driver,omitempty" json:"driver,omitempty"` - // Type of the emulated system, Q35 or i440fx // Required: false Chipset string `url:"chipset,omitempty" json:"chipset,omitempty" validate:"omitempty,chipset"` diff --git a/pkg/cloudbroker/kvmx86/mass_create.go b/pkg/cloudbroker/kvmx86/mass_create.go index 4f34fe8..fa8997b 100644 --- a/pkg/cloudbroker/kvmx86/mass_create.go +++ b/pkg/cloudbroker/kvmx86/mass_create.go @@ -31,6 +31,10 @@ type MassCreateRequest struct { // Required: true RAM uint64 `url:"ram" json:"ram" validate:"required"` + // Storage policy id of сompute. The rules of the specified storage policy will be used. + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + // If True, the imageId, bootDisk, sepId, pool parameters are ignored and the compute is created without a boot disk in the stopped state // Required: false WithoutBootDisk bool `url:"withoutBootDisk" json:"withoutBootDisk"` diff --git a/pkg/cloudbroker/lb/list.go b/pkg/cloudbroker/lb/list.go index f554e97..78c61c9 100644 --- a/pkg/cloudbroker/lb/list.go +++ b/pkg/cloudbroker/lb/list.go @@ -50,6 +50,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudbroker/node/models.go b/pkg/cloudbroker/node/models.go index b4c9dd5..abe123e 100644 --- a/pkg/cloudbroker/node/models.go +++ b/pkg/cloudbroker/node/models.go @@ -100,6 +100,9 @@ type ConsumptionInfo struct { type FreeResourcesInfo struct { // RAM RAM float64 `json:"RAM"` + + // VCPU + VCPU uint64 `json:"vCPU"` } // Resources Info diff --git a/pkg/cloudbroker/rg/add_storage_policy.go b/pkg/cloudbroker/rg/add_storage_policy.go new file mode 100644 index 0000000..b9cec46 --- /dev/null +++ b/pkg/cloudbroker/rg/add_storage_policy.go @@ -0,0 +1,46 @@ +package rg + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// AddStoragePolicyRequest struct for adding storage policy to the resource group +type AddStoragePolicyRequest struct { + // ID of resource group to add to + // Required: true + RGID uint64 `url:"resgroup_id" json:"resgroup_id" validate:"required"` + + // ID of the storage policy to which to connect resource group + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + + // Limit storage resources GB. Or -1 unlimit + // Required: false + Limit int `url:"limit,omitempty" json:"limit,omitempty"` +} + +// AddStoragePolicy add storage policy to the account. +func (r RG) AddStoragePolicy(ctx context.Context, req AddStoragePolicyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/rg/add_storage_policy" + + res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/rg/create.go b/pkg/cloudbroker/rg/create.go index 2181876..ae30cd5 100644 --- a/pkg/cloudbroker/rg/create.go +++ b/pkg/cloudbroker/rg/create.go @@ -5,6 +5,7 @@ import ( "net/http" "strconv" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) @@ -26,6 +27,10 @@ type CreateRequest struct { // Required: false MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"` + // Storage policies + // Required: false + StoragePolicies []StoragePolicy `url:"-" json:"storage_policies,omitempty"` + // Max size of aggregated virtual disks in GB // Required: false MaxVDiskCapacity int64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"` @@ -82,6 +87,11 @@ type CreateRequest struct { SDNAccessGroupID string `url:"sdn_access_group_id,omitempty" json:"sdn_access_group_id,omitempty"` } +type StoragePolicy struct { + ID int64 `url:"id" json:"id"` + Limit int `url:"limit" json:"limit"` +} + // Create creates resource group func (r RG) Create(ctx context.Context, req CreateRequest) (uint64, error) { err := validators.ValidateRequest(req) @@ -91,7 +101,7 @@ func (r RG) Create(ctx context.Context, req CreateRequest) (uint64, error) { url := "/cloudbroker/rg/create" - res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := r.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) if err != nil { return 0, err } diff --git a/pkg/cloudbroker/rg/del_storage_policy.go b/pkg/cloudbroker/rg/del_storage_policy.go new file mode 100644 index 0000000..23fc0f5 --- /dev/null +++ b/pkg/cloudbroker/rg/del_storage_policy.go @@ -0,0 +1,42 @@ +package rg + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DelStoragePolicyRequest struct for deleting storage policy to the resource group +type DelStoragePolicyRequest struct { + // ID of resource group + // Required: true + RGID uint64 `url:"resgroup_id" json:"resgroup_id" validate:"required"` + + // ID of the storage policy to which to disconnect account + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +// DelStoragePolicy delete storage policy to the account. +func (r RG) DelStoragePolicy(ctx context.Context, req DelStoragePolicyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/rg/del_storage_policy" + + res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/rg/models.go b/pkg/cloudbroker/rg/models.go index fa5798d..3fbe1e7 100644 --- a/pkg/cloudbroker/rg/models.go +++ b/pkg/cloudbroker/rg/models.go @@ -126,6 +126,9 @@ type ResourceLimits struct { // GPU units GPUUnits float64 `json:"gpu_units"` + + // Storage policies + StoragePolicies []StoragePolicy `json:"storage_policy"` } // Detailed information about resource group @@ -208,6 +211,9 @@ type ItemRG struct { // Secret Secret string `json:"secret"` + // Storage policy ids + StoragePolicyIDs []uint64 `json:"storage_policy_ids"` + // Status Status string `json:"status"` diff --git a/pkg/cloudbroker/rg/update.go b/pkg/cloudbroker/rg/update.go index 3afce9c..a967d7e 100644 --- a/pkg/cloudbroker/rg/update.go +++ b/pkg/cloudbroker/rg/update.go @@ -5,6 +5,7 @@ import ( "net/http" "strconv" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) @@ -50,6 +51,10 @@ type UpdateRequest struct { // Default: false // Required: false ClearUniqPools bool `url:"clearUniqPools" json:"clearUniqPools"` + + // Storage policies + // Required: false + StoragePolicies []StoragePolicy `url:"-" json:"storage_policies,omitempty"` } // Update updates resource group @@ -61,7 +66,7 @@ func (r RG) Update(ctx context.Context, req UpdateRequest) (bool, error) { url := "/cloudbroker/rg/update" - res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := r.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) if err != nil { return false, err } diff --git a/pkg/cloudbroker/security_group/create.go b/pkg/cloudbroker/security_group/create.go new file mode 100644 index 0000000..dfe2407 --- /dev/null +++ b/pkg/cloudbroker/security_group/create.go @@ -0,0 +1,46 @@ +package securitygroup + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type CreateRequest struct { + // Account ID that owns security group + // Required: true + AccountID uint64 `url:"account_id" json:"account_id" validate:"required"` + + // Security group name + // Required: true + Name string `url:"name" json:"name" validate:"required"` + + // Security group description + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` +} + +func (sg SecurityGroup) Create(ctx context.Context, req CreateRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/security_group/create" + + res, err := sg.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) + if err != nil { + return 0, err + } + + result, err := strconv.ParseUint(string(res), 10, 64) + if err != nil { + return 0, err + } + + return result, nil + +} diff --git a/pkg/cloudbroker/security_group/create_rule.go b/pkg/cloudbroker/security_group/create_rule.go new file mode 100644 index 0000000..f7be1d0 --- /dev/null +++ b/pkg/cloudbroker/security_group/create_rule.go @@ -0,0 +1,63 @@ +package securitygroup + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type CreateRuleRequest struct { + // Security group ID + // Required: true + SecurityGroupID uint64 `url:"security_group_id" json:"security_group_id" validate:"required"` + + // Traffic direction (inbound/outbound) + // Required: true + Direction string `url:"direction" json:"direction" validate:"required,securityGroupDirection"` + + // IP protocol version + // Default: IPv4 + // Required: false + Ethertype string `url:"ethertype,omitempty" json:"ethertype,omitempty" validate:"omitempty,securityGroupEthertype"` + + // Network protocol, available values : icmp, tcp, udp + // Required: false + Protocol string `url:"protocol,omitempty" json:"protocol,omitempty" validate:"omitempty,securityGroupProtocol"` + + // Start port number (for TCP/UDP) + // Required: false + PortRangeMin uint64 `url:"port_range_min,omitempty" json:"port_range_min,omitempty"` + + // End port number (for TCP/UDP) + // Required: false + PortRangeMax uint64 `url:"port_range_max,omitempty" json:"port_range_max,omitempty"` + + // Remote IP prefix in CIDR notation + // Required: false + RemoteIPPrefix string `url:"remote_ip_prefix,omitempty" json:"remote_ip_prefix,omitempty"` +} + +func (sg SecurityGroup) CreateRule(ctx context.Context, req CreateRuleRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/security_group/create_rule" + + res, err := sg.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) + if err != nil { + return 0, err + } + + result, err := strconv.ParseUint(string(res), 10, 64) + if err != nil { + return 0, err + } + + return result, nil + +} diff --git a/pkg/cloudbroker/security_group/delete.go b/pkg/cloudbroker/security_group/delete.go new file mode 100644 index 0000000..4538a6f --- /dev/null +++ b/pkg/cloudbroker/security_group/delete.go @@ -0,0 +1,36 @@ +package securitygroup + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type DeleteRequest struct { + // Security group ID + // Required: true + SecurityGroupID uint64 `url:"security_group_id" json:"security_group_id" validate:"required"` +} + +func (sg SecurityGroup) Delete(ctx context.Context, req DeleteRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/security_group/delete" + + res, err := sg.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/security_group/delete_rule.go b/pkg/cloudbroker/security_group/delete_rule.go new file mode 100644 index 0000000..9609cec --- /dev/null +++ b/pkg/cloudbroker/security_group/delete_rule.go @@ -0,0 +1,40 @@ +package securitygroup + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type DeleteRuleRequest struct { + // Security group ID + // Required: true + SecurityGroupID uint64 `url:"security_group_id" json:"security_group_id" validate:"required"` + + // Rule ID + // Required: true + RuleID uint64 `url:"rule_id" json:"rule_id" validate:"required"` +} + +func (sg SecurityGroup) DeleteRule(ctx context.Context, req DeleteRuleRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/security_group/delete_rule" + + res, err := sg.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/security_group/filter.go b/pkg/cloudbroker/security_group/filter.go new file mode 100644 index 0000000..e95ee28 --- /dev/null +++ b/pkg/cloudbroker/security_group/filter.go @@ -0,0 +1,80 @@ +package securitygroup + +// FilterByID returns ListSecurityGroups with specified ID. +func (lsg ListSecurityGroups) FilterByID(id uint64) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.ID == id + } + + return lsg.FilterFunc(predicate) +} + +// FilterByID returns ListSecurityGroups with specified Name. +func (lsg ListSecurityGroups) FilterByName(name string) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.Name == name + } + + return lsg.FilterFunc(predicate) +} + +// FilterByCreatedBy returns ListSecurityGroups with specified CreatedBy. +func (lsg ListSecurityGroups) FilterByCreatedBy(createdBy string) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.CreatedBy == createdBy + } + + return lsg.FilterFunc(predicate) +} + +// FilterByDescription returns ListSecurityGroups with specified Description. +func (lsg ListSecurityGroups) FilterByDescription(description string) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.Description == description + } + + return lsg.FilterFunc(predicate) +} + +// FilterByUpdatedBy returns ListSecurityGroups with specified UpdatedBy. +func (lsg ListSecurityGroups) FilterByUpdatedBy(updatedBy string) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.UpdatedBy == updatedBy + } + + return lsg.FilterFunc(predicate) +} + +// FilterByAccountID returns ListSecurityGroups with specified AccountID. +func (lsg ListSecurityGroups) FilterByAccountID(accountID uint64) ListSecurityGroups { + predicate := func(isg ItemSecurityGroup) bool { + return isg.AccountID == accountID + } + + return lsg.FilterFunc(predicate) +} + +// FilterFunc allows filtering ListSecurityGroups based on a user-specified predicate. +func (lsg ListSecurityGroups) FilterFunc(predicate func(ItemSecurityGroup) bool) ListSecurityGroups { + var result ListSecurityGroups + + for _, item := range lsg.Data { + if predicate(item) { + result.Data = append(result.Data, item) + } + } + + result.EntryCount = uint64(len(result.Data)) + + return result +} + +// FindOne returns first found ItemSecurityGroup +// If none was found, returns an empty struct. +func (lsg ListSecurityGroups) FindOne() ItemSecurityGroup { + if len(lsg.Data) == 0 { + return ItemSecurityGroup{} + } + + return lsg.Data[0] +} diff --git a/pkg/cloudbroker/security_group/filter_test.go b/pkg/cloudbroker/security_group/filter_test.go new file mode 100644 index 0000000..821f016 --- /dev/null +++ b/pkg/cloudbroker/security_group/filter_test.go @@ -0,0 +1,87 @@ +package securitygroup + +import "testing" + +var securityGroups = ListSecurityGroups{ + Data: []ItemSecurityGroup{ + { + ID: 1, + AccountID: 1, + Name: "sg1", + Description: "some desc", + CreatedBy: "user", + }, + { + ID: 3, + AccountID: 3, + Name: "sg3", + Description: "some desc", + CreatedBy: "anotheruser", + }, + { + ID: 5, + AccountID: 3, + Name: "sg5", + Description: "some other desc", + CreatedBy: "anotheruser", + UpdatedBy: "user", + }, + }, + EntryCount: 3, +} + +func TestFilterByID(t *testing.T) { + actual := securityGroups.FilterByID(1).FindOne() + if actual.ID != 1 { + t.Fatal("expected ID 1, found: ", actual.ID) + } +} + +func TestFilterByName(t *testing.T) { + actual := securityGroups.FilterByName("sg3").FindOne() + if actual.Name != "sg3" { + t.Fatal("expected Name sg3, found: ", actual.Name) + } +} + +func TestFilterByDescription(t *testing.T) { + actual := securityGroups.FilterByDescription("some desc") + + if len(actual.Data) != 2 { + t.Fatal("expected 2 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if item.Description != "some desc" { + t.Fatal("expected Description 'some desc', found: ", item.Description) + } + } +} + +func TestFilterByAccountID(t *testing.T) { + actual := securityGroups.FilterByAccountID(1).FindOne() + if actual.AccountID != 1 { + t.Fatal("expected AccountID 1, found: ", actual.AccountID) + } +} + +func TestFilterByCreatedBy(t *testing.T) { + actual := securityGroups.FilterByCreatedBy("anotheruser") + + if len(actual.Data) != 2 { + t.Fatal("expected 2 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if item.CreatedBy != "anotheruser" { + t.Fatal("expected CreatedBy 'anotheruser', found: ", item.CreatedBy) + } + } +} + +func TestFilterByUpdatedBy(t *testing.T) { + actual := securityGroups.FilterByUpdatedBy("user").FindOne() + if actual.UpdatedBy != "user" { + t.Fatal("expected UpdatedBy 'user', found: ", actual.UpdatedBy) + } +} diff --git a/pkg/cloudbroker/security_group/get.go b/pkg/cloudbroker/security_group/get.go new file mode 100644 index 0000000..2b92d03 --- /dev/null +++ b/pkg/cloudbroker/security_group/get.go @@ -0,0 +1,43 @@ +package securitygroup + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type GetRequest struct { + // ID of security group + // Required: true + SecurityGroupID uint64 `url:"security_group_id" json:"security_group_id" validate:"required"` +} + +func (sg SecurityGroup) Get(ctx context.Context, req GetRequest) (*RecordSecurityGroup, error) { + res, err := sg.GetRaw(ctx, req) + if err != nil { + return nil, err + } + + info := RecordSecurityGroup{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +func (sg SecurityGroup) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/security_group/get" + + res, err := sg.client.DecortApiCall(ctx, http.MethodGet, url, req) + return res, err +} diff --git a/pkg/cloudbroker/security_group/list.go b/pkg/cloudbroker/security_group/list.go new file mode 100644 index 0000000..ab13a28 --- /dev/null +++ b/pkg/cloudbroker/security_group/list.go @@ -0,0 +1,86 @@ +package securitygroup + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type ListRequest struct { + // Search by security group id + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Search by account id + // Required: false + AccountID uint64 `url:"account_id,omitempty" json:"account_id,omitempty"` + + // Search by security group name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Search by security group description + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` + + // Search by created after time (unix timestamp) + // Required: false + CreatedMin uint64 `url:"created_min,omitempty" json:"created_min,omitempty"` + + // Search by created before time (unix timestamp) + // Required: false + CreatedMax uint64 `url:"created_max,omitempty" json:"created_max,omitempty"` + + // Search by updated after time (unix timestamp) + // Required: false + UpdatedMin uint64 `url:"updated_min,omitempty" json:"updated_min,omitempty"` + + // Search by updated before time (unix timestamp) + // Required: false + UpdatedMax uint64 `url:"updated_max,omitempty" json:"updated_max,omitempty"` + + // Sort by one of supported fields, format ± + // Required: false + SortBy string `url:"sort_by,omitempty" json:"sort_by,omitempty"` + + // Page number + // Required: false + Page uint64 `url:"page,omitempty" json:"page,omitempty"` + + // Page size + // Required: false + Size uint64 `url:"size,omitempty" json:"size,omitempty"` +} + +// List gets list of security groups as a ListSecurityGroups struct +func (sg SecurityGroup) List(ctx context.Context, req ListRequest) (*ListSecurityGroups, error) { + + res, err := sg.ListRaw(ctx, req) + if err != nil { + return nil, err + } + + list := ListSecurityGroups{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} + +// ListRaw gets list of security groups as an array of bytes +func (sg SecurityGroup) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/security_group/list" + + res, err := sg.client.DecortApiCall(ctx, http.MethodGet, url, req) + return res, err +} diff --git a/pkg/cloudbroker/security_group/models.go b/pkg/cloudbroker/security_group/models.go new file mode 100644 index 0000000..440e813 --- /dev/null +++ b/pkg/cloudbroker/security_group/models.go @@ -0,0 +1,43 @@ +package securitygroup + +type ListSecurityGroups struct { + Data []ItemSecurityGroup `json:"data"` + EntryCount uint64 `json:"entryCount"` +} + +type ItemSecurityGroup struct { + ID uint64 `json:"id"` + AccountID uint64 `json:"account_id"` + Name string `json:"name"` + Description string `json:"description"` + Rules Rules `json:"rules"` + CreatedAt uint64 `json:"created_at"` + UpdatedAt uint64 `json:"updated_at"` + CreatedBy string `json:"created_by"` + UpdatedBy string `json:"updated_by"` +} + +type RecordSecurityGroup struct { + ID uint64 `json:"id"` + AccountID uint64 `json:"account_id"` + Name string `json:"name"` + Description string `json:"description"` + Rules Rules `json:"rules"` + CreatedAt uint64 `json:"created_at"` + UpdatedAt uint64 `json:"updated_at"` + CreatedBy string `json:"created_by"` + UpdatedBy string `json:"updated_by"` +} + +type Rules []Rule + +type Rule struct { + ID uint64 `json:"id"` + Direction string `json:"direction"` + Ethertype string `json:"ethertype"` + Protocol string `json:"protocol"` + PortRangeMin uint64 `json:"port_range_min"` + PortRangeMax uint64 `json:"port_range_max"` + RemoteIPPrefix string `json:"remote_ip_prefix"` + RemoteGroupID uint64 `json:"remote_group_id"` +} diff --git a/pkg/cloudbroker/security_group/security_group.go b/pkg/cloudbroker/security_group/security_group.go new file mode 100644 index 0000000..35c6a3b --- /dev/null +++ b/pkg/cloudbroker/security_group/security_group.go @@ -0,0 +1,15 @@ +package securitygroup + +import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" + +// Structure for creating request to storage policy +type SecurityGroup struct { + client interfaces.Caller +} + +// Builder for stack endpoint +func New(client interfaces.Caller) *SecurityGroup { + return &SecurityGroup{ + client: client, + } +} diff --git a/pkg/cloudbroker/security_group/sorting.go b/pkg/cloudbroker/security_group/sorting.go new file mode 100644 index 0000000..5a54b53 --- /dev/null +++ b/pkg/cloudbroker/security_group/sorting.go @@ -0,0 +1,41 @@ +package securitygroup + +import "sort" + +// SortByCreatedAt sorts ListSecurityGroups by the CreatedAt field in ascending order. +// +// If inverse param is set to true, the order is reversed. +func (lsg ListSecurityGroups) SortByCreatedAt(inverse bool) ListSecurityGroups { + if len(lsg.Data) < 2 { + return lsg + } + + sort.Slice(lsg.Data, func(i, j int) bool { + if inverse { + return lsg.Data[i].CreatedAt > lsg.Data[j].CreatedAt + } + + return lsg.Data[i].CreatedAt < lsg.Data[j].CreatedAt + }) + + return lsg +} + +// SortByUpdatedAt sorts ListSecurityGroups by the UpdatedAt field in ascending order. +// +// If inverse param is set to true, the order is reversed. +func (lsg ListSecurityGroups) SortByUpdatedAt(inverse bool) ListSecurityGroups { + if len(lsg.Data) < 2 { + return lsg + } + + sort.Slice(lsg.Data, func(i, j int) bool { + if inverse { + return lsg.Data[i].UpdatedAt > lsg.Data[j].UpdatedAt + } + + return lsg.Data[i].UpdatedAt < lsg.Data[j].UpdatedAt + }) + + return lsg +} diff --git a/pkg/cloudbroker/security_group/update.go b/pkg/cloudbroker/security_group/update.go new file mode 100644 index 0000000..0e6835e --- /dev/null +++ b/pkg/cloudbroker/security_group/update.go @@ -0,0 +1,51 @@ +package securitygroup + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type UpdateRequest struct { + // Security group ID + // Required: true + SecurityGroupID uint64 `url:"security_group_id" json:"security_group_id" validate:"required"` + + // New security group name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // New security group description + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` +} + +func (sg SecurityGroup) Update(ctx context.Context, req UpdateRequest) (*RecordSecurityGroup, error) { + res, err := sg.UpdateRaw(ctx, req) + if err != nil { + return nil, err + } + + info := RecordSecurityGroup{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +func (sg SecurityGroup) UpdateRaw(ctx context.Context, req UpdateRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/security_group/update" + + res, err := sg.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudbroker/securitygroup.go b/pkg/cloudbroker/securitygroup.go new file mode 100644 index 0000000..5dba9c5 --- /dev/null +++ b/pkg/cloudbroker/securitygroup.go @@ -0,0 +1,10 @@ +package cloudbroker + +import ( + securitygroup "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/security_group" +) + +// Accessing the Security Group method group +func (cb *CloudBroker) SecurityGroup() *securitygroup.SecurityGroup { + return securitygroup.New(cb.client) +} diff --git a/pkg/cloudbroker/storage_policy/add_pool.go b/pkg/cloudbroker/storage_policy/add_pool.go new file mode 100644 index 0000000..a957e4f --- /dev/null +++ b/pkg/cloudbroker/storage_policy/add_pool.go @@ -0,0 +1,51 @@ +package storagepolicy + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type AddPoolRequest struct { + // ID of storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + + // Storage endpoint provider ID to add + // Required: true + SepID uint64 `url:"sep_id" json:"sep_id" validate:"required"` + + // Pool to add + // Required: true + PoolName string `url:"pool_name" json:"pool_name" validate:"required"` +} + +func (sp StoragePolicy) AddPool(ctx context.Context, req AddPoolRequest) (*InfoStoragePolicyWithID, error) { + res, err := sp.AddPoolRaw(ctx, req) + if err != nil { + return nil, err + } + + info := InfoStoragePolicyWithID{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +func (sp StoragePolicy) AddPoolRaw(ctx context.Context, req AddPoolRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/storage_policy/add_pool" + + res, err := sp.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudbroker/storage_policy/create.go b/pkg/cloudbroker/storage_policy/create.go new file mode 100644 index 0000000..b3a4181 --- /dev/null +++ b/pkg/cloudbroker/storage_policy/create.go @@ -0,0 +1,63 @@ +package storagepolicy + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type AccessSepsPool struct { + + // Storage endpoint provider ID + // Required: true + SepID uint64 `url:"sep_id" json:"sep_id" validate:"required"` + + // Names of pools + // Required: true + PoolNames []string `url:"pool_names" json:"pool_names" validate:"required"` +} + +type CreateRequest struct { + // Name of the storage policy + // Required: true + Name string `url:"name" json:"name" validate:"required"` + + // List of storage endpoint access objects + // Required: true + AccessSepsPools []AccessSepPool `url:"access_seps_pools" json:"access_seps_pools" validate:"required"` + + // Description of the storage policy + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` + + // Maximum IOPS limit + // Default: 2000 + // Required: false + LimitIOPS uint64 `url:"limit_iops,omitempty" json:"limit_iops,omitempty"` +} + +// Create creates a new storage policy +func (sp StoragePolicy) Create(ctx context.Context, req CreateRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/storage_policy/create" + + res, err := sp.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) + if err != nil { + return 0, err + } + + result, err := strconv.ParseUint(string(res), 10, 64) + if err != nil { + return 0, err + } + + return result, nil + +} diff --git a/pkg/cloudbroker/storage_policy/delete.go b/pkg/cloudbroker/storage_policy/delete.go new file mode 100644 index 0000000..38e4889 --- /dev/null +++ b/pkg/cloudbroker/storage_policy/delete.go @@ -0,0 +1,36 @@ +package storagepolicy + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type DeleteRequest struct { + // ID of storage policy to delete + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +func (sp StoragePolicy) Delete(ctx context.Context, req DeleteRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/storage_policy/delete" + + res, err := sp.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/storage_policy/delete_pool.go b/pkg/cloudbroker/storage_policy/delete_pool.go new file mode 100644 index 0000000..76d124a --- /dev/null +++ b/pkg/cloudbroker/storage_policy/delete_pool.go @@ -0,0 +1,51 @@ +package storagepolicy + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type DeletePollRequest struct { + // ID of storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + + // Storage endpoint provider ID to delete + // Required: true + SepID uint64 `url:"sep_id" json:"sep_id" validate:"required"` + + // Pool to delete + // Required: true + PoolName string `url:"pool_name" json:"pool_name" validate:"required"` +} + +func (sp StoragePolicy) DeletePool(ctx context.Context, req DeletePollRequest) (*InfoStoragePolicyWithID, error) { + res, err := sp.DeletePoolRaw(ctx, req) + if err != nil { + return nil, err + } + + info := InfoStoragePolicyWithID{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +func (sp StoragePolicy) DeletePoolRaw(ctx context.Context, req DeletePollRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/storage_policy/delete_pool" + + res, err := sp.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudbroker/storage_policy/disable.go b/pkg/cloudbroker/storage_policy/disable.go new file mode 100644 index 0000000..c6be2fa --- /dev/null +++ b/pkg/cloudbroker/storage_policy/disable.go @@ -0,0 +1,36 @@ +package storagepolicy + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type DisableRequest struct { + // ID of storage policy to disable + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +func (sp StoragePolicy) Disable(ctx context.Context, req DisableRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/storage_policy/disable" + + res, err := sp.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/storage_policy/enable.go b/pkg/cloudbroker/storage_policy/enable.go new file mode 100644 index 0000000..b889e69 --- /dev/null +++ b/pkg/cloudbroker/storage_policy/enable.go @@ -0,0 +1,36 @@ +package storagepolicy + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type EnableRequest struct { + // ID of storage policy to enable + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +func (sp StoragePolicy) Enable(ctx context.Context, req EnableRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/storage_policy/enable" + + res, err := sp.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/cloudbroker/storage_policy/filter.go b/pkg/cloudbroker/storage_policy/filter.go new file mode 100644 index 0000000..2e053c1 --- /dev/null +++ b/pkg/cloudbroker/storage_policy/filter.go @@ -0,0 +1,71 @@ +package storagepolicy + +// FilterByID returns ListStoragePolicies with specified ID. +func (lsp ListStoragePolicies) FilterByID(id uint64) ListStoragePolicies { + predicate := func(isp ItemStoragePolicy) bool { + return isp.ID == id + } + + return lsp.FilterFunc(predicate) +} + +// FilterByName returns ListStoragePolicies with specified Name. +func (lsp ListStoragePolicies) FilterByName(name string) ListStoragePolicies { + predicate := func(isp ItemStoragePolicy) bool { + return isp.Name == name + } + + return lsp.FilterFunc(predicate) +} + +// FilterByStatus returns ListStoragePolicies with specified Status. +func (lsp ListStoragePolicies) FilterByStatus(status string) ListStoragePolicies { + predicate := func(isp ItemStoragePolicy) bool { + return isp.Status == status + } + + return lsp.FilterFunc(predicate) +} + +// FilterByStatus returns ListStoragePolicies with specified Desc. +func (lsp ListStoragePolicies) FilterByDesc(desc string) ListStoragePolicies { + predicate := func(isp ItemStoragePolicy) bool { + return isp.Description == desc + } + + return lsp.FilterFunc(predicate) +} + +// FilterByLimitIOPS returns ListStoragePolicies with specified IOPS. +func (lsp ListStoragePolicies) FilterByLimitIOPS(limitIOPS uint64) ListStoragePolicies { + predicate := func(isp ItemStoragePolicy) bool { + return isp.LimitIOPS == limitIOPS + } + + return lsp.FilterFunc(predicate) +} + +// FilterFunc allows filtering ListStoragePolicies based on a user-specified predicate. +func (lsp ListStoragePolicies) FilterFunc(predicate func(ItemStoragePolicy) bool) ListStoragePolicies { + var result ListStoragePolicies + + for _, item := range lsp.Data { + if predicate(item) { + result.Data = append(result.Data, item) + } + } + + result.EntryCount = uint64(len(result.Data)) + + return result +} + +// FindOne returns first found ItemStoragePolicy +// If none was found, returns an empty struct. +func (lsp ListStoragePolicies) FindOne() ItemStoragePolicy { + if len(lsp.Data) == 0 { + return ItemStoragePolicy{} + } + + return lsp.Data[0] +} diff --git a/pkg/cloudbroker/storage_policy/filter_test.go b/pkg/cloudbroker/storage_policy/filter_test.go new file mode 100644 index 0000000..2666c10 --- /dev/null +++ b/pkg/cloudbroker/storage_policy/filter_test.go @@ -0,0 +1,110 @@ +package storagepolicy + +import "testing" + +var asp9 = AccessSepPool{ + SepID: 9, + PoolNames: []string{"data03"}, +} + +var asp7 = AccessSepPool{ + SepID: 7, + PoolNames: []string{"pool_QA"}, +} + +var asp8 = AccessSepPool{ + SepID: 8, + PoolNames: []string{ + "alpha_pool_block", + "alpha_pool_stripe", + "alpha_pool_file", + }, +} + +var storagePolicyItems = ListStoragePolicies{ + Data: []ItemStoragePolicy{ + { + ID: 1, + GUID: 1, + Name: "storagePolicy01", + Description: "desc", + AccessSepPools: ListAccessSepPools{asp7}, + Status: "ENABLED", + LimitIOPS: 2000, + Usage: Usage{}, + }, + { + ID: 3, + GUID: 3, + Name: "storagePolicy03", + Description: "desc", + AccessSepPools: ListAccessSepPools{asp7, asp8, asp9}, + Status: "ENABLED", + LimitIOPS: 2500, + Usage: Usage{}, + }, + { + ID: 5, + GUID: 5, + Name: "storagePolicy05", + Description: "another desc", + AccessSepPools: ListAccessSepPools{asp8, asp9}, + Status: "DISABLED", + LimitIOPS: 2000, + Usage: Usage{}, + }, + }, + EntryCount: 3, +} + +func TestFilterByID(t *testing.T) { + actual := storagePolicyItems.FilterByID(1).FindOne() + + if actual.ID != 1 { + t.Fatal("expected 1 ID, found: ", actual.ID) + } +} + +func TestFilterByName(t *testing.T) { + actual := storagePolicyItems.FilterByName("storagePolicy01").FindOne() + + if actual.Name != "storagePolicy01" { + t.Fatal("expected Name 'storagePolicy01', found: ", actual.Name) + } +} + +func TestFilterByStatus(t *testing.T) { + actual := storagePolicyItems.FilterByStatus("ENABLED") + + if len(actual.Data) != 2 { + t.Fatal("expected 2 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if item.Status != "ENABLED" { + t.Fatal("expected Status 'ENABLED', found: ", item.Status) + } + } +} + +func TestFilterByDesc(t *testing.T) { + actual := storagePolicyItems.FilterByDesc("desc") + + if len(actual.Data) != 2 { + t.Fatal("expected 2 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if item.Description != "desc" { + t.Fatal("expected Description 'desc', found: ", item.Status) + } + } +} + +func TestFilterByLimitIOPS(t *testing.T) { + actual := storagePolicyItems.FilterByLimitIOPS(2500).FindOne() + + if actual.LimitIOPS != 2500 { + t.Fatal("expected LimitIOPS '2500', found: ", actual.LimitIOPS) + } +} diff --git a/pkg/cloudbroker/storage_policy/get.go b/pkg/cloudbroker/storage_policy/get.go new file mode 100644 index 0000000..31ebd3c --- /dev/null +++ b/pkg/cloudbroker/storage_policy/get.go @@ -0,0 +1,43 @@ +package storagepolicy + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type GetRequest struct { + // ID of storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` +} + +func (sp StoragePolicy) Get(ctx context.Context, req GetRequest) (*InfoStoragePolicy, error) { + res, err := sp.GetRaw(ctx, req) + if err != nil { + return nil, err + } + + info := InfoStoragePolicy{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +func (sp StoragePolicy) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/storage_policy/get" + + res, err := sp.client.DecortApiCall(ctx, http.MethodGet, url, req) + return res, err +} diff --git a/pkg/cloudbroker/storage_policy/list.go b/pkg/cloudbroker/storage_policy/list.go new file mode 100644 index 0000000..8827ff5 --- /dev/null +++ b/pkg/cloudbroker/storage_policy/list.go @@ -0,0 +1,90 @@ +package storagepolicy + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type ListRequest struct { + // Page number + // Required: false + Page uint64 `url:"page,omitempty" json:"page,omitempty"` + + // Page size + // Required: false + Size uint64 `url:"size,omitempty" json:"size,omitempty"` + + // Search by storage policy ID + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Search by storage policy name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Search by storage policy status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Search by storage policy desc + // Required: false + Desc string `url:"desc,omitempty" json:"desc,omitempty"` + + // Search by storage policy iops limit + // Required: false + LimitIOPS uint64 `url:"limit_iops,omitempty" json:"limit_iops,omitempty"` + + // Sort by one of supported fields, format ± + // Required: false + SortBy string `url:"sort_by,omitempty" json:"sort_by,omitempty"` + + // ID of account ID + // Required: false + AccountID uint64 `url:"account_id,omitempty" json:"account_id,omitempty"` + + // Search by resgroup id + // Required: false + ResgroupID uint64 `url:"resgroup_id,omitempty" json:"resgroup_id,omitempty"` + + // Search by sep id + // Required: false + SepID uint64 `url:"sep_id,omitempty" json:"sep_id,omitempty"` + + // Search by pool name + // Required: false + PoolName string `url:"pool_name,omitempty" json:"pool_name,omitempty"` +} + +// List gets list of storage policies as a ListStoragePolicies struct +func (sp StoragePolicy) List(ctx context.Context, req ListRequest) (*ListStoragePolicies, error) { + + res, err := sp.ListRaw(ctx, req) + if err != nil { + return nil, err + } + + list := ListStoragePolicies{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} + +// ListRaw gets list of storage policies as an array of bytes +func (sp StoragePolicy) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/storage_policy/list" + + res, err := sp.client.DecortApiCall(ctx, http.MethodGet, url, req) + return res, err +} diff --git a/pkg/cloudbroker/storage_policy/models.go b/pkg/cloudbroker/storage_policy/models.go new file mode 100644 index 0000000..8643881 --- /dev/null +++ b/pkg/cloudbroker/storage_policy/models.go @@ -0,0 +1,51 @@ +package storagepolicy + +type InfoStoragePolicyWithID struct { + ID uint64 `json:"id"` + GUID uint64 `json:"guid"` + Name string `json:"name"` + Description string `json:"description"` + AccessSepPools ListAccessSepPools `json:"access_seps_pools"` + Status string `json:"status"` + LimitIOPS uint64 `json:"limit_iops"` + StoragePolicyID uint64 `json:"storage_policy_id"` +} + +type ListStoragePolicies struct { + Data []ItemStoragePolicy `json:"data"` + EntryCount uint64 `json:"entryCount"` +} + +type ItemStoragePolicy struct { + ID uint64 `json:"id"` + GUID uint64 `json:"guid"` + Name string `json:"name"` + Description string `json:"description"` + AccessSepPools ListAccessSepPools `json:"access_seps_pools"` + Status string `json:"status"` + LimitIOPS uint64 `json:"limit_iops"` + Usage Usage `json:"usage"` +} + +type InfoStoragePolicy struct { + ID uint64 `json:"id"` + GUID uint64 `json:"guid"` + Name string `json:"name"` + Description string `json:"description"` + AccessSepPools ListAccessSepPools `json:"access_seps_pools"` + Status string `json:"status"` + LimitIOPS uint64 `json:"limit_iops"` + Usage Usage `json:"usage"` +} + +type ListAccessSepPools []AccessSepPool + +type AccessSepPool struct { + SepID uint64 `json:"sep_id"` + PoolNames []string `json:"pool_names"` +} + +type Usage struct { + Accounts []uint64 `json:"accounts"` + Resgroups []uint64 `json:"resgroups"` +} diff --git a/pkg/cloudbroker/storage_policy/storage_policy.go b/pkg/cloudbroker/storage_policy/storage_policy.go new file mode 100644 index 0000000..42b42a2 --- /dev/null +++ b/pkg/cloudbroker/storage_policy/storage_policy.go @@ -0,0 +1,15 @@ +package storagepolicy + +import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" + +// Structure for creating request to storage policy +type StoragePolicy struct { + client interfaces.Caller +} + +// Builder for stack endpoint +func New(client interfaces.Caller) *StoragePolicy { + return &StoragePolicy{ + client: client, + } +} diff --git a/pkg/cloudbroker/storage_policy/update.go b/pkg/cloudbroker/storage_policy/update.go new file mode 100644 index 0000000..d233c76 --- /dev/null +++ b/pkg/cloudbroker/storage_policy/update.go @@ -0,0 +1,56 @@ +package storagepolicy + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +type UpdateRequest struct { + // ID of storage policy + // Required: true + StoragePolicyID uint64 `url:"storage_policy_id" json:"storage_policy_id" validate:"required"` + + // New name for the storage policy + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // New value for limit IOPS + // Required: false + LimitIOPS uint64 `url:"limit_iops,omitempty" json:"limit_iops,omitempty"` + + // New description of the storage policy + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` +} + +// Update updates storage policy +func (sp StoragePolicy) Update(ctx context.Context, req UpdateRequest) (*InfoStoragePolicyWithID, error) { + res, err := sp.UpdateRaw(ctx, req) + if err != nil { + return nil, err + } + + info := InfoStoragePolicyWithID{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +func (sp StoragePolicy) UpdateRaw(ctx context.Context, req UpdateRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/storage_policy/update" + + res, err := sp.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudbroker/storagepolicy.go b/pkg/cloudbroker/storagepolicy.go new file mode 100644 index 0000000..732eb08 --- /dev/null +++ b/pkg/cloudbroker/storagepolicy.go @@ -0,0 +1,10 @@ +package cloudbroker + +import ( + storagepolicy "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/storage_policy" +) + +// Accessing the Storage Policy method group +func (cb *CloudBroker) StoragePolicy() *storagepolicy.StoragePolicy { + return storagepolicy.New(cb.client) +} diff --git a/pkg/cloudbroker/trunk/list.go b/pkg/cloudbroker/trunk/list.go index da75c08..eb0fcb7 100644 --- a/pkg/cloudbroker/trunk/list.go +++ b/pkg/cloudbroker/trunk/list.go @@ -27,6 +27,9 @@ type ListRequest struct { // Page size Size uint64 `url:"size,omitempty" json:"size,omitempty"` + + // Status + Status string `url:"status,omitempty" json:"status,omitempty"` } // List gets list of all trunks as a ListTrunks struct diff --git a/pkg/cloudbroker/user/delete_users.go b/pkg/cloudbroker/user/delete_users.go index a879b8e..1a7c69e 100644 --- a/pkg/cloudbroker/user/delete_users.go +++ b/pkg/cloudbroker/user/delete_users.go @@ -3,15 +3,16 @@ package user import ( "context" "net/http" - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // DeleteUsersRequest struct for bulk delete a list of users. type DeleteUsersRequest struct { // List of user ids // Required: true - UserIDs string `url:"userIds" json:"userIds" validate:"required"` + UserIDs []string `url:"userIds" json:"userIds" validate:"required"` } // DeleteUsers bulk delete a list of users. diff --git a/pkg/cloudbroker/vins/list.go b/pkg/cloudbroker/vins/list.go index fe35a34..fbe8c63 100644 --- a/pkg/cloudbroker/vins/list.go +++ b/pkg/cloudbroker/vins/list.go @@ -46,6 +46,11 @@ type ListRequest struct { // Required: false SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Sort by zone id + // Default value: 0 + // Required: false + ZoneID uint64 `url:"zone_id,omitempty" json:"zone_id,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` diff --git a/pkg/cloudbroker/vins/mass_delete.go b/pkg/cloudbroker/vins/mass_delete.go index f783270..a47c53f 100644 --- a/pkg/cloudbroker/vins/mass_delete.go +++ b/pkg/cloudbroker/vins/mass_delete.go @@ -28,18 +28,18 @@ type MassDeleteRequest struct { } // MassDelete start jobs to delete several VINSes -func (v VINS) MassDelete(ctx context.Context, req MassDeleteRequest) (bool, error) { +func (v VINS) MassDelete(ctx context.Context, req MassDeleteRequest) (string, error) { err := validators.ValidateRequest(req) if err != nil { - return false, validators.ValidationErrors(validators.GetErrors(err)) + return "", validators.ValidationErrors(validators.GetErrors(err)) } url := "/cloudbroker/vins/massDelete" - _, err = v.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) if err != nil { - return false, err + return "", err } - return true, nil + return string(res), nil } diff --git a/pkg/cloudbroker/vins/mass_disable.go b/pkg/cloudbroker/vins/mass_disable.go index faf370f..6e92dbe 100644 --- a/pkg/cloudbroker/vins/mass_disable.go +++ b/pkg/cloudbroker/vins/mass_disable.go @@ -15,18 +15,18 @@ type MassDisableRequest struct { } // MassDisable start jobs to disable several VINSes -func (v VINS) MassDisable(ctx context.Context, req MassDisableRequest) (bool, error) { +func (v VINS) MassDisable(ctx context.Context, req MassDisableRequest) (string, error) { err := validators.ValidateRequest(req) if err != nil { - return false, validators.ValidationErrors(validators.GetErrors(err)) + return "", validators.ValidationErrors(validators.GetErrors(err)) } url := "/cloudbroker/vins/massDisable" - _, err = v.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) if err != nil { - return false, err + return "", err } - return true, nil + return string(res), nil } diff --git a/pkg/cloudbroker/vins/mass_enable.go b/pkg/cloudbroker/vins/mass_enable.go index 4224c40..116544f 100644 --- a/pkg/cloudbroker/vins/mass_enable.go +++ b/pkg/cloudbroker/vins/mass_enable.go @@ -15,18 +15,18 @@ type MassEnableRequest struct { } // MassEnable start jobs to enable several VINSes -func (v VINS) MassEnable(ctx context.Context, req MassEnableRequest) (bool, error) { +func (v VINS) MassEnable(ctx context.Context, req MassEnableRequest) (string, error) { err := validators.ValidateRequest(req) if err != nil { - return false, validators.ValidationErrors(validators.GetErrors(err)) + return "", validators.ValidationErrors(validators.GetErrors(err)) } url := "/cloudbroker/vins/massEnable" - _, err = v.client.DecortApiCall(ctx, http.MethodPost, url, req) + res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) if err != nil { - return false, err + return "", err } - return true, nil + return string(res), nil } diff --git a/pkg/cloudbroker/vins/models.go b/pkg/cloudbroker/vins/models.go index 16f3a81..6c59e2b 100644 --- a/pkg/cloudbroker/vins/models.go +++ b/pkg/cloudbroker/vins/models.go @@ -508,6 +508,9 @@ type RecordVINS struct { // Description Description string `json:"desc"` + // Enable Security Groups + EnableSecGroups bool `json:"enable_secgroups"` + // Grid ID GID uint64 `json:"gid"` @@ -718,6 +721,9 @@ type ItemVINS struct { // Description Description string `json:"desc"` + // Enable Security Groups + EnableSecGroups bool `json:"enable_secgroups"` + // External IP ExternalIP string `json:"externalIP"` diff --git a/pkg/cloudbroker/vins/update.go b/pkg/cloudbroker/vins/update.go new file mode 100644 index 0000000..1ad584b --- /dev/null +++ b/pkg/cloudbroker/vins/update.go @@ -0,0 +1,51 @@ +package vins + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// UpdateRequest struct to update vins parameters +type UpdateRequest struct { + // VINS ID + // Required: true + VINSID uint64 `url:"vins_id" json:"vins_id" validate:"required"` + + // Name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Desc + // Required: false + Desc string `url:"desc,omitempty" json:"desc,omitempty"` + + // Flag indicating whether security groups are enabled for this network + // Required: false + EnableSecGroups interface{} `url:"enable_secgroups,omitempty" json:"enable_secgroups,omitempty" validate:"omitempty,isBool"` +} + +// Update updates a vins parameters +func (v VINS) Update(ctx context.Context, req UpdateRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/vins/update" + + res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil + +} diff --git a/pkg/cloudbroker/zone/models.go b/pkg/cloudbroker/zone/models.go index b2340ca..110f9f9 100644 --- a/pkg/cloudbroker/zone/models.go +++ b/pkg/cloudbroker/zone/models.go @@ -22,12 +22,30 @@ type RecordZone struct { // Name Name string `json:"name"` + // List of associated account IDs + AccountIDs []uint64 `json:"accountIds"` + + // List of associated bservice IDs + BserviceIDs []uint64 `json:"bserviceIds"` + + // List of associated compute IDs + ComputeIDs []uint64 `json:"computeIds"` + // Description Description string `json:"description"` // Deletable flag Deletable bool `json:"deletable"` + // List of associated ExtNet IDs + ExtnetIDs []uint64 `json:"extnetIds"` + + // List of associated K8s IDs + K8SIDs []uint64 `json:"k8sIds"` + + // List of associated LB IDs + LBIDs []uint64 `json:"lbIds"` + // Status Status string `json:"status"` @@ -39,4 +57,7 @@ type RecordZone struct { // List of associated Node IDs NodeIDs []uint64 `json:"nodeIds"` + + // List of associated VINS IDs + VinsIDs []uint64 `json:"vinsIds"` } diff --git a/pkg/sdn/access_groups.go b/pkg/sdn/access_groups.go new file mode 100644 index 0000000..4b0e83f --- /dev/null +++ b/pkg/sdn/access_groups.go @@ -0,0 +1,10 @@ +package sdn + +import ( + ag "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/sdn/acsgroups" +) + +// Accessing the SDN method group +func (sdn *SDN) AccessGroups() *ag.AccessGroups { + return ag.New(sdn.client) +} diff --git a/pkg/sdn/acsgroups/access_groups.go b/pkg/sdn/acsgroups/access_groups.go new file mode 100644 index 0000000..458ec4b --- /dev/null +++ b/pkg/sdn/acsgroups/access_groups.go @@ -0,0 +1,18 @@ +// API Actor API for managing SDN access groups +package acsgroups + +import ( + "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" +) + +// Structure for creating request to access groups +type AccessGroups struct { + client interfaces.Caller +} + +// Builder for access groups endpoints +func New(client interfaces.Caller) *AccessGroups { + return &AccessGroups{ + client, + } +} diff --git a/pkg/sdn/acsgroups/create.go b/pkg/sdn/acsgroups/create.go new file mode 100644 index 0000000..a197e8d --- /dev/null +++ b/pkg/sdn/acsgroups/create.go @@ -0,0 +1,45 @@ +package acsgroups + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// CreateRequest struct to create access group +type CreateRequest struct { + // Comment of the access group + // Required: true + Comment string `url:"comment" json:"comment" validate:"required"` + + // Name of acces group + // Required: true + DisplayName string `url:"display_name" json:"display_name" validate:"required"` +} + +// Create creates a access groups +func (i AccessGroups) Create(ctx context.Context, req CreateRequest) (*AccessGroupItem, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/sdn/access_group/create" + + res, err := i.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) + if err != nil { + return nil, err + } + + info := AccessGroupItem{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/sdn/acsgroups/delete.go b/pkg/sdn/acsgroups/delete.go new file mode 100644 index 0000000..7915e9f --- /dev/null +++ b/pkg/sdn/acsgroups/delete.go @@ -0,0 +1,39 @@ +package acsgroups + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DeleteRequest struct to delete access group +type DeleteRequest struct { + // Comment of the access group + // Required: true + GroupID string `url:"access_group_id" json:"access_group_id" validate:"required"` +} + +// Delete a access groups +func (i AccessGroups) Delete(ctx context.Context, req DeleteRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/sdn/access_group/delete" + + res, err := i.client.DecortApiCallCtype(ctx, http.MethodDelete, url, constants.MIMEJSON, req) + if err != nil { + return false, err + } + + result, err := strconv.ParseBool(string(res)) + if err != nil { + return false, err + } + + return result, nil +} diff --git a/pkg/sdn/acsgroups/filter.go b/pkg/sdn/acsgroups/filter.go new file mode 100644 index 0000000..2ac4355 --- /dev/null +++ b/pkg/sdn/acsgroups/filter.go @@ -0,0 +1,42 @@ +package acsgroups + +// FilterByID returns AccessGroupList with specified ID. +func (agl AccessGroupList) FilterByID(id string) AccessGroupList { + predicate := func(ia AccessGroup) bool { + return ia.ID == id + } + + return agl.FilterFunc(predicate) +} + +// FilterByName returns AccessGroupList with specified Name. +func (agl AccessGroupList) FilterByName(name string) AccessGroupList { + predicate := func(ia AccessGroup) bool { + return ia.DisplayName == name + } + + return agl.FilterFunc(predicate) +} + +// FilterFunc allows filtering AccessGroupList based on a user-specified predicate. +func (agl AccessGroupList) FilterFunc(predicate func(AccessGroup) bool) AccessGroupList { + var result AccessGroupList + + for _, acc := range agl.AccessGroups { + if predicate(acc) { + result.AccessGroups = append(result.AccessGroups, acc) + } + } + + return result +} + +// FindOne returns first element. +// If none was found, returns an empty struct. +func (agl AccessGroupList) FindOne() AccessGroup { + if len(agl.AccessGroups) == 0 { + return AccessGroup{} + } + + return agl.AccessGroups[0] +} diff --git a/pkg/sdn/acsgroups/filter_test.go b/pkg/sdn/acsgroups/filter_test.go new file mode 100644 index 0000000..bb55a21 --- /dev/null +++ b/pkg/sdn/acsgroups/filter_test.go @@ -0,0 +1,89 @@ +package acsgroups + +import ( + "testing" +) + +var testAccessGroups = AccessGroupList{ + AccessGroups: []AccessGroup{ + { + ID: "group1", + DisplayName: "Developers", + Comment: "First group", + CreatedAt: "2023-01-01", + CreatedBy: "admin", + }, + { + ID: "group2", + DisplayName: "Admins", + Comment: "Second group", + CreatedAt: "2023-01-02", + CreatedBy: "admin", + }, + { + ID: "group3", + DisplayName: "Users", + Comment: "Third group", + CreatedAt: "2023-01-03", + CreatedBy: "admin", + }, + }, +} + +func TestFilterByID(t *testing.T) { + actual := testAccessGroups.FilterByID("group2").FindOne() + + if actual.ID != "group2" { + t.Fatal("actual:", actual.ID, "> expected: group2") + } +} + +func TestFilterByName(t *testing.T) { + actual := testAccessGroups.FilterByName("Users").FindOne() + + if actual.DisplayName != "Users" { + t.Fatal("actual:", actual.DisplayName, ">> expected: Users") + } +} + +func TestFilterFunc(t *testing.T) { + actual := testAccessGroups.FilterFunc(func(ag AccessGroup) bool { + return ag.Comment == "Second group" + }) + + if len(actual.AccessGroups) != 1 || actual.AccessGroups[0].ID != "group2" { + t.Fatal("Expected 1 group with comment 'Second group', found:", len(actual.AccessGroups)) + } +} + +func TestFindOneWithResults(t *testing.T) { + result := testAccessGroups.FilterByID("group1").FindOne() + if result.ID != "group1" { + t.Fatal("Expected group1, got:", result.ID) + } +} + +func TestFindOneEmpty(t *testing.T) { + emptyList := AccessGroupList{} + result := emptyList.FindOne() + + if result.ID != "" || result.DisplayName != "" { + t.Fatal("Expected empty AccessGroup, got:", result) + } +} + +func TestFilterByIDNotFound(t *testing.T) { + actual := testAccessGroups.FilterByID("nonexistent") + + if len(actual.AccessGroups) != 0 { + t.Fatal("Expected 0 groups, found:", len(actual.AccessGroups)) + } +} + +func TestFilterByNameNotFound(t *testing.T) { + actual := testAccessGroups.FilterByName("Nonexistent Group") + + if len(actual.AccessGroups) != 0 { + t.Fatal("Expected 0 groups, found:", len(actual.AccessGroups)) + } +} diff --git a/pkg/sdn/acsgroups/ids.go b/pkg/sdn/acsgroups/ids.go new file mode 100644 index 0000000..1c925e8 --- /dev/null +++ b/pkg/sdn/acsgroups/ids.go @@ -0,0 +1,19 @@ +package acsgroups + +// IDs gets array of IDs from AccessGroupList struct +func (agl AccessGroupList) IDs() []string { + res := make([]string, 0, len(agl.AccessGroups)) + for _, c := range agl.AccessGroups { + res = append(res, c.ID) + } + return res +} + +// IDs gets array of IDs from UsersList struct +func (ul UsersList) IDs() []string { + res := make([]string, 0, len(ul.Users)) + for _, c := range ul.Users { + res = append(res, c.ID) + } + return res +} diff --git a/pkg/sdn/acsgroups/list.go b/pkg/sdn/acsgroups/list.go new file mode 100644 index 0000000..38f82b2 --- /dev/null +++ b/pkg/sdn/acsgroups/list.go @@ -0,0 +1,80 @@ +package acsgroups + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ListGroupsRequest struct to get a list of access groups +type ListGroupsRequest struct { + // Find by enabled status, true or false + // Required: false + Enabled interface{} `url:"enabled,omitempty" json:"enabled,omitempty" validate:"omitempty,isBool"` + + // Find by deleted status, true or false + // Required: false + Deleted interface{} `url:"deleted,omitempty" json:"deleted,omitempty" validate:"omitempty,isBool"` + + // Display name filter + // Required: false + DisplayName string `url:"display_name,omitempty" json:"display_name,omitempty"` + + // Page number for pagination + // Required: false + Page uint64 `url:"page,omitempty" json:"page,omitempty"` + + // Number of results per page + // Required: false + PerPage uint64 `url:"per_page,omitempty" json:"per_page,omitempty"` + + // Field to sort by (display_name, created_at, updated_at, deleted_at, owner_login) + // Required: false + SortBy string `url:"sort_by,omitempty" json:"sort_by,omitempty"` + + // Sort order (asc/desc) + // Required: false + SortOrder string `url:"sort_order,omitempty" json:"sort_order,omitempty"` + + // Creation date lower bound (inclusive) + // Required: false + CreatedFrom string `url:"created_from,omitempty" json:"created_from,omitempty"` + + // Creation date upper bound (inclusive) + // Required: false + CreatedTo string `url:"created_to,omitempty" json:"created_to,omitempty"` +} + +// List of access groups +func (i AccessGroups) List(ctx context.Context, req ListGroupsRequest) (*AccessGroupList, error) { + res, err := i.ListRaw(ctx, req) + if err != nil { + return nil, err + } + + groups := []AccessGroup{} + + err = json.Unmarshal(res, &groups) + if err != nil { + return nil, err + } + + result := AccessGroupList{AccessGroups: groups} + + return &result, nil +} + +// ListRaw gets a list of all users as an array of bytes +func (a AccessGroups) ListRaw(ctx context.Context, req ListGroupsRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/sdn/access_group/list" + + res, err := a.client.DecortApiCall(ctx, http.MethodGet, url, req) + return res, err +} diff --git a/pkg/sdn/acsgroups/models.go b/pkg/sdn/acsgroups/models.go new file mode 100644 index 0000000..fb70f4a --- /dev/null +++ b/pkg/sdn/acsgroups/models.go @@ -0,0 +1,49 @@ +package acsgroups + +type AccessGroupItem struct { + Name string `json:"display_name"` + ID string `json:"id"` +} + +type AccessGroupList struct { + AccessGroups []AccessGroup +} + +type AccessGroup struct { + ID string `json:"id"` + DisplayName string `json:"display_name"` + Comment string `json:"comment"` + CreatedAt string `json:"created_at"` + CreatedBy string `json:"created_by"` + UpdatedAt string `json:"updated_at"` + UpdatedBy string `json:"updated_by"` + NetObjectAccessGroup NetObjectAccessGroup `json:"net_object_access_group"` + DefaultSecurityPolicy DefaultSecurityPolicy `json:"default_security_policy"` +} + +type NetObjectAccessGroup struct { + ID string `json:"id"` + VersionID int64 `json:"version_id"` + AccessGroupID string `json:"access_group_id"` +} + +type DefaultSecurityPolicy struct { + ID string `json:"id"` + DisplayName string `json:"display_name"` + Description string `json:"description"` + VersionID int64 `json:"version_id"` + AccessGroupID string `json:"access_group_id"` + DefaultAclDrop string `json:"default_acl_drop"` + DefaultOpenSessionDrop bool `json:"default_open_session_drop"` +} + +type User struct { + Name string `json:"display_name"` + ID string `json:"id"` + RoleID string `json:"role_id"` + Login string `json:"login"` +} + +type UsersList struct { + Users []User +} diff --git a/pkg/sdn/acsgroups/path.go b/pkg/sdn/acsgroups/path.go new file mode 100644 index 0000000..d0318cd --- /dev/null +++ b/pkg/sdn/acsgroups/path.go @@ -0,0 +1,49 @@ +package acsgroups + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// PatchRequest struct to update access group +type PatchRequest struct { + // Access group ID + // Required: true + AccessGroupID string `url:"access_group_id" json:"access_group_id" validate:"required"` + + // Comment of the acces group + // Required: false + Comment string `url:"comment,omitempty" json:"comment,omitempty"` + + // Name of acces group + // Required: false + DisplayName string `url:"display_name,omitempty" json:"display_name,omitempty"` +} + +// Update updates a access groups +func (i AccessGroups) Patch(ctx context.Context, req PatchRequest) (*AccessGroup, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/sdn/access_group/patch" + + res, err := i.client.DecortApiCallCtype(ctx, http.MethodPatch, url, constants.MIMEJSON, req) + if err != nil { + return nil, err + } + + info := AccessGroup{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/sdn/acsgroups/user_add.go b/pkg/sdn/acsgroups/user_add.go new file mode 100644 index 0000000..dd7b46e --- /dev/null +++ b/pkg/sdn/acsgroups/user_add.go @@ -0,0 +1,41 @@ +package acsgroups + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// UserAddRequest struct to userAdd access group +type UserAddRequest struct { + // Comment of the access group + // Required: true + GroupID string `url:"access_group_id" json:"access_group_id" validate:"required"` + + // Access group role ID + // Required: true + AccessGroupRoleID string `url:"access_group_role_id" json:"access_group_role_id" validate:"required"` + + // User ID + // Required: true + UserID string `url:"user_id" json:"user_id" validate:"required"` +} + +// UserAdd a access groups +func (i AccessGroups) UserAdd(ctx context.Context, req UserAddRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/sdn/access_group/user_add" + + _, err = i.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req) + if err != nil { + return false, err + } + + return true, nil +} diff --git a/pkg/sdn/acsgroups/user_delete.go b/pkg/sdn/acsgroups/user_delete.go new file mode 100644 index 0000000..546d48b --- /dev/null +++ b/pkg/sdn/acsgroups/user_delete.go @@ -0,0 +1,37 @@ +package acsgroups + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// UserDeleteRequest struct to userDelete access group +type UserDeleteRequest struct { + // Comment of the access group + // Required: true + GroupID string `url:"access_group_id" json:"access_group_id" validate:"required"` + + // User ID + // Required: true + UserID string `url:"user_id" json:"user_id" validate:"required"` +} + +// UserDelete a access groups +func (i AccessGroups) UserDelete(ctx context.Context, req UserDeleteRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/sdn/access_group/user_delete" + + _, err = i.client.DecortApiCallCtype(ctx, http.MethodDelete, url, constants.MIMEJSON, req) + if err != nil { + return false, err + } + + return true, nil +} diff --git a/pkg/sdn/acsgroups/user_list.go b/pkg/sdn/acsgroups/user_list.go new file mode 100644 index 0000000..6b9d2a5 --- /dev/null +++ b/pkg/sdn/acsgroups/user_list.go @@ -0,0 +1,113 @@ +package acsgroups + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// UsersListRequest struct to get a list of users +type UsersListRequest struct { + // Access group identifier + // Required: true + AccessGroupID string `url:"access_group_id" json:"access_group_id" validate:"required"` + + // Filter by global role + // Required: false + GlobalRole string `url:"global_role,omitempty" json:"global_role,omitempty"` + + // Filter by access group role + // Required: false + AccessGroupRole string `url:"access_group_role,omitempty" json:"access_group_role,omitempty"` + + // Filter by enabled status (true/false) + // Required: false + Enabled interface{} `url:"enabled,omitempty" json:"enabled,omitempty" validate:"omitempty,isBool"` + + // Filter by deleted status (true/false) + // Required: false + Deleted interface{} `url:"deleted,omitempty" json:"deleted,omitempty" validate:"omitempty,isBool"` + + // Filter by display name + // Required: false + DisplayName string `url:"display_name,omitempty" json:"display_name,omitempty"` + + // Filter by user login + // Required: false + Login string `url:"login,omitempty" json:"login,omitempty"` + + // Filter by creator login + // Required: false + CreatedBy string `url:"created_by,omitempty" json:"created_by,omitempty"` + + // Filter by last updater login + // Required: false + UpdatedBy string `url:"updated_by,omitempty" json:"updated_by,omitempty"` + + // Filter by deleter login + // Required: false + DeletedBy string `url:"deleted_by,omitempty" json:"deleted_by,omitempty"` + + // Filter by disabler login + // Required: false + DisabledBy string `url:"disabled_by,omitempty" json:"disabled_by,omitempty"` + + // Page number for pagination + // Required: false + Page uint64 `url:"page,omitempty" json:"page,omitempty"` + + // Number of results per page + // Required: false + PerPage uint64 `url:"per_page,omitempty" json:"per_page,omitempty"` + + // Field to sort by (display_name, email, phone, created_at, updated_at, deleted_at) + // Required: false + SortBy string `url:"sort_by,omitempty" json:"sort_by,omitempty"` + + // Sort order (asc/desc) + // Required: false + SortOrder string `url:"sort_order,omitempty" json:"sort_order,omitempty"` + + // Creation date lower bound (inclusive) + // Required: false + CreatedFrom string `url:"created_from,omitempty" json:"created_from,omitempty"` + + // Creation date upper bound (exclusive) + // Required: false + CreatedTo string `url:"created_to,omitempty" json:"created_to,omitempty"` +} + +// List of access groups +func (i AccessGroups) UsersList(ctx context.Context, req UsersListRequest) (*UsersList, error) { + + res, err := i.UserListRaw(ctx, req) + if err != nil { + return nil, err + } + + users := []User{} + + err = json.Unmarshal(res, &users) + if err != nil { + return nil, err + } + + result := UsersList{Users: users} + + return &result, nil +} + +// ListRaw gets a list of all users as an array of bytes +func (a AccessGroups) UserListRaw(ctx context.Context, req UsersListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/sdn/access_group/user_list" + + res, err := a.client.DecortApiCall(ctx, http.MethodGet, url, req) + return res, err +} diff --git a/pkg/sdn/acsgroups/user_update_role.go b/pkg/sdn/acsgroups/user_update_role.go new file mode 100644 index 0000000..4f20c15 --- /dev/null +++ b/pkg/sdn/acsgroups/user_update_role.go @@ -0,0 +1,41 @@ +package acsgroups + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// UserUpdateRoleRequest struct to userUpdateRole access group +type UserUpdateRoleRequest struct { + // Comment of the access group + // Required: true + GroupID string `url:"access_group_id" json:"access_group_id" validate:"required"` + + // Access group role ID + // Required: true + AccessGroupRoleID string `url:"access_group_role_id" json:"access_group_role_id" validate:"required"` + + // User ID + // Required: true + UserID string `url:"user_id" json:"user_id" validate:"required"` +} + +// UserUpdateRole a access groups +func (i AccessGroups) UserUpdateRole(ctx context.Context, req UserUpdateRoleRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/sdn/access_group/update_role" + + _, err = i.client.DecortApiCallCtype(ctx, http.MethodPut, url, constants.MIMEJSON, req) + if err != nil { + return false, err + } + + return true, nil +} diff --git a/pkg/sdn/sdn.go b/pkg/sdn/sdn.go new file mode 100644 index 0000000..8017495 --- /dev/null +++ b/pkg/sdn/sdn.go @@ -0,0 +1,16 @@ +// List of method groups for the SDN +package sdn + +import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" + +// Structure for creating request to SDN groups +type SDN struct { + client interfaces.Caller +} + +// Builder to get access to SDN +func New(client interfaces.Caller) *SDN { + return &SDN{ + client: client, + } +} diff --git a/tests/platform_upgrade/cloud_test.go b/tests/platform_upgrade/cloud_test.go index c14ca90..ef6a63c 100644 --- a/tests/platform_upgrade/cloud_test.go +++ b/tests/platform_upgrade/cloud_test.go @@ -17,12 +17,15 @@ import ( "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/lb" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/locations" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/rg" + securitygroup "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/security_group" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/sep" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/stack" + storagepolicy "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/storage_policy" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/tasks" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/trunk" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/vins" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/zone" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/sdn/acsgroups" account_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/account" audit_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/audit" @@ -39,8 +42,10 @@ import ( node_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/node" pcidevice_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/pcidevice" rg_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/rg" + securitygroup_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/security_group" sep_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/sep" stack_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/stack" + storagepolicy_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/storage_policy" tasks_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/tasks" trunk_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/trunk" vins_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/vins" @@ -301,6 +306,46 @@ func TestGetListCloudAPI(t *testing.T) { } getResult("Stack list", bytes, stack.ListStacks{}, t) + // Storage policy + // List + bytes, err = client.CloudAPI().StoragePolicy().ListRaw(context.Background(), storagepolicy.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Storage policy list", bytes, storagepolicy.ListStoragePolicies{}, t) + // Get + listStoragePolicies, _ := client.CloudAPI().StoragePolicy().List(context.Background(), storagepolicy.ListRequest{}) + if len(listStoragePolicies.Data) > 0 { + id := listStoragePolicies.Data[0].ID + bytes, err = client.CloudAPI().StoragePolicy().GetRaw(context.Background(), storagepolicy.GetRequest{StoragePolicyID: id}) + if err != nil { + t.Error(err) + } + getResult("Storage policy get", bytes, storagepolicy.InfoStoragePolicy{}, t) + } else { + t.Errorf("Can not test Storage policy get because Storage policy list is empty") + } + + // Security group + // List + bytes, err = client.CloudAPI().SecurityGroup().ListRaw(context.Background(), securitygroup.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Security group list", bytes, securitygroup.ListSecurityGroups{}, t) + // Get + listSecurityGroups, _ := client.CloudAPI().SecurityGroup().List(context.Background(), securitygroup.ListRequest{}) + if len(listSecurityGroups.Data) > 0 { + id := listSecurityGroups.Data[0].ID + bytes, err = client.CloudAPI().SecurityGroup().GetRaw(context.Background(), securitygroup.GetRequest{SecurityGroupID: id}) + if err != nil { + t.Error(err) + } + getResult("Security group get", bytes, securitygroup.RecordSecurityGroup{}, t) + } else { + t.Errorf("Can not test Security group get because Security group list is empty") + } + // Tasks // List bytes, err = client.CloudAPI().Tasks().ListRaw(context.Background(), tasks.ListRequest{}) @@ -681,6 +726,26 @@ func TestGetListCloudbroker(t *testing.T) { t.Errorf("Can not test RG get because RG list is empty") } + // Security group + // List + bytes, err = client.CloudBroker().SecurityGroup().ListRaw(context.Background(), securitygroup_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Security group list", bytes, securitygroup_cb.ListSecurityGroups{}, t) + // Get + listSecurityGroups, _ := client.CloudBroker().SecurityGroup().List(context.Background(), securitygroup_cb.ListRequest{}) + if len(listSecurityGroups.Data) > 0 { + id := listSecurityGroups.Data[0].ID + bytes, err = client.CloudBroker().SecurityGroup().GetRaw(context.Background(), securitygroup_cb.GetRequest{SecurityGroupID: id}) + if err != nil { + t.Error(err) + } + getResult("Security group get", bytes, securitygroup_cb.RecordSecurityGroup{}, t) + } else { + t.Errorf("Can not test Security group get because Security group list is empty") + } + // SEP // List bytes, err = client.CloudBroker().SEP().ListRaw(context.Background(), sep_cb.ListRequest{}) @@ -727,6 +792,26 @@ func TestGetListCloudbroker(t *testing.T) { t.Errorf("Can not test Stack get because Stack list is empty") } + // Storage policy + // List + bytes, err = client.CloudBroker().StoragePolicy().ListRaw(context.Background(), storagepolicy_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Storage policy list", bytes, storagepolicy_cb.ListStoragePolicies{}, t) + // Get + listStoragePolicies, _ := client.CloudBroker().StoragePolicy().List(context.Background(), storagepolicy_cb.ListRequest{}) + if len(listStoragePolicies.Data) > 0 { + id := listStoragePolicies.Data[0].ID + bytes, err = client.CloudBroker().StoragePolicy().GetRaw(context.Background(), storagepolicy_cb.GetRequest{StoragePolicyID: id}) + if err != nil { + t.Error(err) + } + getResult("Storage policy get", bytes, storagepolicy_cb.InfoStoragePolicy{}, t) + } else { + t.Errorf("Can not test Storage policy get because Storage policy list is empty") + } + // Tasks // List bytes, err = client.CloudBroker().Tasks().ListRaw(context.Background(), tasks_cb.ListRequest{}) @@ -796,6 +881,40 @@ func TestGetListCloudbroker(t *testing.T) { } } +// TestGetListSDNAPI tests platforms responses vs. json tags of golang structures in cloudapi get/list methods +func TestGetListSDNAPI(t *testing.T) { + var bytes []byte + var err error + client, err := getClient() + if err != nil { + t.Fatalf("Cannot get client: %v", err) + } + + // AccessGroups + // List + bytes, err = client.SDN().AccessGroups().ListRaw(context.Background(), acsgroups.ListGroupsRequest{}) + if err != nil { + t.Error(err) + } + + getResult("access groups list", bytes, acsgroups.AccessGroup{}, t) + + // Users AccessGroups + // list + listAcsGroups, _ := client.SDN().AccessGroups().List(context.Background(), acsgroups.ListGroupsRequest{}) + if len(listAcsGroups.AccessGroups) > 0 { + id := listAcsGroups.AccessGroups[0].ID + bytes, err = client.SDN().AccessGroups().UserListRaw(context.Background(), acsgroups.UsersListRequest{AccessGroupID: id}) + if err != nil { + t.Error(err) + } + getResult("access groups users list", bytes, acsgroups.User{}, t) + } else { + t.Errorf("Can not test users get because acs groups list is empty") + } + +} + // TestRequestsCloudAPI tests platform requests vs. golang request structures in sdk for cloudapi requests func TestRequestsCloudAPI(t *testing.T) { bytes := getBytesFromJSON("input.json", t) @@ -808,6 +927,11 @@ func TestRequestsCloudbroker(t *testing.T) { getErrorsFromJSON(bytes, t, "cloudbroker") } +func TestRequestsSDN(t *testing.T) { + bytes := getBytesFromJSON("input.json", t) + getErrorsFromJSON(bytes, t, "sdn") +} + // TestGetAllPaths tests if platform has any handlers that golang sdk doesn't. In this case, list of missing handlers is provided. // Note that DEPRECATED_GROUPS stores list of groups that are considered deprecated. You can add additional grops to DEPRECATED_GROUPS if required. func TestGetAllPaths(t *testing.T) { @@ -839,8 +963,9 @@ func TestGetAllPaths(t *testing.T) { caTestUrls := getRequestsMapCloudAPI() cbTestUrls := getRequestsMapCloudbroker() + sdnTestUrls := getRequestsMapSDN() - urlsInTest := make([]string, len(caTestUrls)+len(cbTestUrls)) + urlsInTest := make([]string, len(caTestUrls)+len(cbTestUrls)+len(sdnTestUrls)) i := 0 for k := range caTestUrls { @@ -851,6 +976,10 @@ func TestGetAllPaths(t *testing.T) { urlsInTest[i] = k i++ } + for k := range sdnTestUrls { + urlsInTest[i] = k + i++ + } missingUrls = getMissingDecortUrls(jsonUrls, urlsInTest) if len(missingUrls) > 0 { diff --git a/tests/platform_upgrade/request_map.go b/tests/platform_upgrade/request_map.go index 5526088..f6af4cc 100644 --- a/tests/platform_upgrade/request_map.go +++ b/tests/platform_upgrade/request_map.go @@ -18,14 +18,17 @@ import ( "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/pcidevice" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/prometheus" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/rg" + securitygroup "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/security_group" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/sep" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/stack" + storagepolicy "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/storage_policy" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/tasks" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/trunk" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/user" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/vfpool" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/vins" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/zone" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/sdn/acsgroups" account_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/account" apiaccess_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/apiaccess" @@ -47,8 +50,10 @@ import ( pcidevice_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/pcidevice" prometheus_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/prometheus" rg_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/rg" + securitygroup_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/security_group" sep_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/sep" stack_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/stack" + storagepolicy_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/storage_policy" tasks_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/tasks" trunk_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/trunk" user_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/user" @@ -141,6 +146,7 @@ func getRequestsMapCloudAPI() map[string]interface{} { "/restmachine/cloudapi/compute/cdEject": compute.CDEjectRequest{}, "/restmachine/cloudapi/compute/cdInsert": compute.CDInsertRequest{}, "/restmachine/cloudapi/compute/changeLinkState": compute.ChangeLinkStateRequest{}, + "/restmachine/cloudapi/compute/change_security_groups": compute.ChangeSecGroupsRequest{}, "/restmachine/cloudapi/compute/clone": compute.CloneRequest{}, "/restmachine/cloudapi/compute/createTemplate": compute.CreateTemplateRequest{}, "/restmachine/cloudapi/compute/createTemplateFromBlank": compute.CreateTemplateFromBlankRequest{}, @@ -207,31 +213,32 @@ func getRequestsMapCloudAPI() map[string]interface{} { "/restmachine/cloudapi/compute/guest_agent_feature_update": compute.GuestAgentFeatureUpdateRequest{}, // disks - "/restmachine/cloudapi/disks/create": disks.CreateRequest{}, - "/restmachine/cloudapi/disks/delete": disks.DeleteRequest{}, - "/restmachine/cloudapi/disks/deleteDisks": disks.DisksDeleteRequest{}, - "/restmachine/cloudapi/disks/fromPlatformDisk": disks.FromPlatformDiskRequest{}, - "/restmachine/cloudapi/disks/get": disks.GetRequest{}, - "/restmachine/cloudapi/disks/limitIO": disks.LimitIORequest{}, - "/restmachine/cloudapi/disks/list": disks.ListRequest{}, - "/restmachine/cloudapi/disks/listDeleted": disks.ListDeletedRequest{}, - "/restmachine/cloudapi/disks/listTypes": disks.ListTypesRequest{}, - "/restmachine/cloudapi/disks/listUnattached": disks.ListUnattachedRequest{}, - "/restmachine/cloudapi/disks/rename": disks.RenameRequest{}, - "/restmachine/cloudapi/disks/replicate": disks.ReplicateRequest{}, - "/restmachine/cloudapi/disks/replicationResume": disks.ReplicationResumeRequest{}, - "/restmachine/cloudapi/disks/replicationReverse": disks.ReplicationReverseRequest{}, - "/restmachine/cloudapi/disks/replicationStart": disks.ReplicationStartRequest{}, - "/restmachine/cloudapi/disks/replicationStatus": disks.ReplicationStatusRequest{}, - "/restmachine/cloudapi/disks/replicationStop": disks.ReplicationStopRequest{}, - "/restmachine/cloudapi/disks/replicationSuspend": disks.ReplicationSuspendRequest{}, - "/restmachine/cloudapi/disks/resize2": disks.ResizeRequest{}, - "/restmachine/cloudapi/disks/restore": disks.RestoreRequest{}, - "/restmachine/cloudapi/disks/search": disks.SearchRequest{}, - "/restmachine/cloudapi/disks/share": disks.ShareRequest{}, - "/restmachine/cloudapi/disks/snapshotDelete": disks.SnapshotDeleteRequest{}, - "/restmachine/cloudapi/disks/snapshotRollback": disks.SnapshotRollbackRequest{}, - "/restmachine/cloudapi/disks/unshare": disks.UnshareRequest{}, + "/restmachine/cloudapi/disks/change_disk_storage_policy": disks.ChangeDiskStoragePolicyRequest{}, + "/restmachine/cloudapi/disks/create": disks.CreateRequest{}, + "/restmachine/cloudapi/disks/delete": disks.DeleteRequest{}, + "/restmachine/cloudapi/disks/deleteDisks": disks.DisksDeleteRequest{}, + "/restmachine/cloudapi/disks/fromPlatformDisk": disks.FromPlatformDiskRequest{}, + "/restmachine/cloudapi/disks/get": disks.GetRequest{}, + "/restmachine/cloudapi/disks/limitIO": disks.LimitIORequest{}, + "/restmachine/cloudapi/disks/list": disks.ListRequest{}, + "/restmachine/cloudapi/disks/listDeleted": disks.ListDeletedRequest{}, + "/restmachine/cloudapi/disks/listTypes": disks.ListTypesRequest{}, + "/restmachine/cloudapi/disks/listUnattached": disks.ListUnattachedRequest{}, + "/restmachine/cloudapi/disks/rename": disks.RenameRequest{}, + "/restmachine/cloudapi/disks/replicate": disks.ReplicateRequest{}, + "/restmachine/cloudapi/disks/replicationResume": disks.ReplicationResumeRequest{}, + "/restmachine/cloudapi/disks/replicationReverse": disks.ReplicationReverseRequest{}, + "/restmachine/cloudapi/disks/replicationStart": disks.ReplicationStartRequest{}, + "/restmachine/cloudapi/disks/replicationStatus": disks.ReplicationStatusRequest{}, + "/restmachine/cloudapi/disks/replicationStop": disks.ReplicationStopRequest{}, + "/restmachine/cloudapi/disks/replicationSuspend": disks.ReplicationSuspendRequest{}, + "/restmachine/cloudapi/disks/resize2": disks.ResizeRequest{}, + "/restmachine/cloudapi/disks/restore": disks.RestoreRequest{}, + "/restmachine/cloudapi/disks/search": disks.SearchRequest{}, + "/restmachine/cloudapi/disks/share": disks.ShareRequest{}, + "/restmachine/cloudapi/disks/snapshotDelete": disks.SnapshotDeleteRequest{}, + "/restmachine/cloudapi/disks/snapshotRollback": disks.SnapshotRollbackRequest{}, + "/restmachine/cloudapi/disks/unshare": disks.UnshareRequest{}, //dpdknet "/restmachine/cloudapi/dpdknet/get": dpdknet.GetRequest{}, @@ -254,13 +261,14 @@ func getRequestsMapCloudAPI() map[string]interface{} { "/restmachine/cloudapi/flipgroup/list": flipgroup.ListRequest{}, // image - "/restmachine/cloudapi/image/create": image.CreateRequest{}, - "/restmachine/cloudapi/image/createVirtual": image.CreateVirtualRequest{}, - "/restmachine/cloudapi/image/delete": image.DeleteRequest{}, - "/restmachine/cloudapi/image/get": image.GetRequest{}, - "/restmachine/cloudapi/image/link": image.LinkRequest{}, - "/restmachine/cloudapi/image/list": image.ListRequest{}, - "/restmachine/cloudapi/image/rename": image.RenameRequest{}, + "/restmachine/cloudapi/image/change_storage_policy": image.ChangeStoragePolicyRequest{}, + "/restmachine/cloudapi/image/create": image.CreateRequest{}, + "/restmachine/cloudapi/image/createVirtual": image.CreateVirtualRequest{}, + "/restmachine/cloudapi/image/delete": image.DeleteRequest{}, + "/restmachine/cloudapi/image/get": image.GetRequest{}, + "/restmachine/cloudapi/image/link": image.LinkRequest{}, + "/restmachine/cloudapi/image/list": image.ListRequest{}, + "/restmachine/cloudapi/image/rename": image.RenameRequest{}, // k8ci, k8s "/restmachine/cloudapi/k8ci/get": k8ci.GetRequest{}, @@ -375,6 +383,15 @@ func getRequestsMapCloudAPI() map[string]interface{} { "/restmachine/cloudapi/rg/usage": rg.UsageRequest{}, "/restmachine/cloudapi/rg/removeDefNet": rg.RemoveDefNetRequest{}, + // security_group + "/restmachine/cloudapi/security_group/create": securitygroup.CreateRequest{}, + "/restmachine/cloudapi/security_group/create_rule": securitygroup.CreateRuleRequest{}, + "/restmachine/cloudapi/security_group/delete": securitygroup.DeleteRequest{}, + "/restmachine/cloudapi/security_group/delete_rule": securitygroup.DeleteRuleRequest{}, + "/restmachine/cloudapi/security_group/get": securitygroup.GetRequest{}, + "/restmachine/cloudapi/security_group/list": securitygroup.ListRequest{}, + "/restmachine/cloudapi/security_group/update": securitygroup.UpdateRequest{}, + // sep "/restmachine/cloudapi/sep/listAvailableSepAndPools": sep.ListAvailableSEPAndPoolsRequest{}, @@ -384,6 +401,10 @@ func getRequestsMapCloudAPI() map[string]interface{} { "/restmachine/cloudapi/tasks/get": tasks.GetRequest{}, "/restmachine/cloudapi/tasks/list": tasks.ListRequest{}, + // storage policy + "/restmachine/cloudapi/storage_policy/get": storagepolicy.GetRequest{}, + "/restmachine/cloudapi/storage_policy/list": storagepolicy.ListRequest{}, + // trunk "/restmachine/cloudapi/trunk/get": trunk.GetRequest{}, "/restmachine/cloudapi/trunk/list": trunk.ListRequest{}, @@ -442,8 +463,10 @@ func getRequestsMapCloudbroker() map[string]interface{} { return map[string]interface{}{ // account_cb "/restmachine/cloudbroker/account/addUser": account_cb.AddUserRequest{}, + "/restmachine/cloudbroker/account/add_storage_policy": account_cb.AddStoragePolicyRequest{}, "/restmachine/cloudbroker/account/audits": account_cb.AuditsRequest{}, "/restmachine/cloudbroker/account/create": account_cb.CreateRequest{}, + "/restmachine/cloudbroker/account/del_storage_policy": account_cb.DelStoragePolicyRequest{}, "/restmachine/cloudbroker/account/delete": account_cb.DeleteRequest{}, "/restmachine/cloudbroker/account/deleteAccounts": account_cb.DeleteAccountsRequest{}, "/restmachine/cloudbroker/account/deleteUser": account_cb.DeleteUserRequest{}, @@ -527,6 +550,7 @@ func getRequestsMapCloudbroker() map[string]interface{} { "/restmachine/cloudbroker/compute/cdInsert": compute_cb.CDInsertRequest{}, "/restmachine/cloudbroker/compute/changeLinkState": compute_cb.ChangeLinkStateRequest{}, "/restmachine/cloudbroker/compute/change_mtu": compute_cb.ChangeMTURequest{}, + "/restmachine/cloudbroker/compute/change_security_groups": compute_cb.ChangeSecGroupsRequest{}, "/restmachine/cloudbroker/compute/clone": compute_cb.CloneRequest{}, "/restmachine/cloudbroker/compute/computeciSet": compute_cb.ComputeCISetRequest{}, "/restmachine/cloudbroker/compute/computeciUnset": compute_cb.ComputeCIUnsetRequest{}, @@ -608,33 +632,34 @@ func getRequestsMapCloudbroker() map[string]interface{} { "/restmachine/cloudbroker/compute/guest_agent_feature_update": compute_cb.GuestAgentFeatureUpdateRequest{}, // disks - "/restmachine/cloudbroker/disks/create": disks_cb.CreateRequest{}, - "/restmachine/cloudbroker/disks/delete": disks_cb.DeleteRequest{}, - "/restmachine/cloudbroker/disks/deleteDisks": disks_cb.DeleteDisksRequest{}, - "/restmachine/cloudbroker/disks/depresent": disks_cb.DepresentRequest{}, - "/restmachine/cloudbroker/disks/fromPlatformDisk": disks_cb.FromPlatformDiskRequest{}, - "/restmachine/cloudbroker/disks/get": disks_cb.GetRequest{}, - "/restmachine/cloudbroker/disks/limitIO": disks_cb.LimitIORequest{}, - "/restmachine/cloudbroker/disks/list": disks_cb.ListRequest{}, - "/restmachine/cloudbroker/disks/listDeleted": disks_cb.ListDeletedRequest{}, - "/restmachine/cloudbroker/disks/listTypes": disks_cb.ListTypesRequest{}, - "/restmachine/cloudbroker/disks/listUnattached": disks_cb.ListUnattachedRequest{}, - "/restmachine/cloudbroker/disks/rename": disks_cb.RenameRequest{}, - "/restmachine/cloudbroker/disks/present": disks_cb.PresentRequest{}, - "/restmachine/cloudbroker/disks/replicate": disks_cb.ReplicateRequest{}, - "/restmachine/cloudbroker/disks/replicationResume": disks_cb.ReplicationResumeRequest{}, - "/restmachine/cloudbroker/disks/replicationReverse": disks_cb.ReplicationReverseRequest{}, - "/restmachine/cloudbroker/disks/replicationStart": disks_cb.ReplicationStartRequest{}, - "/restmachine/cloudbroker/disks/replicationStatus": disks_cb.ReplicationStatusRequest{}, - "/restmachine/cloudbroker/disks/replicationStop": disks_cb.ReplicationStopRequest{}, - "/restmachine/cloudbroker/disks/replicationSuspend": disks_cb.ReplicationSuspendRequest{}, - "/restmachine/cloudbroker/disks/resize2": disks_cb.ResizeRequest{}, - "/restmachine/cloudbroker/disks/restore": disks_cb.RestoreRequest{}, - "/restmachine/cloudbroker/disks/search": disks_cb.SearchRequest{}, - "/restmachine/cloudbroker/disks/share": disks_cb.ShareRequest{}, - "/restmachine/cloudbroker/disks/snapshotDelete": disks_cb.SnapshotDeleteRequest{}, - "/restmachine/cloudbroker/disks/snapshotRollback": disks_cb.SnapshotRollbackRequest{}, - "/restmachine/cloudbroker/disks/unshare": disks_cb.UnshareRequest{}, + "/restmachine/cloudbroker/disks/change_disk_storage_policy": disks_cb.ChangeDiskStoragePolicyRequest{}, + "/restmachine/cloudbroker/disks/create": disks_cb.CreateRequest{}, + "/restmachine/cloudbroker/disks/delete": disks_cb.DeleteRequest{}, + "/restmachine/cloudbroker/disks/deleteDisks": disks_cb.DeleteDisksRequest{}, + "/restmachine/cloudbroker/disks/depresent": disks_cb.DepresentRequest{}, + "/restmachine/cloudbroker/disks/fromPlatformDisk": disks_cb.FromPlatformDiskRequest{}, + "/restmachine/cloudbroker/disks/get": disks_cb.GetRequest{}, + "/restmachine/cloudbroker/disks/limitIO": disks_cb.LimitIORequest{}, + "/restmachine/cloudbroker/disks/list": disks_cb.ListRequest{}, + "/restmachine/cloudbroker/disks/listDeleted": disks_cb.ListDeletedRequest{}, + "/restmachine/cloudbroker/disks/listTypes": disks_cb.ListTypesRequest{}, + "/restmachine/cloudbroker/disks/listUnattached": disks_cb.ListUnattachedRequest{}, + "/restmachine/cloudbroker/disks/rename": disks_cb.RenameRequest{}, + "/restmachine/cloudbroker/disks/present": disks_cb.PresentRequest{}, + "/restmachine/cloudbroker/disks/replicate": disks_cb.ReplicateRequest{}, + "/restmachine/cloudbroker/disks/replicationResume": disks_cb.ReplicationResumeRequest{}, + "/restmachine/cloudbroker/disks/replicationReverse": disks_cb.ReplicationReverseRequest{}, + "/restmachine/cloudbroker/disks/replicationStart": disks_cb.ReplicationStartRequest{}, + "/restmachine/cloudbroker/disks/replicationStatus": disks_cb.ReplicationStatusRequest{}, + "/restmachine/cloudbroker/disks/replicationStop": disks_cb.ReplicationStopRequest{}, + "/restmachine/cloudbroker/disks/replicationSuspend": disks_cb.ReplicationSuspendRequest{}, + "/restmachine/cloudbroker/disks/resize2": disks_cb.ResizeRequest{}, + "/restmachine/cloudbroker/disks/restore": disks_cb.RestoreRequest{}, + "/restmachine/cloudbroker/disks/search": disks_cb.SearchRequest{}, + "/restmachine/cloudbroker/disks/share": disks_cb.ShareRequest{}, + "/restmachine/cloudbroker/disks/snapshotDelete": disks_cb.SnapshotDeleteRequest{}, + "/restmachine/cloudbroker/disks/snapshotRollback": disks_cb.SnapshotRollbackRequest{}, + "/restmachine/cloudbroker/disks/unshare": disks_cb.UnshareRequest{}, // dpdknet "/restmachine/cloudbroker/dpdknet/get": dpdknet_cb.GetRequest{}, @@ -717,26 +742,27 @@ func getRequestsMapCloudbroker() map[string]interface{} { "/restmachine/cloudbroker/group/list": group_cb.ListRequest{}, // image - "/restmachine/cloudbroker/image/computeciSet": image_cb.ComputeCISetRequest{}, - "/restmachine/cloudbroker/image/computeciUnset": image_cb.ComputeCIUnsetRequest{}, - "/restmachine/cloudbroker/image/createCDROMImage": image_cb.CreateCDROMImageRequest{}, - "/restmachine/cloudbroker/image/createImage": image_cb.CreateRequest{}, - "/restmachine/cloudbroker/image/createVirtual": image_cb.CreateVirtualRequest{}, - "/restmachine/cloudbroker/image/delete": image_cb.DeleteRequest{}, - "/restmachine/cloudbroker/image/deleteCDROMImage": image_cb.DeleteCDROMImageRequest{}, - "/restmachine/cloudbroker/image/deleteImages": image_cb.DeleteImagesRequest{}, - "/restmachine/cloudbroker/image/disable": image_cb.DisableRequest{}, - "/restmachine/cloudbroker/image/edit": image_cb.EditRequest{}, - "/restmachine/cloudbroker/image/enable": image_cb.EnableRequest{}, - "/restmachine/cloudbroker/image/get": image_cb.GetRequest{}, - "/restmachine/cloudbroker/image/grantAccess": image_cb.GrantAccessRequest{}, - "/restmachine/cloudbroker/image/link": image_cb.LinkRequest{}, - "/restmachine/cloudbroker/image/list": image_cb.ListRequest{}, - "/restmachine/cloudbroker/image/listStacks": image_cb.ListStacksRequest{}, - "/restmachine/cloudbroker/image/rename": image_cb.RenameRequest{}, - "/restmachine/cloudbroker/image/revokeAccess": image_cb.RevokeAccessRequest{}, - "/restmachine/cloudbroker/image/share": image_cb.ShareRequest{}, - "/restmachine/cloudbroker/image/updateNodes": image_cb.UpdateNodesRequest{}, + "/restmachine/cloudbroker/image/change_storage_policy": image_cb.ChangeStoragePolicyRequest{}, + "/restmachine/cloudbroker/image/computeciSet": image_cb.ComputeCISetRequest{}, + "/restmachine/cloudbroker/image/computeciUnset": image_cb.ComputeCIUnsetRequest{}, + "/restmachine/cloudbroker/image/createCDROMImage": image_cb.CreateCDROMImageRequest{}, + "/restmachine/cloudbroker/image/createImage": image_cb.CreateRequest{}, + "/restmachine/cloudbroker/image/createVirtual": image_cb.CreateVirtualRequest{}, + "/restmachine/cloudbroker/image/delete": image_cb.DeleteRequest{}, + "/restmachine/cloudbroker/image/deleteCDROMImage": image_cb.DeleteCDROMImageRequest{}, + "/restmachine/cloudbroker/image/deleteImages": image_cb.DeleteImagesRequest{}, + "/restmachine/cloudbroker/image/disable": image_cb.DisableRequest{}, + "/restmachine/cloudbroker/image/edit": image_cb.EditRequest{}, + "/restmachine/cloudbroker/image/enable": image_cb.EnableRequest{}, + "/restmachine/cloudbroker/image/get": image_cb.GetRequest{}, + "/restmachine/cloudbroker/image/grantAccess": image_cb.GrantAccessRequest{}, + "/restmachine/cloudbroker/image/link": image_cb.LinkRequest{}, + "/restmachine/cloudbroker/image/list": image_cb.ListRequest{}, + "/restmachine/cloudbroker/image/listStacks": image_cb.ListStacksRequest{}, + "/restmachine/cloudbroker/image/rename": image_cb.RenameRequest{}, + "/restmachine/cloudbroker/image/revokeAccess": image_cb.RevokeAccessRequest{}, + "/restmachine/cloudbroker/image/share": image_cb.ShareRequest{}, + "/restmachine/cloudbroker/image/updateNodes": image_cb.UpdateNodesRequest{}, // k8ci "/restmachine/cloudbroker/k8ci/accessAdd": k8ci_cb.AccessAddRequest{}, @@ -855,11 +881,13 @@ func getRequestsMapCloudbroker() map[string]interface{} { // rg "/restmachine/cloudbroker/rg/accessGrant": rg_cb.AccessGrantRequest{}, "/restmachine/cloudbroker/rg/accessRevoke": rg_cb.AccessRevokeRequest{}, + "/restmachine/cloudbroker/rg/add_storage_policy": rg_cb.AddStoragePolicyRequest{}, "/restmachine/cloudbroker/rg/affinityGroupComputes": rg_cb.AffinityGroupComputesRequest{}, "/restmachine/cloudbroker/rg/affinityGroupsGet": rg_cb.AffinityGroupsGetRequest{}, "/restmachine/cloudbroker/rg/affinityGroupsList": rg_cb.AffinityGroupsListRequest{}, "/restmachine/cloudbroker/rg/audits": rg_cb.AuditsRequest{}, "/restmachine/cloudbroker/rg/create": rg_cb.CreateRequest{}, + "/restmachine/cloudbroker/rg/del_storage_policy": rg_cb.DelStoragePolicyRequest{}, "/restmachine/cloudbroker/rg/delete": rg_cb.DeleteRequest{}, "/restmachine/cloudbroker/rg/disable": rg_cb.DisableRequest{}, "/restmachine/cloudbroker/rg/enable": rg_cb.EnableRequest{}, @@ -885,6 +913,15 @@ func getRequestsMapCloudbroker() map[string]interface{} { "/restmachine/cloudbroker/rg/usage": rg_cb.UsageRequest{}, "/restmachine/cloudbroker/rg/removeDefNet": rg_cb.RemoveDefNetRequest{}, + // security_group + "/restmachine/cloudbroker/security_group/create": securitygroup_cb.CreateRequest{}, + "/restmachine/cloudbroker/security_group/create_rule": securitygroup_cb.CreateRuleRequest{}, + "/restmachine/cloudbroker/security_group/delete": securitygroup_cb.DeleteRequest{}, + "/restmachine/cloudbroker/security_group/delete_rule": securitygroup_cb.DeleteRuleRequest{}, + "/restmachine/cloudbroker/security_group/get": securitygroup_cb.GetRequest{}, + "/restmachine/cloudbroker/security_group/list": securitygroup_cb.ListRequest{}, + "/restmachine/cloudbroker/security_group/update": securitygroup_cb.UpdateRequest{}, + // sep "/restmachine/cloudbroker/sep/accessGrant": sep_cb.AccessGrantRequest{}, "/restmachine/cloudbroker/sep/accessGrantToPool": sep_cb.AccessGrantToPoolRequest{}, @@ -920,6 +957,17 @@ func getRequestsMapCloudbroker() map[string]interface{} { "/restmachine/cloudbroker/stack/setCpuAllocationRatio": stack_cb.SetCpuAllocationRatioRequest{}, "/restmachine/cloudbroker/stack/setMemAllocationRatio": stack_cb.SetMemAllocationRatioRequest{}, + // storage_policy + "/restmachine/cloudbroker/storage_policy/get": storagepolicy_cb.GetRequest{}, + "/restmachine/cloudbroker/storage_policy/list": storagepolicy_cb.ListRequest{}, + "/restmachine/cloudbroker/storage_policy/create": storagepolicy_cb.CreateRequest{}, + "/restmachine/cloudbroker/storage_policy/update": storagepolicy_cb.UpdateRequest{}, + "/restmachine/cloudbroker/storage_policy/add_pool": storagepolicy_cb.AddPoolRequest{}, + "/restmachine/cloudbroker/storage_policy/delete": storagepolicy_cb.DeleteRequest{}, + "/restmachine/cloudbroker/storage_policy/disable": storagepolicy_cb.DisableRequest{}, + "/restmachine/cloudbroker/storage_policy/enable": storagepolicy_cb.EnableRequest{}, + "/restmachine/cloudbroker/storage_policy/delete_pool": storagepolicy_cb.DeletePollRequest{}, + // tasks "/restmachine/cloudbroker/tasks/get": tasks_cb.GetRequest{}, "/restmachine/cloudbroker/tasks/list": tasks_cb.ListRequest{}, @@ -1000,6 +1048,7 @@ func getRequestsMapCloudbroker() map[string]interface{} { "/restmachine/cloudbroker/vins/staticRouteAdd": vins_cb.StaticRouteAddRequest{}, "/restmachine/cloudbroker/vins/staticRouteDel": vins_cb.StaticRouteDelRequest{}, "/restmachine/cloudbroker/vins/staticRouteList": vins_cb.StaticRouteListRequest{}, + "/restmachine/cloudbroker/vins/update": vins_cb.UpdateRequest{}, "/restmachine/cloudbroker/vins/vnfdevRedeploy": vins_cb.VNFDevRedeployRequest{}, "/restmachine/cloudbroker/vins/vnfdevRestart": vins_cb.VNFDevRestartRequest{}, "/restmachine/cloudbroker/vins/vnfdevReset": vins_cb.VNFDevResetRequest{}, @@ -1016,3 +1065,18 @@ func getRequestsMapCloudbroker() map[string]interface{} { "/restmachine/cloudbroker/zone/delNode": zone_cb.DelNodeRequest{}, } } + +// getRequestsMapSDN maps request path with request golang sdk structures for sdn most used requests +func getRequestsMapSDN() map[string]interface{} { + return map[string]interface{}{ + // access_groups + "/restmachine/sdn/access_group/list": acsgroups.ListGroupsRequest{}, + "/restmachine/sdn/access_group/user_list": acsgroups.UsersListRequest{}, + "/restmachine/sdn/access_group/create": acsgroups.CreateRequest{}, + "/restmachine/sdn/access_group/delete": acsgroups.DeleteRequest{}, + "/restmachine/sdn/access_group/user_add": acsgroups.UserAddRequest{}, + "/restmachine/sdn/access_group/patch": acsgroups.PatchRequest{}, + "/restmachine/sdn/access_group/user_delete": acsgroups.UserDeleteRequest{}, + "/restmachine/sdn/access_group/update_role": acsgroups.UserUpdateRoleRequest{}, + } +} diff --git a/tests/platform_upgrade/utils_get_list.go b/tests/platform_upgrade/utils_get_list.go index 12f5ddd..3a5d413 100644 --- a/tests/platform_upgrade/utils_get_list.go +++ b/tests/platform_upgrade/utils_get_list.go @@ -72,22 +72,25 @@ func getResult(testName string, bytes []byte, structure any, t *testing.T) strin t.Errorf(result) return result } - return "" + result := fmt.Sprint(testName, ": ok") + t.Log(result) + return result } // getDifference tells which fields are present in bytesMap and not present in structMap and vice versa. func getDifference(testName string, bytesMap, structMap map[string]interface{}) string { var result string bytesFields, _ := evaluate(bytesMap, structMap) + // structFields, _ := evaluate(structMap, bytesMap) result += fmt.Sprintf("%s: ", testName) if len(bytesFields) > 0 { result += fmt.Sprintf("\nPlatform has these fields that golang struct doesn't: %v\n", bytesFields) } - //if len(structFields) > 0 { - // result += fmt.Sprintf("Golang struct has these fields that platform doesn't: %v\n", structFields) - //} + // if len(structFields) > 0 { + // result += fmt.Sprintf("Golang struct has these fields that platform doesn't: %v\n", structFields) + // } if len(bytesFields) == 0 { result += "OK" @@ -172,13 +175,25 @@ func appendSelectedElements(slice []string, elements []string) []string { // GetMapFromBytes converts []byte to map[string]interface{} func GetMapFromBytes(bytes []byte) (map[string]interface{}, error) { - var x map[string]interface{} - err := json.Unmarshal(bytes, &x) + var unmarshalMaps map[string]interface{} + err := json.Unmarshal(bytes, &unmarshalMaps) + if err != nil { + var unmarshalSlice []interface{} + err = json.Unmarshal(bytes, &unmarshalSlice) + if err != nil { + return nil, err + } + t, ok := unmarshalSlice[0].(map[string]interface{}) + if !ok { + return nil, err + } + unmarshalMaps = t + } if err != nil { return nil, err } - return getMapBytes(x), nil + return getMapBytes(unmarshalMaps), nil } func getMapBytes(value map[string]interface{}) map[string]interface{} { diff --git a/tests/platform_upgrade/utils_requests.go b/tests/platform_upgrade/utils_requests.go index 5545620..72cf31a 100644 --- a/tests/platform_upgrade/utils_requests.go +++ b/tests/platform_upgrade/utils_requests.go @@ -11,12 +11,24 @@ import ( func getParameters(input map[string]interface{}) []interface{} { var emptySlice []interface{} - post, ok := input["post"] - if !ok { + methods := []string{"get", "post", "put", "delete", "patch", "head", "options"} + + var methodData interface{} + found := false + + for _, method := range methods { + if data, ok := input[method]; ok { + methodData = data + found = true + break + } + } + + if !found { return emptySlice } - parameters, ok := post.(map[string]interface{}) + parameters, ok := methodData.(map[string]interface{}) if !ok { return emptySlice } @@ -30,7 +42,47 @@ func getParameters(input map[string]interface{}) []interface{} { if !ok { return emptySlice } - + // Check if there's a body parameter + for _, p := range res { + param, ok := p.(map[string]interface{}) + if !ok { + continue + } + if param["name"] == "body" { + schema, ok := param["schema"].(map[string]interface{}) + if !ok { + continue + } + properties, ok := schema["properties"].(map[string]interface{}) + if !ok { + continue + } + requiredFields := make(map[string]bool) + if req, ok := schema["required"].([]interface{}); ok { + for _, r := range req { + requiredFields[r.(string)] = true + } + } + var newParams []interface{} + for name, prop := range properties { + propMap, ok := prop.(map[string]interface{}) + if !ok { + continue + } + newParam := make(map[string]interface{}) + newParam["name"] = name + newParam["type"] = propMap["type"] + newParam["required"] = requiredFields[name] + if propMap["type"] == "array" { + if items, ok := propMap["items"].(map[string]interface{}); ok { + newParam["items"] = items + } + } + newParams = append(newParams, newParam) + } + return newParams + } + } return res } @@ -57,8 +109,10 @@ func getErrorsFromJSON(bytes []byte, t *testing.T, cloud string) { requests = getRequestsMapCloudAPI() case "cloudbroker": requests = getRequestsMapCloudbroker() + case "sdn": + requests = getRequestsMapSDN() default: - t.Fatalf("Wrong cloud provided, expected `cloudapi` or `cloudbroker`, got %s", cloud) + t.Fatalf("Wrong cloud provided, expected `cloudapi`, `cloudbroker` or `sdn`, got %s", cloud) } var dataLogs []string @@ -96,12 +150,18 @@ func getErrorsFromJSON(bytes []byte, t *testing.T, cloud string) { continue } - name := param["name"].(string) + name, ok := param["name"].(string) + if !ok { + name = "" + } required, ok := param["required"].(bool) if !ok { required = false } - typ := p.(map[string]interface{})["type"].(string) + typ, ok := p.(map[string]interface{})["type"].(string) + if !ok { + typ = "" + } var items string if p.(map[string]interface{})["items"] != nil { @@ -109,7 +169,10 @@ func getErrorsFromJSON(bytes []byte, t *testing.T, cloud string) { if itemsTemp != nil { itemsType := itemsTemp.(map[string]interface{})["type"] if itemsType != nil { - items = itemsType.(string) + items, ok = itemsType.(string) + if !ok { + items = "" + } } } } @@ -143,7 +206,7 @@ func getErrorsFromJSON(bytes []byte, t *testing.T, cloud string) { } if len(requests) != i { - msg := fmt.Sprintf("Amount of structure checked (%d) is not the same as amount of platform requests available (%d), please check getRequestsMapCloudAPI func in code.", + msg := fmt.Sprintf("Amount of structure checked (%d) is not the same as amount of platform requests available (%d), please check getRequests func in code.", i, len(requests)) t.Error(msg) dataLogs = append(dataLogs, msg) diff --git a/tests/platform_upgrade/utils_urls.go b/tests/platform_upgrade/utils_urls.go index 9a7f953..90dd6d7 100644 --- a/tests/platform_upgrade/utils_urls.go +++ b/tests/platform_upgrade/utils_urls.go @@ -67,7 +67,7 @@ func getUrlsFromBytes(bytes []byte) ([]string, error) { } func validateUrlFromJson(url string) bool { - if !strings.HasPrefix(url, "/restmachine/cloudapi/") && !strings.HasPrefix(url, "/restmachine/cloudbroker/") { + if !strings.HasPrefix(url, "/restmachine/cloudapi/") && !strings.HasPrefix(url, "/restmachine/cloudbroker/") && !strings.HasPrefix(url, "/restmachine/sdn/") { return false } @@ -189,6 +189,11 @@ func readUrlFromFile(fileName string) ([]string, error) { url := strings.Trim(scanner.Text()[indexStart:], `"`) result = append(result, "/restmachine"+url) } + if strings.Contains(scanner.Text(), `"/sdn/`) { + indexStart := strings.Index(scanner.Text(), "/sdn/") + url := strings.Trim(scanner.Text()[indexStart:], `"`) + result = append(result, "/restmachine"+url) + } } if len(result) == 0 {