diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c3bb74..03ee6f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,197 @@ -## Version 1.7.7 +## Version 1.8.0 + +### Feature + +#### account: +- Add endpoints GrantAccessTemplates, ListAvailableTemplates, RevokeAccessTemplates in cloudbroker/account +- Add SortBy field for list groups and validation functionality +- Add ComputeFeatures field to RecordAccount and ItemAccount models in cloudapi/account +- Add ComputeFeatures field to InfoAccount and CreateRequest model in cloudbroker/account +- Add UpdateComputeFeatures endpoint in cloudbroker/account +- Add ExtnetId, FreeIPs fields to model ItemVINS in cloudapi/account and cloudbroker/account + +#### audit: +- Add field GUID in model ItemLinkedJobs cloudbroker/audit +- Delete field StatusCode in model ListRequest cloudbroker/audit +- Add fields MinStatusCode and MaxStatusCode in model ListRequest cloudbroker/audit + +#### bservice: +- Add validation of RAM to be divisible by 128 in cloudapi/bservice + +#### compute: +- Add field CdImageId in models ItemCompute and RecordCompute in cloudapi/compute and cloudbroker/compute +- Add fields NatableVINSID, NatableVINSIP, NatableVINSName, NatableVINSNetwork, NatableVINSNetworkName in models RecordCompute in cloudbroker/compute +- Set field LocalBasePort in model PFWAddRequest as optional in cloudapi/compute and cloudbroker/compute +- Add SortBy field for list groups and validation functionality +- Add HPBacked, CPUPin, NumaAffinity fields to RecordCompute and InfoCompute models in cloudbroker/compute +- Add HPBacked, CPUPin, NumaAffinity fields to RecordCompute and ItemCompute models in cloudapi/compute +- Add validation of RAM to be divisible by 128 in cloudapi/compute and cloudbroker/compute +- Add field NumaNodeId in models RecordCompute and ItemCompute in cloudapi/compute and cloudbroker/compute +- Add BootDiskSet endpoints in cloudapi/compute and cloudbroker/compute +- Add endpoints DiskSwitchToReplication, DiskMigrate in cloudapi/compute and cloudbroker/compute +- Add field Replication in model RecordCompute.Disks.ItemComputeDisk in cloudapi/compute and cloudbroker/compute +- Add endpoint getCustomFields in cloudbroker/compute +- Delete field AffinityLabel in model AffinityRelationsRequest in cloudbroker/compute +- Add fields ImageName and VirtualImageName, delete VINSConnected fields in RecordCompute model in cloudbroker/compute +- Add fields Enabled and NodeID in ItemInterface model in cloudbroker/compute. Add NodeID field in ItemVNFInterface model in cloudapi/compute + +#### disks: +- Add endpoints Replicate, ReplicationResume, ReplicationReverse, ReplicationStart, ReplicationStop, ReplicationStatus, ReplicationSuspend in cloudapi/disks and cloudbroker/disks +- Add field Replication in models RecordDisk and ItemDisk in cloudapi/disks and cloudbroker/disks +- Add CreateTemplateFromBlank and CreateTemplateFromBlankAsync endpoints in cloudapi/compute and cloudbroker/compute +- Add fields Page and Size in model SearchRequest in cloudapi/disks +- Add FromPlatformDisk and FromPlatformDiskAsync endpoints in cloudapi/disks and cloudbroker/disks + +#### flipgroup: +- Add fields ConnId, Status, AccountId to model ListRequest in cloudapi/flipgroup and cloudbroker/flipgroup +- Add SortBy field for list groups and validation functionality + +#### grid: +- Add endpoints addCustomBackupPath, removeCustomBackupPath, setPasswordPolicy in cloudbroker/grid + +#### image: +- Add field CdPresentedTo in model RecordImage in cloudapi/image cloudbroker/image +- Set field AccountId in CreateRequest in cloudapi/image as required +- Add endpoints GrantAccess, RevokeAccess in cloudbroker/image +- Add SortBy field for list groups and validation functionality +- Add field NetworkInterfaceNaming in model CreateRequest in cloudapi/image cloudbroker/image, in model EditRequest in cloudbroker/image, in models ItemImage and RecordImage in cloudapi/image and cloudbroker/image +- Add validation field NetworkInterfaceNaming in cloudapi/image cloudbroker/image +- Delete field GID in model CreateRequest in cloudapi/image +- Delete field Meta and Ckey in model and RecordImage in cloudbroker/image +- Add model ItemImage in cloudbroker/image + +#### k8s: +- Add field LbSysctlParams in model CreateRequest in cloudapi/k8s/create and cloudbroker/k8s/create +- Add validation of RAM to be divisible by 128 in cloudapi/k8s and cloudbroker/k8s +- Set uint64 as MasterRAM and WorkerRAM types in CreateRequest struct in cloudapi/k8s and cloudbroker/k8s + +#### kvmppc +- Add validation of RAM to be divisible by 128 in cloudapi/kvmppc and cloudbroker/kvmppc +- Add DataDisks field to CreateRequest and CreateBlankRequest in cloudapi/kvmppc and cloudbroker/kvmppc +- Add DataDisks field to MassCreateRequest in cloudbroker/kvmppc + +#### kvmx86 +- Add validation of RAM to be divisible by 128 in cloudapi/kvmx86 and cloudbroker/kvmx86 +- Add DataDisks field to CreateRequest and CreateBlankRequest in cloudapi/kvmx86 and cloudbroker/kvmx86 +- Add DataDisks field to MassCreateRequest in cloudbroker/kvmx86 + +#### lb: +- Add fields UserManaged, ManagerId, ManagerType, PartK8S in models RecordLB, ItemLBList in cloudapi/lb and cloudbroker/lb +- Add SortBy field for list groups and validation functionality +- Add field SysctlParams in model CreateRequest in cloudapi/lb/create and cloudbroker/lb/create +- Add endpoint update_sysctl_params in cloudapi/lb and cloudbroker/lb + +#### node: +- Add ApplyIpmiAction, Consumption, Decommission, Enable, EnableNodes, Get, GetRaw, List, ListRaw, Maintenance, Restrict, SetCoreIsolation, SetHugePages, SetSRIOVStatus, SetVFSNumber and Update endpoints in cloudbroker/node +- Add IDs method and Filters methods for ListNodes structure in cloudbroker/node +- Add Serialize method for ListNodes, ItemNode and RecordNode structures in cloudbroker/node + +#### pcidevice: +- Add List, ListRaw endpoints in cloudapi/pcidevice +- Add IDs and Serialize methods for ListPCIDevices structure in cloudapi/pcidevice + +#### rg: +- Add ComputeFeatures field to ItemResourceGroup and RecordResourceGroup models in cloudapi/rg +- Add ComputeFeatures field to ItemRG and CreateRequest models in cloudbroker/rg +- Add UpdateComputeFeatures endpoint in cloudbroker/rg +- Add ExtnetId, FreeIPs fields to model ItemVINS in cloudapi/rg and cloudbroker/rg + +#### sep: +- Add endpoints addPool, delPool in cloudbroker/sep +- Set field Config in CreateRequest as required in cloudbroker/sep +- Add SortBy field for list groups and validation functionality + +#### stack: +- Add endpoints getLogicalCoresCount, setCpuAllocationRatio, setMemAllocationRatio in cloudbroker/stack + +#### tasks: +- Add field TaskId, Status, Completed in model ListRequest in cloudapi/task and cloudbroker/task +- Add fields GUID, UpdatedBy in model ItemTask in cloudapi/task and cloudbroker/task +- Fix panic in List endpoints in cloudapi/task and cloudbroker/task +- Change type field Result from int to interface{} in models RecordAsyncTask, ItemAsyncTask in cloudapi/task and models ItemTask, RecordTask in cloudbroker/task +- Add methods ID(), Name(), ToString(), ToMaps() for processing the value of the Result field in model ItemTask in cloudapi/task and cloudbroker/task +- Add use case examples for the above methods in README.md +- Add SortBy field for list groups and validation functionality +- Add fields UpdateTimeAt and UpdateTimeTo in model ListRequest in cloudapi/tasks and cloudbroker/tasks + +#### user: +- Add fields Call, StatusCode, TimestampAt, TimestampTo in models GetAuditRequest in cloudbroker/user +- Fix return value in GetAudit endpoint in cloudbroker/user +- Add model ListAudits and change type field APIAccess in model ItemUser in cloudbroker/user +- Add SortBy field for list groups and validation functionality in cloudbroker/user +- Add APIList, Authenticate, Brief, GetAudit, GetResourceConsumption, Get, GetRaw, IsValidInviteUserToken, Search, SetData endpoints in cloudapi/user + +#### vfpool: +- Add Get, GetRaw, List, ListRaw endpoints in cloudapi/vfpool +- Add Create, Delete, Disable, Enable, Get, GetRaw, List, ListRaw, Update endpoints in cloudbroker/vfpool +- Add IDs method for ListVFPool, VFSInfoListand in cloudapi/vfpool and cloudbroker/vfpool +- Add Filters methods for ListVFPool structure in cloudapi/vfpool and cloudbroker/vfpool +- Add Serialize method for ListVFPool, ItemVFPool and RecordVFPool structures in cloudapi/vfpool and cloudbroker/vfpool + +#### vins: +- Set field IntPort in model NATRuleAddRequest as optional in cloudapi/vins and cloudbroker/vins +- Add SortBy field for list groups and validation functionality +- Add ExtnetId, FreeIPs fields to model ItemVINS in cloudapi/vins and cloudbroker/vins +- Add DNSList field to models CreateInAccountRequest and CreateInRGRequest in cloudapi/vins and cloudbroker/vins +- Add DNSApply endpoints in cloudapi/vins and cloudbroker/vins +- Add field NodeID in model RecordVINS.RecordVNFDev.Interfaces in cloudapi/vins and cloudbroker/vins ### Bugfix -- Fix url for Disable method in cloudapi/bservice \ No newline at end of file + +#### account: +- Fix wrong json, url field AccountID in model SetCPUAllocationParameterRequest in cloudbroker/account +- Fix wrong json, url field AccountID in model SetCPUAllocationRatioRequest in cloudbroker/account +- Change Start and End fields type from uint64 to float64 in model GetConsumptionRequest in cloudapi/account + +#### apiaccess: +- Changed Job and Resmon field types in model CloudBrokerEndpoints in cloudbroker/apiaccess +- Add fields Page and Size in model UserListRequest in cloudbroker/apiaccess + +#### bservice: +- Fix url for Disable endpoint in cloudapi/bservice + +#### compute: +- Fix Entrycount tag in model ListComputes in cloudbroker/compute +- Add field Name in model ListPCIDeviceRequest in cloudbroker/compute +- Fix type of field Data in model ListPCIDevices in cloudapi/compute +- Add model ItemPCIDevice in cloudapi/compute +- Fix type of field Data in model ListVGPUs in cloudapi/compute and cloudbroker/compute +- Add model ItemVGPU in cloudapi/compute and cloudbroker/compute + +#### disks: +- Delete tag required from field Detailed in ListTypesRequest model in cloudapi/disks + +#### grid: +- Fix json, url tags in field Name in model RenameRequest in cloudbroker/grid + +#### image: +- Fix url for ComputeCIUnset endpoint in cloudbroker/image + +#### k8ci: +- Delete omitempty from json, url tags in field Permanently in model DeleteRequest in cloudbroker/k8ci +- Fix wrong json, url tags field ByID in model ListDeletedRequest in cloudbroker/k8ci +- Fix allowed network plugin value from "weawenet" to "weavenet" in validators for cloudbroker/k8ci + +#### k8s: +- Fix allowed network plugin value from "weawenet" to "weavenet" in validators for cloudapi/k8s, cloudbroker/k8s + +#### lb: +- Fix wrong json, url tags field AccountID in model ListDeletedRequest in cloudapi/lb +- Add field Safe in model RestartRequest in cloudbroker/lb +- Fix wrong json, url tags field AccountID in models ListRequest, ListDeletedRequest in cloudbroker/lb +- Fix url for Stop endpoint in cloudapi/lb + +#### rg: +- Fix wrong json, url field AccountID in model ListLBRequest in cloudapi/rg and cloudbroker/rg +- Fix wrong json, url field UniqPools in model CreateRequest in cloudbroker/rg + +#### sep: +- Fix wrong json, url tag in field GID in model ListRequest in cloudbroker/sep + +#### user: +- Fix wrong json, url field Password in model ItemUser in cloudbroker/user +- Change ByID field type from uint64 to string in model ListRequest in cloudbroker/user + +#### vins: +- Fix wrong json, url tags in models DefaultQOSUpdateRequest and NetQOSRequest in field IngressBirst in cloudbroker/vins +- Fix wrong name field ListNatRule to ListNATRule in cloudbroker/vins \ No newline at end of file diff --git a/README.md b/README.md index bbba2f2..7303b66 100644 --- a/README.md +++ b/README.md @@ -12,49 +12,63 @@ Decort SDK - это библиотека, написанная на языке G - Версия 1.5.x Decort-SDK соответствует 3.8.7 версии платформы - Версия 1.6.x Decort-SDK соответствует 3.8.8 версии платформы - Версия 1.7.х Decort-SDK соответствует 3.8.9 версии платформы + - Версия 1.8.х Decort-SDK соответствует 4.0.0 версии платформы ## Оглавление -- [Установка](#установка) -- [Список API](#список-api) +- [Decort SDK](#decort-sdk) + - [Версии](#версии) + - [Оглавление](#оглавление) + - [Установка](#установка) + - [Список API](#список-api) - [Cloudapi](#cloudapi) - [Cloudbroker](#cloudbroker) -- [Работа с библиотекой](#работа-с-библиотекой) + - [Работа с библиотекой](#работа-с-библиотекой) - [Настройка конфигурации клиента](#настройка-конфигурации-клиента) - - [Пример конфигурации клиента](#пример-конфигурации-клиента) - - [Парсинг конфигурации из файла](#парсинг-конфигурации-из-файла) - - [Пример JSON конфигурации](#пример-json-конфигурации) - - [Пример YAML конфигурации](#пример-yaml-конфигурации) + - [Пример конфигурации клиента](#пример-конфигурации-клиента) + - [Парсинг конфигурации из файла](#парсинг-конфигурации-из-файла) + - [Пример JSON конфигурации](#пример-json-конфигурации) + - [Пример YAML конфигурации](#пример-yaml-конфигурации) - [Создание клиента](#создание-клиента) - - [Создание структуры запроса](#cоздание-структуры-запроса) + - [Пример](#пример) + - [Создание структуры запроса](#создание-структуры-запроса) + - [Пример комментариев структуры](#пример-комментариев-структуры) + - [Пример создания запроса для развертывания виртуальной машины:](#пример-создания-запроса-для-развертывания-виртуальной-машины) - [Выполнение запроса](#выполнение-запроса) + - [Пример выполнения запроса](#пример-выполнения-запроса) + - [Пример выполнения GetRaw и ListRaw запросов](#пример-выполнения-getraw-и-listraw-запросов) - [Фильтрация](#фильтрация) + - [Использование на примере `compute.FilterByK8SID`:](#использование-на-примере-computefilterbyk8sid) - [Сортировка](#сортировка) - [Сериализация](#сериализация) - - [Получение списка уникальных идентификаторов (ID) объекта](#получение-списка-уникальных-идентификаторов-id-объекта) -- [Работа с legacy клиентом](#работа-с-legacy-клиентом) + - [Комплексный пример](#комплексный-пример) + - [Получение списка уникальных идентификаторов ID объекта](#получение-списка-уникальных-идентификаторов-id-объекта) + - [Методы поля Result для группы tasks](#методы-поля-result-для-группы-tasks) + - [Работа с legacy клиентом](#работа-с-legacy-клиентом) - [Настройка конфигурации legacy клиента](#настройка-конфигурации-legacy-клиента) - - [Пример конфигурации legacy клиента](#пример-конфигурации-legacy-клиента) - - [Парсинг legacy конфигурации из файла](#парсинг-legacy-конфигурации-из-файла) - - [Пример legacy JSON конфигурации](#пример-legacy-json-конфигурации) - - [Пример legacy YAML конфигурации](#пример-legacy-yaml-конфигурации) + - [Пример конфигурации legacy клиента](#пример-конфигурации-legacy-клиента) + - [Парсинг legacy конфигурации из файла](#парсинг-legacy-конфигурации-из-файла) + - [Пример legacy JSON конфигурации](#пример-legacy-json-конфигурации) + - [Пример legacy YAML конфигурации](#пример-legacy-yaml-конфигурации) - [Создание legacy клиента](#создание-legacy-клиента) - - [Создание структуры запроса](#cоздание-структуры-запроса) - - [Выполнение запроса](#выполнение-запроса) -- [Работа с BVS клиентом](#работа-с-bvs-клиентом) + - [Пример создания legacy клиента](#пример-создания-legacy-клиента) + - [Пример выполнения запроса](#пример-выполнения-запроса-1) + - [Работа с BVS клиентом](#работа-с-bvs-клиентом) - [Настройка параметров BVS в кабинете администратора](#настройка-параметров-bvs-в-кабинете-администратора) - [Настройка конфигурации BVS клиента](#настройка-конфигурации-bvs-клиента) - [Описание структуры token](#описание-структуры-token) - - [Пример конфигурации BVS клиента](#пример-конфигурации-bvs-клиента) - - [Парсинг BVS конфигурации из файла](#парсинг-bvs-конфигурации-из-файла) - - [Парсинг BVS токена из файла](#парсинг-bvs-токена-из-файла) - - [Пример BVS JSON конфигурации](#пример-bvs-json-конфигурации) - - [Пример BVS YAML конфигурации](#пример-bvs-yaml-конфигурации) + - [Пример конфигурации BVS клиента](#пример-конфигурации-bvs-клиента) + - [Парсинг BVS конфигурации из файла](#парсинг-bvs-конфигурации-из-файла) + - [Парсинг BVS токена из файла](#парсинг-bvs-токена-из-файла) + - [Пример BVS JSON конфигурации](#пример-bvs-json-конфигурации) + - [Пример BVS YAML конфигурации](#пример-bvs-yaml-конфигурации) - [Создание BVS клиента](#создание-bvs-клиента) - - [Пример создания BVS клиента](#пример-создания-bvs-клиента) - - [Пример получения BVS токена](#пример-получения-bvs-токена) - - [Пример обновления BVS токена](#пример-обновления-bvs-токена) - - [Пример выполнения запроса](#пример-выполнения-запроса) + - [Пример создания BVS клиента](#пример-создания-bvs-клиента) + - [Пример получения BVS токена](#пример-получения-bvs-токена) + - [Пример обновления BVS токена](#пример-обновления-bvs-токена) + - [Пример выполнения запроса](#пример-выполнения-запроса-2) + - [Пример валидации запросов, имеющих в своей структуре поле RAM (или MasterRam/WorkerRAM)](#пример-валидации-запросов-имеющих-в-своей-структуре-поле-ram-или-masterramworkerram) + - [Пример выполнения запроса](#пример-выполнения-запроса-3) ## Установка @@ -93,6 +107,7 @@ go get -u repository.basistech.ru/BASIS/decort-golang-sdk - `Sizes` - получение информации о потребляемых ресурсах виртуальными машинами и дисками; - `Stack` - получение информации о вычислительных узлах; - `Tasks` - получение информации о ходе выполнения асинхронных задач (например, создание кластера); +- `VFPool` - управление пулом виртуальных сетевых функций; - `VINS` - управление виртуальными изолированными сетями. ### Cloudbroker @@ -115,6 +130,7 @@ go get -u repository.basistech.ru/BASIS/decort-golang-sdk - `KVMPPC` - создание виртуальной машины Power PC (IBM); - `KVMx86` - создание виртуальной машины x86; - `LB` - управление балансировщиками нагрузки; +- `Node` - управление нодами платформы; - `PCIDevice` - управление устройствами; - `RG` - управление ресурсными группами аккаунта; - `SEP` - управление storage endpoint (sep); @@ -122,6 +138,7 @@ go get -u repository.basistech.ru/BASIS/decort-golang-sdk - `Tasks` - получение информации о ходе выполнения асинхронных задач (например, создание кластера); - `User` - управление пользователями (индивидуально); - `VGPU` - управление виртуальными графическими процессорами; +- `VFPool` - управление пулом виртуальных сетевых функций; - `VINS` - управление виртуальными изолированными сетями. ## Работа с библиотекой @@ -271,6 +288,7 @@ func main() { - `pkg/cloudapi/sizes` - для `Sizes` - `pkg/cloudapi/stack` - для `Stack` - `pkg/cloudapi/tasks` - для `Tasks` + - `pkg/cloudapi/vfpool` - для `VFPool` - `pkg/cloudapi/vins` - для `VINS` - **cloudbroker**: - `pkg/cloudbroker/account` - для `Account` @@ -288,6 +306,7 @@ func main() { - `pkg/cloudbroker/kvmppc` - для `KVMPPC` - `pkg/cloudbroker/kvmx86` - для `KVMX86` - `pkg/cloudbroker/lb` - для `LB` + - `pkg/cloudbroker/node` - для `Node` - `pkg/cloudbroker/pcidevice` - для `PCIDevice` - `pkg/cloudbroker/rg` - для `RG` - `pkg/cloudbroker/sep` - для `SEP` @@ -295,6 +314,7 @@ func main() { - `pkg/cloudbroker/tasks` - для `Tasks` - `pkg/cloudbroker/user` - для `User` - `pkg/cloudbroker/vgpu` - для `VGPU` + - `pkg/cloudbroker/vfpool` - для `VFPool` - `pkg/cloudbroker/vins` - для `VINS` Все поля структуры имеют описание, в которых содержится: @@ -453,6 +473,7 @@ func main() { - `.Sizes()` - для работы с `Sizes` - `.Stack()` - для работы с `Stack` - `.Tasks()` - для работы с `Tasks` + - `.VFPool()` - для работы с `VFPool` - `.VINS()` - для работы с `VINS` Доступные методы для `.CloudBroker()`: @@ -472,6 +493,7 @@ func main() { - `.KVMPPC()` - для работы с `KVMPPC` - `.KVMx86()` - для работы с `KVMX86` - `.LB()` - для работы с `LB` + - `.Node()` - для работы с `Node` - `.PCIDevice()` - для работы с `PCIDevice` - `.RG()` - для работы с `RG` - `.SEP()` - для работы с `SEP` @@ -479,6 +501,7 @@ func main() { - `.Tasks()` - для работы с `Tasks` - `.User()` - для работы с `User` - `.VGPU()` - для работы с `VGPU` + - `.VFPool()` - для работы с `VFPool` - `.VINS()` - для работы с `VINS` 3. Вызвать метод, отвечающий за выполнение запроса и передать в него: @@ -828,6 +851,87 @@ func main() { } ``` +### Методы поля Result для группы tasks + +Поле Result внутри структур группы tasks имеет тип интерфейс и может содержать: +- строку о результате выполнения задачи, например `true` +- массив, содержащий ID и имя созданного ресурса, например `[12345, "resource_name"]` +- массив, содержащий информацию о восстновленных дисках, например `[{"computeId": 123, "diskId": 456}, {"computeId": 789, "diskId": 10}]` + +Соответственно, для получения информации из поля Result доступны следующие методы: +- ToString(): строковое представление результата выполнения задачи +- ID() и Name(): получение ID и имени созданного в результате выполнения задачи ресурса +- ToMaps(): получение списка карт, содержащих информацию о дисках, восстановленных в результате выполнения задачи. +Все методы оборудованы возвратом ошибок. Непустая ошибка означает, что из поля Result нельзя получить информацию, которую предоставляет метод. + +```go +package main + +import ( + "log" + "fmt" + + "repository.basistech.ru/BASIS/decort-golang-sdk/config" + decort "repository.basistech.ru/BASIS/decort-golang-sdk" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/tasks" + tasks_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/tasks" +) + +func main() { + // Настройка конфигурации + cfg := config.Config{ + AppID: "", + AppSecret: "", + SSOURL: "https://sso.digitalenergy.online", + DecortURL: "https://mr4.digitalenergy.online", + Retries: 5, + } + + // Создание клиента + client := decort.New(cfg) + + // Создание структуры запроса GetRequest на получение информации о конкретной задаче и выполнение запроса с помощью конвейера + getReq := tasks.GetRequest{ + AuditID: "b6316", + } + task, err := client.CloudAPI().Tasks().Get(context.Background(), getReq) + if err != nil { + log.Fatal(err) + } + + // Получение списка карт с информацией о восстановленных дисках + maps, err := task.Result.ToMaps() + if err != nil { + log.Fatal(err) + } + fmt.Println(maps) + + // Получение строкового результата выполнения задачи task + res, _ := task.Result.ToString() + fmt.Println(res) + + // Создание структуры запроса ListRequest на получение информации о всех задачах и выполнение запроса с помощью конвейера + listReq := tasks_cb.ListRequest{} + tasks, err := client.CloudBroker().Tasks().List(context.Background(), listReq) + if err != nil { + log.Fatal(err) + } + + for _, t := range tasks { + // Получение id ресурса, созданного в результате выполнения задачи t + id, err := task.Result.ID() + if err != nil { + log.Fatal(err) + } + fmt.Println(id) + + // Получение имени ресурса, созданного в результате выполнения задачи t + name, _ := task.Result.Name() + fmt.Println(name) + } +} +``` + ## Работа с legacy клиентом Работа с legacy клиентом применяется для пользователей, которые не используют для авторизации decs3o. @@ -1290,3 +1394,65 @@ func main() { fmt.Println(res) } ``` +#### Пример валидации запросов, имеющих в своей структуре поле RAM (или MasterRam/WorkerRAM) + +Если структура запроса содержит поле RAM (или MasterRam/WorkerRAM), то он может быть проверен на валидность. Для этого запрос должен быть передан в функцию ValidateRAM. Вторым аргументом ValidateRAM ожидает число uint64. Рекомендуется использовать константу constants.RAM_DIVISIBILITY. Функция проверит кратно ли значение поля RAM (или MasterRam/WorkerRAM) этому числу. + +#### Пример выполнения запроса + +```go +package main + +import ( + "context" + "fmt" + "log" + "os" + + decort "repository.basistech.ru/BASIS/decort-golang-sdk" + "repository.basistech.ru/BASIS/decort-golang-sdk/config" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/kvmx86" +) + +func main() { + // Настройка конфигурации + cfg := config.Config{ + AppID: "", + AppSecret: "", + SSOURL: "https://sso-delta.qa.loc:8443", + DecortURL: "https://delta.qa.loc", + Retries: 5, + SSLSkipVerify: true, + } + + // Создание клиента + client := decort.New(cfg) + + // Создание структуры запроса + // CreateRequest - реквест на создание виртуальной машины + req := kvmx86.CreateRequest{ + Name: "kvmx86", + RGID: 907, + CPU: 2048, + RAM: 1024, + ImageID: 161, + } + + // Валидация запроса + err := validators.ValidateRAM(req, constants.RAM_DIVISIBILITY) + if err != nil { + log.Fatalf("unable to validate request: %v", err) + } + //Выполнение запроса с помощью конвейера + res, err := client.CloudBroker().KVMX86().Create(context.Background(), req) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + log.Println(res) + +} +``` \ No newline at end of file diff --git a/client.go b/client.go index 730d923..b248244 100644 --- a/client.go +++ b/client.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/tls" + "encoding/json" "fmt" "io" "mime/multipart" @@ -77,7 +78,7 @@ func (dc *DecortClient) DecortApiCall(ctx context.Context, method, url string, p body := bytes.NewBufferString(values.Encode()) - req, err := http.NewRequestWithContext(ctx, method, dc.decortURL+constants.Restmachine+url, body) + req, err := http.NewRequestWithContext(ctx, method, dc.decortURL+constants.RESTMACHINE+url, body) if err != nil { return nil, err } @@ -103,7 +104,7 @@ func (dc *DecortClient) DecortApiCallMP(ctx context.Context, method, url string, return nil, err } - req, err := http.NewRequestWithContext(ctx, method, dc.decortURL+constants.Restmachine+url, body) + req, err := http.NewRequestWithContext(ctx, method, dc.decortURL+constants.RESTMACHINE+url, body) if err != nil { return nil, err } @@ -303,10 +304,20 @@ func multiPartReq(params interface{}) (*bytes.Buffer, string, error) { return &bytes.Buffer{}, "", err } } + case []map[string]interface{}: + for _, val := range slice { + encodeStr, err := json.Marshal(val) + if err != nil { + return &bytes.Buffer{}, "", err + } + err = writer.WriteField(trimString(types.Field(i)), string(encodeStr)) + if err != nil { + return &bytes.Buffer{}, "", err + } + } default: return &bytes.Buffer{}, "", fmt.Errorf("unsupported slice type:%T", slice) } - continue } diff --git a/client_bvs.go b/client_bvs.go index 80c449c..8b02bb6 100644 --- a/client_bvs.go +++ b/client_bvs.go @@ -78,7 +78,7 @@ func (bdc *BVSDecortClient) DecortApiCall(ctx context.Context, method, url strin body := bytes.NewBufferString(values.Encode()) - req, err := http.NewRequestWithContext(ctx, method, bdc.decortURL+constants.Restmachine+url, body) + req, err := http.NewRequestWithContext(ctx, method, bdc.decortURL+constants.RESTMACHINE+url, body) if err != nil { return nil, err } @@ -128,7 +128,7 @@ func (bdc *BVSDecortClient) DecortApiCallMP(ctx context.Context, method, url str return nil, err } - req, err := http.NewRequestWithContext(ctx, method, bdc.decortURL+constants.Restmachine+url, body) + req, err := http.NewRequestWithContext(ctx, method, bdc.decortURL+constants.RESTMACHINE+url, body) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 18fb1e0..782c22a 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/go-playground/validator/v10 v10.11.2 github.com/google/go-querystring v1.1.0 + github.com/joho/godotenv v1.5.1 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 52f813c..a63c3b7 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= diff --git a/interfaces/request.go b/interfaces/request.go new file mode 100644 index 0000000..6d1066b --- /dev/null +++ b/interfaces/request.go @@ -0,0 +1,7 @@ +package interfaces + +// Interface to valiate RAM values +type RequestWithRAM interface { + // GetRAM returns RAM values + GetRAM() map[string]uint64 +} diff --git a/internal/constants/constants.go b/internal/constants/constants.go index b48202e..8385511 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -1,6 +1,11 @@ package constants -const Restmachine = "/restmachine" +const ( + RESTMACHINE = "/restmachine" + + // RAM_DIVISIBILITY sets divisibility of RAM value + RAM_DIVISIBILITY uint64 = 128 +) var FileName = map[string]string{ "OidcCertificate": "ca.crt", diff --git a/internal/validators/custom.go b/internal/validators/custom.go index ee6db50..ba9352b 100644 --- a/internal/validators/custom.go +++ b/internal/validators/custom.go @@ -1,31 +1,35 @@ package validators import ( + "errors" + "fmt" "regexp" "strings" "github.com/go-playground/validator/v10" + "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/multierror" ) // computeDriverValidator is used to validate Driver field in kvmx86/kvmppc create. func computeDriverValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, computeDriverValues) + return IsInSlice(fieldValue, computeDriverValues) } // protoValidator is used to validate Proto fields. func protoValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, protoValues) + return IsInSlice(fieldValue, protoValues) } // accessTypeValidator is used to validate AccessType fields. func accessTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, accessTypeValues) + return IsInSlice(fieldValue, accessTypeValues) } // resTypesValidator is used to validate ResTypes fields. @@ -36,7 +40,7 @@ func resTypesValidator(fe validator.FieldLevel) bool { } for _, value := range fieldSlice { - if !StringInSlice(value, resTypesValues) { + if !IsInSlice(value, resTypesValues) { return false } } @@ -48,56 +52,56 @@ func resTypesValidator(fe validator.FieldLevel) bool { func driverValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, driverValues) + return IsInSlice(fieldValue, driverValues) } // accountCUTypeValidator is used to validate CUType field. func accountCUTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, accountCUTypeValues) + return IsInSlice(fieldValue, accountCUTypeValues) } // bserviceModeValidator is used to validate Mode field. func bserviceModeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, bserviceModeValues) + return IsInSlice(fieldValue, bserviceModeValues) } // computeTopologyValidator is used to validate Topology field. func computeTopologyValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, computeTopologyValues) + return IsInSlice(fieldValue, computeTopologyValues) } // computePolicyValidator is used to validate Policy field. func computePolicyValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, computePolicyValues) + return IsInSlice(fieldValue, computePolicyValues) } // computeModeValidator is used to validate Mode field. func computeModeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, computeModeValues) + return IsInSlice(fieldValue, computeModeValues) } // computeDiskTypeValidator is used to validate DiskType field. func computeDiskTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, computeDiskTypeValues) + return IsInSlice(fieldValue, computeDiskTypeValues) } // computeNetTypeValidator is used to validate NetType field. func computeNetTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, computeNetTypeValues) + return IsInSlice(fieldValue, computeNetTypeValues) } // computeOrderValidator is used to validate Order field. @@ -108,7 +112,7 @@ func computeOrderValidator(fe validator.FieldLevel) bool { } for _, value := range fieldSlice { - if !StringInSlice(value, computeOrderValues) { + if !IsInSlice(value, computeOrderValues) { return false } } @@ -120,70 +124,70 @@ func computeOrderValidator(fe validator.FieldLevel) bool { func computeDataDisksValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, computeDataDisksValues) + return IsInSlice(fieldValue, computeDataDisksValues) } // diskTypeValidator is used to validate Type field. func diskTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, diskTypeValues) + return IsInSlice(fieldValue, diskTypeValues) } // flipgroupClientTypeValidator is used to validate ClientType field. func flipgroupClientTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, flipgroupClientTypeValues) + return IsInSlice(fieldValue, flipgroupClientTypeValues) } // kvmNetTypeValidator is used to validate NetType field. func kvmNetTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, kvmNetTypeValues) + return IsInSlice(fieldValue, kvmNetTypeValues) } // lbAlgorithmValidator is used to validate Algorithm field. func lbAlgorithmValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, lbAlgorithmValues) + return IsInSlice(fieldValue, lbAlgorithmValues) } // rgDefNetValidator is used to validate DefNet field. func rgDefNetValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, rgDefNetValues) + return IsInSlice(fieldValue, rgDefNetValues) } // rgNetTypeValidator is used to validate NetType field. func rgNetTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, rgNetTypeValues) + return IsInSlice(fieldValue, rgNetTypeValues) } // vinsTypeValidator is used to validate Type field. func vinsTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, vinsTypeValues) + return IsInSlice(fieldValue, vinsTypeValues) } // imageBootTypeValidator is used to validate BootType field. func imageBootTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, imageBootTypeValues) + return IsInSlice(fieldValue, imageBootTypeValues) } // imageTypeValidator is used to validate ImageType field. func imageTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, imageTypeValues) + return IsInSlice(fieldValue, imageTypeValues) } // imageDriversValidator is used to validate Drivers field. @@ -194,7 +198,7 @@ func imageDriversValidator(fe validator.FieldLevel) bool { } for _, item := range fieldSlice { - if !StringInSlice(item, imageDriversValues) { + if !IsInSlice(item, imageDriversValues) { return false } } @@ -206,14 +210,14 @@ func imageDriversValidator(fe validator.FieldLevel) bool { func imageArchitectureValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, imageArchitectureValues) + return IsInSlice(fieldValue, imageArchitectureValues) } // sepFieldTypeValidator is used to validate FieldType field. func sepFieldTypeValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() - return StringInSlice(fieldValue, sepFieldTypeValues) + return IsInSlice(fieldValue, sepFieldTypeValues) } // hwPathValidator is used to validate HWPath field. @@ -230,7 +234,7 @@ func networkPluginValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() fieldValue = strings.ToLower(fieldValue) - return StringInSlice(fieldValue, networkPluginValues) + return IsInSlice(fieldValue, networkPluginValues) } // networkPluginsValidator is used to validate NetworkPlugins field @@ -243,7 +247,7 @@ func networkPluginsValidator(fe validator.FieldLevel) bool { for _, item := range fieldSlice { item = strings.ToLower(item) - if !StringInSlice(item, networkPluginValues) { + if !IsInSlice(item, networkPluginValues) { return false } } @@ -255,14 +259,14 @@ func interfaceStateValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() fieldValue = strings.ToLower(fieldValue) - return StringInSlice(fieldValue, interfaceStateValues) + return IsInSlice(fieldValue, interfaceStateValues) } func strictLooseValidator(fe validator.FieldLevel) bool { fieldValue := fe.Field().String() fieldValue = strings.ToLower(fieldValue) - return StringInSlice(fieldValue, strictLooseValues) + return IsInSlice(fieldValue, strictLooseValues) } // name workerGroup must be more 3 symbol @@ -272,3 +276,60 @@ func workerGroupNameValidator(fe validator.FieldLevel) bool { return len(fieldValue) >= 3 } + +func sortByValidator(fe validator.FieldLevel) bool { + + sortByRegexp := regexp.MustCompile(`^[+-][a-zA-Z_]+`) + + return sortByRegexp.MatchString(fe.Field().String()) +} + +func actionValidator(fe validator.FieldLevel) bool { + fieldValue := fe.Field().String() + + return IsInSlice(fieldValue, actionValues) +} + +func vmActionValidator(fe validator.FieldLevel) bool { + fieldValue := fe.Field().String() + + return IsInSlice(fieldValue, vmActionValues) +} + +func computeFeaturesValidator(fe validator.FieldLevel) bool { + field := fe.Field() + slice, ok := field.Interface().([]string) + if !ok { + return false + } + + return IsSubSlice(slice, computeFeaturesValues) +} + +func networkInterfaceNamingValidator(fe validator.FieldLevel) bool { + fieldValue := fe.Field().String() + + return IsInSlice(fieldValue, networkInterfaceNamingValues) +} + +// ValidateRAM checks if request contains RAM value that is positive integer divisible by divisibility passed. +// It is recommended to pass constants.RAM_DIVISIBILITY as divisility arguement +func ValidateRAM(r interfaces.RequestWithRAM, divisibility uint64) error { + + if divisibility == 0 { + + return errors.New("second argument of ValidateRAM should be greater than 0") + } + mapRAM := r.GetRAM() + + errs := make([]error, 0, len(mapRAM)) + + for k, v := range mapRAM { + + if v%divisibility != 0 { + + errs = append(errs, fmt.Errorf("expected value of %s: \"%d\" should be divisible by %d", k, v, divisibility)) + } + } + return multierror.Join(errs...) +} diff --git a/internal/validators/helper.go b/internal/validators/helper.go index 72251cf..7430751 100644 --- a/internal/validators/helper.go +++ b/internal/validators/helper.go @@ -34,7 +34,7 @@ func GetErrors(err error) validator.ValidationErrors { return err.(validator.ValidationErrors) } -func StringInSlice(str string, target []string) bool { +func IsInSlice(str string, target []string) bool { for _, v := range target { if v == str { return true @@ -42,3 +42,12 @@ func StringInSlice(str string, target []string) bool { } return false } + +func IsSubSlice(source []string, target []string) bool { + for _, s := range source { + if !IsInSlice(s, target) { + return false + } + } + return true +} diff --git a/internal/validators/messages.go b/internal/validators/messages.go index 9cb72c8..35f1c85 100644 --- a/internal/validators/messages.go +++ b/internal/validators/messages.go @@ -229,6 +229,35 @@ func errorMessage(fe validator.FieldError) string { prefix, fe.Field(), joinValues(interfaceStateValues)) + + case "sortBy": + return fmt.Sprintf("%s %s must be in format +|-(field)", + prefix, + fe.Field()) + + case "action": + return fmt.Sprintf("%s %s must be one of the following: %s", + prefix, + fe.Field(), + joinValues(actionValues)) + + case "vmaction": + return fmt.Sprintf("%s %s must be one of the following: %s", + prefix, + fe.Field(), + joinValues(vmActionValues)) + + case "computeFeatures": + return fmt.Sprintf("%s %s must be one of the following: %s", + prefix, + fe.Field(), + joinValues(computeFeaturesValues)) + + case "networkInterfaceNaming": + return fmt.Sprintf("%s %s must be one of the following: %s", + prefix, + fe.Field(), + joinValues(networkInterfaceNamingValues)) } return fe.Error() diff --git a/internal/validators/validator.go b/internal/validators/validator.go index fd8017e..2a00437 100644 --- a/internal/validators/validator.go +++ b/internal/validators/validator.go @@ -25,6 +25,7 @@ func getDecortValidator() *validator.Validate { // registerAllValidators registers all custom validators in DecortValidator. func registerAllValidators(validate *validator.Validate) error { + err := validate.RegisterValidation("proto", protoValidator) if err != nil { return err @@ -185,5 +186,30 @@ func registerAllValidators(validate *validator.Validate) error { return err } + err = validate.RegisterValidation("sortBy", sortByValidator) + if err != nil { + return err + } + + err = validate.RegisterValidation("action", actionValidator) + if err != nil { + return err + } + + err = validate.RegisterValidation("vmaction", vmActionValidator) + if err != nil { + return err + } + + err = validate.RegisterValidation("computeFeatures", computeFeaturesValidator) + if err != nil { + return err + } + + err = validate.RegisterValidation("networkInterfaceNaming", networkInterfaceNamingValidator) + if err != nil { + return err + } + return nil } diff --git a/internal/validators/values.go b/internal/validators/values.go index c90843f..2bcd22a 100644 --- a/internal/validators/values.go +++ b/internal/validators/values.go @@ -44,4 +44,12 @@ var ( strictLooseValues = []string{"strict", "loose"} interfaceStateValues = []string{"on", "off"} + + actionValues = []string{"power_on", "shutdown", "force_shutdown", "reboot"} + + vmActionValues = []string{"stop", "move"} + + computeFeaturesValues = []string{"hugepages", "numa", "cpupin", "vfnic"} + + networkInterfaceNamingValues = []string{"eth", "ens"} ) diff --git a/legacy-client.go b/legacy-client.go index 01293cd..4d4a7a4 100644 --- a/legacy-client.go +++ b/legacy-client.go @@ -80,7 +80,7 @@ func (ldc *LegacyDecortClient) DecortApiCall(ctx context.Context, method, url st body := bytes.NewBufferString(values.Encode() + fmt.Sprintf("&authkey=%s", ldc.cfg.Token)) - req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+constants.Restmachine+url, body) + req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+constants.RESTMACHINE+url, body) if err != nil { return nil, err } @@ -100,7 +100,7 @@ func (ldc *LegacyDecortClient) DecortApiCallMP(ctx context.Context, method, url return nil, err } - req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+constants.Restmachine+url, body) + req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+constants.RESTMACHINE+url, body) if err != nil { return nil, err } @@ -132,7 +132,7 @@ func (ldc *LegacyDecortClient) getToken(ctx context.Context) error { body := fmt.Sprintf("username=%s&password=%s", url.QueryEscape(ldc.cfg.Username), url.QueryEscape(ldc.cfg.Password)) bodyReader := strings.NewReader(body) - req, _ := http.NewRequestWithContext(ctx, "POST", ldc.cfg.DecortURL+"/restmachine/cloudapi/user/authenticate", bodyReader) + req, _ := http.NewRequestWithContext(ctx, "POST", ldc.cfg.DecortURL+constants.RESTMACHINE+"/cloudapi/user/authenticate", bodyReader) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") // request token diff --git a/pkg/cloudapi/account/get_consumption.go b/pkg/cloudapi/account/get_consumption.go index 064133a..2044323 100644 --- a/pkg/cloudapi/account/get_consumption.go +++ b/pkg/cloudapi/account/get_consumption.go @@ -15,11 +15,11 @@ type GetConsumptionRequest struct { // Epoch represents the start time // Required: true - Start uint64 `url:"start" json:"start" validate:"required"` + Start float64 `url:"start" json:"start" validate:"required"` // Epoch represents the end time // Required: true - End uint64 `url:"end" json:"end" validate:"required"` + End float64 `url:"end" json:"end" validate:"required"` } // GetConsumption downloads the resources tracking files for an account within a given period diff --git a/pkg/cloudapi/account/list.go b/pkg/cloudapi/account/list.go index 2d5bff9..81d355a 100644 --- a/pkg/cloudapi/account/list.go +++ b/pkg/cloudapi/account/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of accounts @@ -24,6 +26,10 @@ type ListRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -35,6 +41,7 @@ type ListRequest struct { // List gets a list of all accounts the user has access to a ListAccounts struct func (a Account) List(ctx context.Context, req ListRequest) (*ListAccounts, error) { + res, err := a.ListRaw(ctx, req) if err != nil { return nil, err @@ -52,6 +59,11 @@ func (a Account) List(ctx context.Context, req ListRequest) (*ListAccounts, erro // ListRaw gets a list of all accounts the user has access to as an array of bytes func (a Account) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/account/list" res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/account/list_computes.go b/pkg/cloudapi/account/list_computes.go index f8e4be0..588fc02 100644 --- a/pkg/cloudapi/account/list_computes.go +++ b/pkg/cloudapi/account/list_computes.go @@ -46,6 +46,10 @@ type ListComputesRequest struct { // Required: false ExtNetID uint64 `url:"extNetId,omitempty" json:"extNetId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -57,6 +61,7 @@ type ListComputesRequest struct { // ListComputes gets list all compute instances under specified account, accessible by the user func (a Account) ListComputes(ctx context.Context, req ListComputesRequest) (*ListComputes, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/account/list_deleted.go b/pkg/cloudapi/account/list_deleted.go index 18c836c..f99db1b 100644 --- a/pkg/cloudapi/account/list_deleted.go +++ b/pkg/cloudapi/account/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get a list of deleted accounts @@ -27,10 +29,20 @@ type ListDeletedRequest struct { // Find by access control list // Required: false ACL string `url:"acl,omitempty" json:"acl,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` } // ListDeleted gets list of all deleted accounts the user has access to func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListAccounts, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/account/listDeleted" res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/account/list_disks.go b/pkg/cloudapi/account/list_disks.go index 7936d99..5649a93 100644 --- a/pkg/cloudapi/account/list_disks.go +++ b/pkg/cloudapi/account/list_disks.go @@ -30,6 +30,10 @@ type ListDisksRequest struct { // Required: false Type string `url:"type,omitempty" json:"type,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListDisksRequest struct { // ListDisks gets list all currently unattached disks under specified account func (a Account) ListDisks(ctx context.Context, req ListDisksRequest) (*ListDisks, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/account/list_flipgroups.go b/pkg/cloudapi/account/list_flipgroups.go index 5653fbf..0259dde 100644 --- a/pkg/cloudapi/account/list_flipgroups.go +++ b/pkg/cloudapi/account/list_flipgroups.go @@ -49,6 +49,7 @@ type ListFLIPGroupsRequest struct { // ListFLIPGroups gets list all FLIPGroups under specified account, accessible by the user func (a Account) ListFLIPGroups(ctx context.Context, req ListFLIPGroupsRequest) (*ListFLIPGroups, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/account/list_rg.go b/pkg/cloudapi/account/list_rg.go index 5fa767b..ab76857 100644 --- a/pkg/cloudapi/account/list_rg.go +++ b/pkg/cloudapi/account/list_rg.go @@ -41,10 +41,15 @@ type ListRGRequest struct { // Find by status // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` } // ListRG gets list of all resource groups under specified account, accessible by the user func (a Account) ListRG(ctx context.Context, req ListRGRequest) (*ListRG, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/account/list_templates.go b/pkg/cloudapi/account/list_templates.go index 29fb973..745226f 100644 --- a/pkg/cloudapi/account/list_templates.go +++ b/pkg/cloudapi/account/list_templates.go @@ -30,6 +30,10 @@ type ListTemplatesRequest struct { // Required: false Type string `url:"type,omitempty" json:"type,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListTemplatesRequest struct { // ListTemplates gets list of templates which can be managed by this account func (a Account) ListTemplates(ctx context.Context, req ListTemplatesRequest) (*ListTemplates, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/account/list_vins.go b/pkg/cloudapi/account/list_vins.go index fe07e5e..8b96c54 100644 --- a/pkg/cloudapi/account/list_vins.go +++ b/pkg/cloudapi/account/list_vins.go @@ -30,6 +30,10 @@ type ListVINSRequest struct { // Required: false ExtIP string `url:"extIp,omitempty" json:"extIp,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListVINSRequest struct { // ListVINS gets list of all ViNSes under specified account, accessible by the user func (a Account) ListVINS(ctx context.Context, req ListVINSRequest) (*ListVINS, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/account/models.go b/pkg/cloudapi/account/models.go index 871cc87..8a3a4e1 100644 --- a/pkg/cloudapi/account/models.go +++ b/pkg/cloudapi/account/models.go @@ -53,6 +53,9 @@ type ItemAccount struct { // Access Control List ACL []RecordACL `json:"acl"` + // Compute Features + ComputeFeatures []string `json:"computeFeatures"` + // Created time CreatedTime uint64 `json:"createdTime"` @@ -176,6 +179,9 @@ type RecordAccount struct { // Company URL CompanyURL string `json:"companyurl"` + // Compute Features + ComputeFeatures []string `json:"computeFeatures"` + // Computes Computes Computes `json:"computes"` @@ -374,6 +380,12 @@ type ItemVINS struct { // External IP ExternalIP string `json:"externalIP"` + // Extnet ID + ExtnetId uint64 `json:"extnetId"` + + // Free IPs + FreeIPs uint64 `json:"freeIPs"` + // ID ID uint64 `json:"id"` diff --git a/pkg/cloudapi/bservice/group_add.go b/pkg/cloudapi/bservice/group_add.go index 645c63e..60ce80f 100644 --- a/pkg/cloudapi/bservice/group_add.go +++ b/pkg/cloudapi/bservice/group_add.go @@ -74,6 +74,16 @@ type GroupAddRequest struct { UserData string `url:"userData,omitempty" json:"userData,omitempty"` } +// GetRAM returns RAM field values +func (r GroupAddRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + // GroupAdd creates new Compute Group within BasicService. // Compute Group is NOT started automatically, // so you need to explicitly start it diff --git a/pkg/cloudapi/bservice/group_update.go b/pkg/cloudapi/bservice/group_update.go index d2a8d74..63f87c5 100644 --- a/pkg/cloudapi/bservice/group_update.go +++ b/pkg/cloudapi/bservice/group_update.go @@ -43,6 +43,16 @@ type GroupUpdateRequest struct { Force bool `url:"force,omitempty" json:"force,omitempty"` } +// GetRAM returns RAM field values +func (r GroupUpdateRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + // GroupUpdate updates existing Compute group within Basic Service and apply new settings to its computes as necessary func (b BService) GroupUpdate(ctx context.Context, req GroupUpdateRequest) (bool, error) { err := validators.ValidateRequest(req) diff --git a/pkg/cloudapi/bservice/list.go b/pkg/cloudapi/bservice/list.go index b100579..31734c7 100644 --- a/pkg/cloudapi/bservice/list.go +++ b/pkg/cloudapi/bservice/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of BasicService instances @@ -40,6 +42,10 @@ type ListRequest struct { // Required: false AccountName string `url:"accountName,omitempty" json:"accountName,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -51,6 +57,7 @@ type ListRequest struct { // List gets list of BasicService instances associated with the specified Resource Group as a ListBasicServices struct func (b BService) List(ctx context.Context, req ListRequest) (*ListBasicServices, error) { + res, err := b.ListRaw(ctx, req) if err != nil { return nil, err @@ -68,6 +75,11 @@ func (b BService) List(ctx context.Context, req ListRequest) (*ListBasicServices // ListRaw gets list of BasicService instances associated with the specified Resource Group as an array of bytes func (b BService) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/bservice/list" res, err := b.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/bservice/list_deleted.go b/pkg/cloudapi/bservice/list_deleted.go index 4375435..a07eb44 100644 --- a/pkg/cloudapi/bservice/list_deleted.go +++ b/pkg/cloudapi/bservice/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted BasicService instances @@ -16,6 +18,10 @@ type ListDeletedRequest struct { // Required: false RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -27,6 +33,11 @@ type ListDeletedRequest struct { // ListDeleted gets list of deleted BasicService instances associated with the specified Resource Group func (b BService) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListBasicServices, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/bservice/listDeleted" res, err := b.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/compute/affinity_rule_add.go b/pkg/cloudapi/compute/affinity_rule_add.go index 0f41357..1e0d08e 100644 --- a/pkg/cloudapi/compute/affinity_rule_add.go +++ b/pkg/cloudapi/compute/affinity_rule_add.go @@ -39,6 +39,7 @@ type AffinityRuleAddRequest struct { // Value that must match the key to be taken into account when analyzing this rule // Required: false + // Not required on purpose: despite required tag on platform, empty string is allowed Value string `url:"value" json:"value"` } diff --git a/pkg/cloudapi/compute/affinity_rule_remove.go b/pkg/cloudapi/compute/affinity_rule_remove.go index 2460621..6cf8fda 100644 --- a/pkg/cloudapi/compute/affinity_rule_remove.go +++ b/pkg/cloudapi/compute/affinity_rule_remove.go @@ -39,6 +39,7 @@ type AffinityRuleRemoveRequest struct { // Value that must match the key to be taken into account when analyzing this rule // Required: false + // Not required on purpose: despite required tag on platform, empty string is allowed Value string `url:"value" json:"value"` } diff --git a/pkg/cloudapi/compute/anti_affinity_rule_add.go b/pkg/cloudapi/compute/anti_affinity_rule_add.go index cb2f65d..9b817a7 100644 --- a/pkg/cloudapi/compute/anti_affinity_rule_add.go +++ b/pkg/cloudapi/compute/anti_affinity_rule_add.go @@ -39,6 +39,7 @@ type AntiAffinityRuleAddRequest struct { // Value that must match the key to be taken into account when analyzing this rule // Required: false + // Not required on purpose: despite required tag on platform, empty string is allowed Value string `url:"value" json:"value"` } diff --git a/pkg/cloudapi/compute/anti_affinity_rule_remove.go b/pkg/cloudapi/compute/anti_affinity_rule_remove.go index 0f3363f..1c0adf1 100644 --- a/pkg/cloudapi/compute/anti_affinity_rule_remove.go +++ b/pkg/cloudapi/compute/anti_affinity_rule_remove.go @@ -39,6 +39,7 @@ type AntiAffinityRuleRemoveRequest struct { // Value that must match the key to be taken into account when analyzing this rule // Required: false + // Not required on purpose: despite required tag on platform, empty string is allowed Value string `url:"value" json:"value"` } diff --git a/pkg/cloudapi/compute/boot_disk_set.go b/pkg/cloudapi/compute/boot_disk_set.go new file mode 100644 index 0000000..765c0a5 --- /dev/null +++ b/pkg/cloudapi/compute/boot_disk_set.go @@ -0,0 +1,42 @@ +package compute + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// BootDiskSetRequest struct to set boot disk for compute +type BootDiskSetRequest struct { + // ID of compute instance + // Required: true + ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + + // ID of the disk to set as boot + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// BootDiskSet sets boot disk for compute +func (c Compute) BootDiskSet(ctx context.Context, req BootDiskSetRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/compute/bootDiskSet" + + 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 new file mode 100644 index 0000000..71294f7 --- /dev/null +++ b/pkg/cloudapi/compute/create_template_from_blank.go @@ -0,0 +1,112 @@ +package compute + +import ( + "context" + "net/http" + "strconv" + "strings" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// CreateTemplateFromBlankRequest struct to create template from boot disk of current compute +type CreateTemplateFromBlankRequest struct { + // ID of the compute to create template from + // Required: true + ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + + // Name of the rescue disk + // Required: true + Name string `url:"name" json:"name" validate:"required"` + + // Boot type of image BIOS or UEFI + // Required: true + BootType string `url:"boottype" json:"boottype" validate:"imageBootType"` + + // Image type linux, windows or other + // Required: true + ImageType string `url:"imagetype" json:"imagetype" validate:"imageType"` + + // Username for the image + // Required: false + Username string `url:"username,omitempty" json:"username,omitempty"` + + // Password for the image + // Required: false + Password string `url:"password,omitempty" json:"password,omitempty"` + + // Account ID to make the image exclusive + // Required: false + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + + // SEP ID + // Required: false + SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"` + + // Pool for image create + // Required: false + PoolName string `url:"poolName,omitempty" json:"poolName,omitempty"` + + // Does this machine supports hot resize + // Default: false + // Required: false + HotResize bool `url:"hotresize" json:"hotresize"` +} + +type wrapperCreateTemplateFromBlankRequest struct { + CreateTemplateFromBlankRequest + AsyncMode bool `url:"asyncMode"` +} + +// CreateTemplateFromBlank creates template from boot disk of current compute in sync mode. +// It returns id of created compute and error. +func (c Compute) CreateTemplateFromBlank(ctx context.Context, req CreateTemplateFromBlankRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + reqWrapped := wrapperCreateTemplateFromBlankRequest{ + CreateTemplateFromBlankRequest: req, + AsyncMode: false, + } + + url := "/cloudapi/compute/createTemplateFromBlank" + + res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) + if err != nil { + return 0, err + } + + result, err := strconv.ParseUint(string(res), 10, 64) + if err != nil { + return 0, err + } + + return result, nil +} + +// CreateTemplateFromBlankAsync creates template from boot disk of current compute in async mode. +// It returns guid of task and error. +func (c Compute) CreateTemplateFromBlankAsync(ctx context.Context, req CreateTemplateFromBlankRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + reqWrapped := wrapperCreateTemplateFromBlankRequest{ + CreateTemplateFromBlankRequest: req, + AsyncMode: true, + } + + url := "/cloudapi/compute/createTemplateFromBlank" + + res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) + if err != nil { + return "", err + } + + result := strings.ReplaceAll(string(res), "\"", "") + + return result, nil +} diff --git a/pkg/cloudapi/compute/disk_migrate.go b/pkg/cloudapi/compute/disk_migrate.go new file mode 100644 index 0000000..5f797c8 --- /dev/null +++ b/pkg/cloudapi/compute/disk_migrate.go @@ -0,0 +1,53 @@ +package compute + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DiskMigrateRequest struct to migrate compute's disk to target disk +type DiskMigrateRequest struct { + // ID of compute instance + // Required: true + ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + + // ID source disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` + + // ID target disk + // Required: true + TargetDiskID uint64 `url:"targetDiskId" json:"targetDiskId" validate:"required"` + + // Migration mode. 1 - Data migration and domain update were already completed by third-party software. + // Use this if target disk already connected to compute and you only need to save changes for next reboot. + // Required: true + Mode int64 `url:"mode" json:"mode" validate:"required"` +} + +// DiskMigrate - migrate compute's disk to target disk. Source disk will be detached, target disk will be attached to the same PCI slot. +// (WARNING) Current realisation is limited. No actual data migration will be performed. +// Use this API if target disk already connected to compute and you only need to save changes for next reboot (mode: 1). +func (c Compute) DiskMigrate(ctx context.Context, req DiskMigrateRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/compute/diskMigrate" + + 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/disk_switch_to_replication.go b/pkg/cloudapi/compute/disk_switch_to_replication.go new file mode 100644 index 0000000..82e141d --- /dev/null +++ b/pkg/cloudapi/compute/disk_switch_to_replication.go @@ -0,0 +1,46 @@ +package compute + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DiskSwitchToReplicationRequest struct to switch disk to it's replication +type DiskSwitchToReplicationRequest struct { + // ID of compute instance + // Required: true + ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + + // ID of the disk to switch + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` + + // Delete replication relationship + // Required: false + StopReplication bool `url:"stopReplication" json:"stopReplication"` +} + +// DiskSwitchToReplication switches disk to it's replication +func (c Compute) DiskSwitchToReplication(ctx context.Context, req DiskSwitchToReplicationRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/compute/diskSwitchToReplication" + + 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/list.go b/pkg/cloudapi/compute/list.go index d3860a1..6ec6b84 100644 --- a/pkg/cloudapi/compute/list.go +++ b/pkg/cloudapi/compute/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of available computes @@ -52,6 +54,10 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -64,6 +70,7 @@ type ListRequest struct { // List gets list of the available computes. // Filtering based on status is possible func (c Compute) List(ctx context.Context, req ListRequest) (*ListComputes, error) { + res, err := c.ListRaw(ctx, req) if err != nil { return nil, err @@ -81,6 +88,11 @@ func (c Compute) List(ctx context.Context, req ListRequest) (*ListComputes, erro // ListRaw gets list of the available computes. func (c Compute) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/compute/list" res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/compute/list_deleted.go b/pkg/cloudapi/compute/list_deleted.go index 66a305d..981ea76 100644 --- a/pkg/cloudapi/compute/list_deleted.go +++ b/pkg/cloudapi/compute/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get deleted computes list @@ -44,6 +46,10 @@ type ListDeletedRequest struct { // Required: false ExtNetID uint64 `url:"extNetId,omitempty" json:"extNetId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -55,6 +61,11 @@ type ListDeletedRequest struct { // ListDeleted gets list all deleted computes func (c Compute) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListComputes, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/compute/listDeleted" res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/compute/list_pci_device.go b/pkg/cloudapi/compute/list_pci_device.go index b900b5f..2c84179 100644 --- a/pkg/cloudapi/compute/list_pci_device.go +++ b/pkg/cloudapi/compute/list_pci_device.go @@ -30,6 +30,10 @@ type ListPCIDeviceRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListPCIDeviceRequest struct { // ListPCIDevice gets list PCI device func (c Compute) ListPCIDevice(ctx context.Context, req ListPCIDeviceRequest) (*ListPCIDevices, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/compute/list_vgpu.go b/pkg/cloudapi/compute/list_vgpu.go index e84983c..a119054 100644 --- a/pkg/cloudapi/compute/list_vgpu.go +++ b/pkg/cloudapi/compute/list_vgpu.go @@ -26,6 +26,10 @@ type ListVGPURequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListVGPURequest struct { // ListVGPU gets list vGPU func (c Compute) ListVGPU(ctx context.Context, req ListVGPURequest) (*ListVGPUs, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/compute/models.go b/pkg/cloudapi/compute/models.go index 39ea486..a2f46c9 100644 --- a/pkg/cloudapi/compute/models.go +++ b/pkg/cloudapi/compute/models.go @@ -305,6 +305,9 @@ type RecordCompute struct { // Boot disk size BootDiskSize uint64 `json:"bootdiskSize"` + // cd Image Id + CdImageId uint64 `json:"cdImageId"` + // Clone reference CloneReference uint64 `json:"cloneReference"` @@ -314,6 +317,9 @@ type RecordCompute struct { // Compute CI ID ComputeCIID uint64 `json:"computeciId"` + // CPU Pin + CPUPin bool `json:"cpupin"` + // Number of cores CPU uint64 `json:"cpus"` @@ -350,6 +356,9 @@ type RecordCompute struct { // GUID GUID uint64 `json:"guid"` + // HPBacked + HPBacked bool `json:"hpBacked"` + // ID ID uint64 `json:"id"` @@ -383,6 +392,12 @@ type RecordCompute struct { // NeedReboot NeedReboot bool `json:"needReboot"` + // Numa Affinity + NumaAffinity string `json:"numaAffinity"` + + //NumaNodeId + NumaNodeId int64 `json:"numaNodeId"` + // Natable VINS ID NatableVINSID uint64 `json:"natableVinsId"` @@ -539,6 +554,9 @@ type ItemVNFInterface struct { // Network type NetType string `json:"netType"` + // NodeID + NodeID int64 `json:"nodeId"` + // PCI slot PCISlot int64 `json:"pciSlot"` @@ -654,6 +672,9 @@ type ItemComputeDisk struct { // Reality device number RealityDeviceNumber uint64 `json:"realityDeviceNumber"` + // Replication + Replication interface{} `json:"replication"` + // Resource ID ResID string `json:"resId"` @@ -761,6 +782,7 @@ type IOTune struct { type ItemCompute struct { // Access Control List ACL ListACL `json:"acl"` + // Account ID AccountID uint64 `json:"accountId"` @@ -788,6 +810,9 @@ type ItemCompute struct { // Boot disk size BootDiskSize uint64 `json:"bootdiskSize"` + // cd Image Id + CdImageId uint64 `json:"cdImageId"` + // Clone reference CloneReference uint64 `json:"cloneReference"` @@ -797,6 +822,9 @@ type ItemCompute struct { // Compute CI ID ComputeCIID uint64 `json:"computeciId"` + // CPU Pin + CPUPin bool `json:"cpupin"` + // Number of cores CPU uint64 `json:"cpus"` @@ -833,6 +861,9 @@ type ItemCompute struct { // GUID GUID uint64 `json:"guid"` + // HPBacked + HPBacked bool `json:"hpBacked"` + // ID ID uint64 `json:"id"` @@ -863,6 +894,12 @@ type ItemCompute struct { // NeedReboot NeedReboot bool `json:"needReboot"` + // Numa Affinity + NumaAffinity string `json:"numaAffinity"` + + //NumaNodeId + NumaNodeId int64 `json:"numaNodeId"` + // Pinned or not Pinned bool `json:"pinned"` @@ -948,17 +985,106 @@ type ListComputes struct { // List VGPUs type ListVGPUs struct { // Data - Data []interface{} `json:"data"` + Data []ItemVGPU `json:"data"` // Entry count EntryCount uint64 `json:"entryCount"` } +// Main information about vgpu device +type ItemVGPU struct { + // Account ID + AccountID uint64 `json:"accountId"` + + // Created Time + CreatedTime uint64 `json:"createdTime"` + + // Deleted Time + DeletedTime uint64 `json:"deletedTime"` + + // GID + GID uint64 `json:"gid"` + + // GUID + GUID uint64 `json:"guid"` + + // ID + ID uint64 `json:"id"` + + // Last Claimed By + LastClaimedBy uint64 `json:"lastClaimedBy"` + + // Last Update Time + LastUpdateTime uint64 `json:"lastUpdateTime"` + + // Mode + Mode string `json:"mode"` + + // PCI Slot + PCISlot uint64 `json:"pciSlot"` + + // PGPUID + PGPUID uint64 `json:"pgpuid"` + + // Profile ID + ProfileID uint64 `json:"profileId"` + + // RAM + RAM uint64 `json:"ram"` + + // Reference ID + ReferenceID string `json:"referenceId"` + + // RG ID + RGID uint64 `json:"rgId"` + + // Status + Status string `json:"status"` + + // Type + Type string `json:"type"` + + // VM ID + VMID uint64 `json:"vmid"` +} + +// Main information about PCI device +type ItemPCIDevice struct { + // Compute ID + ComputeID uint64 `json:"computeId"` + + // Description + Description string `json:"description"` + + // GUID + GUID uint64 `json:"guid"` + + // HwPath + HwPath string `json:"hwPath"` + + // ID + ID uint64 `json:"id"` + + // Name + Name string `json:"name"` + + // Resource group ID + RGID uint64 `json:"rgId"` + + // Stack ID + StackID uint64 `json:"stackId"` + + // Status + Status string `json:"status"` + + // System name + SystemName string `json:"systemName"` +} + // List PCI devices type ListPCIDevices struct { // Data - Data []interface{} `json:"data"` - + Data []ItemPCIDevice `json:"data"` // Entry count EntryCount uint64 `json:"entryCount"` } diff --git a/pkg/cloudapi/compute/pfw_add.go b/pkg/cloudapi/compute/pfw_add.go index f896db1..7a89ccd 100644 --- a/pkg/cloudapi/compute/pfw_add.go +++ b/pkg/cloudapi/compute/pfw_add.go @@ -24,8 +24,8 @@ type PFWAddRequest struct { PublicPortEnd int64 `url:"publicPortEnd,omitempty" json:"publicPortEnd,omitempty"` // Internal base port number - // Required: true - LocalBasePort uint64 `url:"localBasePort" json:"localBasePort" validate:"required"` + // Required: false + LocalBasePort uint64 `url:"localBasePort,omitempty" json:"localBasePort,omitempty"` // Network protocol // either "tcp" or "udp" diff --git a/pkg/cloudapi/compute/resize.go b/pkg/cloudapi/compute/resize.go index f2c3b1e..81cddda 100644 --- a/pkg/cloudapi/compute/resize.go +++ b/pkg/cloudapi/compute/resize.go @@ -29,6 +29,16 @@ type ResizeRequest struct { Force bool `url:"force,omitempty" json:"force,omitempty"` } +// GetRAM returns RAM field values +func (r ResizeRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + // Resize resizes compute instance func (c Compute) Resize(ctx context.Context, req ResizeRequest) (bool, error) { err := validators.ValidateRequest(req) diff --git a/pkg/cloudapi/disks/from_platform_disk.go b/pkg/cloudapi/disks/from_platform_disk.go new file mode 100644 index 0000000..c7a54d6 --- /dev/null +++ b/pkg/cloudapi/disks/from_platform_disk.go @@ -0,0 +1,127 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + "strings" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// FromPlatformDiskRequest struct to create template from platform disk +type FromPlatformDiskRequest struct { + // ID of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` + + // Name of the rescue disk + // Required: true + Name string `url:"name" json:"name" validate:"required"` + + // Boot type of image BIOS or UEFI + // Required: true + BootType string `url:"boottype" json:"boottype" validate:"imageBootType"` + + // Image type linux, windows or other + // Required: true + ImageType string `url:"imagetype" json:"imagetype" validate:"imageType"` + + // Binary architecture of this image + // Should be: + // - X86_64 + // - PPC64_LE + // Required: true + Architecture string `url:"architecture" json:"architecture" validate:"imageArchitecture"` + + // Username for the image + // Required: false + Username string `url:"username,omitempty" json:"username,omitempty"` + + // Password for the image + // Required: false + Password string `url:"password,omitempty" json:"password,omitempty"` + + // Account ID to make the image exclusive + // Required: false + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + + // SEP ID + // Required: false + SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"` + + // Pool for image create + // Required: false + PoolName string `url:"poolName,omitempty" json:"poolName,omitempty"` + + // List of types of compute suitable for image + // Example: [ "KVM_X86" ] + // Required: false + Drivers []string `url:"drivers" json:"drivers" validate:"min=1,max=2,imageDrivers"` + + // Does this machine supports hot resize + // Required: false + HotResize bool `url:"hotresize" json:"hotresize"` + + // Bootable image + // Required: true + Bootable bool `url:"bootable" json:"bootable"` +} + +type wrapperFromPlatformDiskRequest struct { + FromPlatformDiskRequest + AsyncMode bool `url:"asyncMode"` +} + +// FromPlatformDisk creates template from platform disk in sync mode. +// It returns id of created disk and error. +func (d Disks) FromPlatformDisk(ctx context.Context, req FromPlatformDiskRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/disks/fromPlatformDisk" + + reqWrapped := wrapperFromPlatformDiskRequest{ + FromPlatformDiskRequest: req, + AsyncMode: false, + } + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) + if err != nil { + return 0, err + } + + result, err := strconv.ParseUint(string(res), 10, 64) + if err != nil { + return 0, err + } + + return result, nil +} + +// FromPlatformDiskAsync creates template from platform disk in async mode. +// It returns guid of task and error. +func (d Disks) FromPlatformDiskAsync(ctx context.Context, req FromPlatformDiskRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/disks/fromPlatformDisk" + + reqWrapped := wrapperFromPlatformDiskRequest{ + FromPlatformDiskRequest: req, + AsyncMode: true, + } + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) + if err != nil { + return "", err + } + + result := strings.ReplaceAll(string(res), "\"", "") + + return result, nil +} diff --git a/pkg/cloudapi/disks/list.go b/pkg/cloudapi/disks/list.go index 7c28588..20f981f 100644 --- a/pkg/cloudapi/disks/list.go +++ b/pkg/cloudapi/disks/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of disks @@ -48,6 +50,10 @@ type ListRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -59,6 +65,7 @@ type ListRequest struct { // List gets list of the created disks belonging to an account as a ListDisks struct func (d Disks) List(ctx context.Context, req ListRequest) (*ListDisks, error) { + res, err := d.ListRaw(ctx, req) if err != nil { return nil, err @@ -76,6 +83,11 @@ func (d Disks) List(ctx context.Context, req ListRequest) (*ListDisks, error) { // ListRaw gets list of the created disks belonging to an account as an array of bytes func (d Disks) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/disks/list" res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/disks/list_deleted.go b/pkg/cloudapi/disks/list_deleted.go index bef9ff8..9252bd3 100644 --- a/pkg/cloudapi/disks/list_deleted.go +++ b/pkg/cloudapi/disks/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted disks @@ -36,6 +38,10 @@ type ListDeletedRequest struct { // Required: false Type string `url:"type,omitempty" json:"type,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,11 @@ type ListDeletedRequest struct { // ListDeleted gets list the deleted disks belonging to an account func (d Disks) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListDisks, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/disks/listDeleted" res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/disks/list_types.go b/pkg/cloudapi/disks/list_types.go index 132c555..81f5ded 100644 --- a/pkg/cloudapi/disks/list_types.go +++ b/pkg/cloudapi/disks/list_types.go @@ -4,13 +4,19 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListTypesRequest struct to get list types of disks type ListTypesRequest struct { // Show detailed disk types by seps // Required: true - Detailed bool `url:"detailed" json:"detailed" validate:"required"` + Detailed bool `url:"detailed" json:"detailed"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` // Page number // Required: false @@ -23,6 +29,11 @@ type ListTypesRequest struct { // ListTypes gets list defined disk types func (d Disks) ListTypes(ctx context.Context, req ListTypesRequest) (*ListTypes, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/disks/listTypes" res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/disks/list_unattached.go b/pkg/cloudapi/disks/list_unattached.go index 3c05a0f..e038861 100644 --- a/pkg/cloudapi/disks/list_unattached.go +++ b/pkg/cloudapi/disks/list_unattached.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListUnattachedRequest struct to get list of unattached disk @@ -40,6 +42,10 @@ type ListUnattachedRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -51,6 +57,11 @@ type ListUnattachedRequest struct { // ListUnattached gets list of unattached disks func (d Disks) ListUnattached(ctx context.Context, req ListUnattachedRequest) (*ListDisksUnattached, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/disks/listUnattached" res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/disks/models.go b/pkg/cloudapi/disks/models.go index 301f857..2aa7f9c 100644 --- a/pkg/cloudapi/disks/models.go +++ b/pkg/cloudapi/disks/models.go @@ -74,6 +74,9 @@ type ItemDisk struct { // Purge time PurgeTime uint64 `json:"purgeTime"` + // Replication + Replication interface{} `json:"replication"` + // Resource ID ResID string `json:"resId"` @@ -403,6 +406,9 @@ type RecordDisk struct { // Purge time PurgeTime uint64 `json:"purgeTime"` + // Replication + Replication interface{} `json:"replication"` + // Resource ID ResID string `json:"resId"` diff --git a/pkg/cloudapi/disks/replicate.go b/pkg/cloudapi/disks/replicate.go new file mode 100644 index 0000000..3e2496e --- /dev/null +++ b/pkg/cloudapi/disks/replicate.go @@ -0,0 +1,52 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicateRequest struct to create an empty disk in chosen SEP and pool combination. +type ReplicateRequest struct { + // Id of the disk to replicate. This disk will become master in replication + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` + + // Name of replica disk to create + // Required: true + Name string `url:"name" json:"name" validate:"required"` + + // ID of SEP to create slave disk + // Required: true + SepID uint64 `url:"sepId" json:"sepId" validate:"required"` + + // Pool name to create slave disk in + // Required: true + PoolName string `url:"poolName" json:"poolName" validate:"required"` +} + +// 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) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/disks/replicate" + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, 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/disks/replication_resume.go b/pkg/cloudapi/disks/replication_resume.go new file mode 100644 index 0000000..e0c205c --- /dev/null +++ b/pkg/cloudapi/disks/replication_resume.go @@ -0,0 +1,38 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationResume struct to resume suspended replication +type ReplicationResumeRequest struct { + // Id of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// ReplicationResume resume suspended replication +func (d Disks) ReplicationResume(ctx context.Context, req ReplicationResumeRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/disks/replicationResume" + + 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/replication_reverse.go b/pkg/cloudapi/disks/replication_reverse.go new file mode 100644 index 0000000..56cc96f --- /dev/null +++ b/pkg/cloudapi/disks/replication_reverse.go @@ -0,0 +1,38 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationReverseRequest struct to change role between disks replications +type ReplicationReverseRequest struct { + // Id of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// ReplicationReverse change role between disks replications +func (d Disks) ReplicationReverse(ctx context.Context, req ReplicationReverseRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/disks/replicationReverse" + + 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/replication_start.go b/pkg/cloudapi/disks/replication_start.go new file mode 100644 index 0000000..6cda86c --- /dev/null +++ b/pkg/cloudapi/disks/replication_start.go @@ -0,0 +1,43 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationStartRequest struct to starts replication between two chosen disks +type ReplicationStartRequest struct { + // Id of the disk to replicate. Primary disk in replication + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` + + // ID of target disk. Secondary disk in replication + // Required: true + TargetDiskID uint64 `url:"targetDiskId" json:"targetDiskId" validate:"required"` +} + +// ReplicationStart starts replication between two chosen disks. It's required for both disks to have same size to avoid replication conflicts +// Note: Source disk's SEP and target SEP supported only of TATLIN type. +func (d Disks) ReplicationStart(ctx context.Context, req ReplicationStartRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/disks/replicationStart" + + 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/replication_status.go b/pkg/cloudapi/disks/replication_status.go new file mode 100644 index 0000000..f5ee27f --- /dev/null +++ b/pkg/cloudapi/disks/replication_status.go @@ -0,0 +1,37 @@ +package disks + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationStatusRequest struct to get replication status +type ReplicationStatusRequest struct { + // Id of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// ReplicationStatus get replication status +func (d Disks) ReplicationStatus(ctx context.Context, req ReplicationStatusRequest) (interface{}, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/disks/replicationStatus" + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + // result, err := strconv.ParseBool(string(res)) + // if err != nil { + // return nil, err + // } + + return res, nil +} diff --git a/pkg/cloudapi/disks/replication_stop.go b/pkg/cloudapi/disks/replication_stop.go new file mode 100644 index 0000000..cd4b4fd --- /dev/null +++ b/pkg/cloudapi/disks/replication_stop.go @@ -0,0 +1,38 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationStopRequest struct to remove replication between disks completely +type ReplicationStopRequest struct { + // Id of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// ReplicationStop remove replication between disks completely +func (d Disks) ReplicationStop(ctx context.Context, req ReplicationStopRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/disks/replicationStop" + + 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/replication_suspend.go b/pkg/cloudapi/disks/replication_suspend.go new file mode 100644 index 0000000..607f226 --- /dev/null +++ b/pkg/cloudapi/disks/replication_suspend.go @@ -0,0 +1,38 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationSuspendRequest struct to pause replication with possibility to resume from pause moment +type ReplicationSuspendRequest struct { + // Id of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// ReplicationSuspend pause replication with possibility to resume from pause moment +func (d Disks) ReplicationSuspend(ctx context.Context, req ReplicationSuspendRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/disks/replicationSuspend" + + 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/search.go b/pkg/cloudapi/disks/search.go index b6ca831..498bb1b 100644 --- a/pkg/cloudapi/disks/search.go +++ b/pkg/cloudapi/disks/search.go @@ -18,6 +18,14 @@ type SearchRequest struct { // If false, then disks having one of the statuses are not listed // Required: false ShowAll bool `url:"show_all,omitempty" json:"show_all,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"` } // Search searches disks diff --git a/pkg/cloudapi/extnet/list.go b/pkg/cloudapi/extnet/list.go index a0fb060..32ea7f9 100644 --- a/pkg/cloudapi/extnet/list.go +++ b/pkg/cloudapi/extnet/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of external network @@ -36,6 +38,10 @@ type ListRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,7 @@ type ListRequest struct { // List gets list of all available external networks as a ListExtNets struct func (e ExtNet) List(ctx context.Context, req ListRequest) (*ListExtNets, error) { + res, err := e.ListRaw(ctx, req) if err != nil { return nil, err @@ -64,6 +71,11 @@ func (e ExtNet) List(ctx context.Context, req ListRequest) (*ListExtNets, error) // ListRaw gets list of all available external networks as an array of bytes func (e ExtNet) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/extnet/list" res, err := e.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/extnet/list_computes.go b/pkg/cloudapi/extnet/list_computes.go index 627b730..080dfa1 100644 --- a/pkg/cloudapi/extnet/list_computes.go +++ b/pkg/cloudapi/extnet/list_computes.go @@ -22,6 +22,10 @@ type ListComputesRequest struct { // Required: false ComputeID uint64 `url:"computeId,omitempty" json:"computeId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -33,6 +37,7 @@ type ListComputesRequest struct { // ListComputes gets computes from account with extnets func (e ExtNet) ListComputes(ctx context.Context, req ListComputesRequest) (*ListExtNetComputes, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/flipgroup/list.go b/pkg/cloudapi/flipgroup/list.go index 7c755d4..b21bb5a 100644 --- a/pkg/cloudapi/flipgroup/list.go +++ b/pkg/cloudapi/flipgroup/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of FLIPGroup available to the current user @@ -28,6 +30,10 @@ type ListRequest struct { // Required: false ByIP string `url:"byIp,omitempty" json:"byIp,omitempty"` + // Find by accountId + // Required: false + AccountId uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + // Find by resource group ID // Required: false RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"` @@ -43,10 +49,23 @@ type ListRequest struct { // Page size // Required: false Size uint64 `url:"size,omitempty" json:"size,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + + // Find by connId + // Required: false + ConnId uint64 `url:"connId,omitempty" json:"connId,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` } // List gets list of FLIPGroup managed cluster instances available to the current user as a ListFLIPGroups struct func (f FLIPGroup) List(ctx context.Context, req ListRequest) (*ListFLIPGroups, error) { + res, err := f.ListRaw(ctx, req) if err != nil { return nil, err @@ -64,6 +83,11 @@ func (f FLIPGroup) List(ctx context.Context, req ListRequest) (*ListFLIPGroups, // ListRaw gets list of FLIPGroup managed cluster instances available to the current user as an array of bytes func (f FLIPGroup) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/flipgroup/list" res, err := f.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/image/create.go b/pkg/cloudapi/image/create.go index a0253c1..e45984a 100644 --- a/pkg/cloudapi/image/create.go +++ b/pkg/cloudapi/image/create.go @@ -18,10 +18,6 @@ type CreateRequest struct { // Required: true URL string `url:"url" json:"url" validate:"required,url"` - // Grid (platform) ID where this template should be create in - // Required: true - GID uint64 `url:"gid" json:"gid" validate:"required"` - // Boot type of image bios or UEFI // Required: true BootType string `url:"boottype" json:"boottype" validate:"required,imageBootType"` @@ -34,6 +30,17 @@ type CreateRequest struct { // Required: true ImageType string `url:"imagetype" json:"imagetype" validate:"required,imageType"` + // Account ID to make the image exclusive + // Required: true + AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` + + // Select a network interface naming pattern for your Linux machine. eth - onboard, ens - pci slot naming + // Should be: + // - eth + // - ens (default value) + // Required: false + NetworkInterfaceNaming string `url:"networkInterfaceNaming,omitempty" json:"networkInterfaceNaming,omitempty" validate:"omitempty,networkInterfaceNaming"` + // Does this machine supports hot resize // Required: false HotResize bool `url:"hotresize,omitempty" json:"hotresize,omitempty"` @@ -46,10 +53,6 @@ type CreateRequest struct { // Required: false Password string `url:"password,omitempty" json:"password,omitempty"` - // Account ID to make the image exclusive - // Required: false - AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` - // Username for upload binary media // Required: false UsernameDL string `url:"usernameDL,omitempty" json:"usernameDL,omitempty"` diff --git a/pkg/cloudapi/image/list.go b/pkg/cloudapi/image/list.go index b89acee..cf8c2f9 100644 --- a/pkg/cloudapi/image/list.go +++ b/pkg/cloudapi/image/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of available images @@ -56,6 +58,10 @@ type ListRequest struct { // Required: false Bootable bool `url:"bootable,omitempty" json:"bootable,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -67,6 +73,7 @@ type ListRequest struct { // List gets list of available images as a ListImages struct, optionally filtering by account ID func (i Image) List(ctx context.Context, req ListRequest) (*ListImages, error) { + res, err := i.ListRaw(ctx, req) if err != nil { return nil, err @@ -84,6 +91,11 @@ func (i Image) List(ctx context.Context, req ListRequest) (*ListImages, error) { // ListRaw gets list of available images as an array of bytes func (i Image) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/image/list" res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/image/models.go b/pkg/cloudapi/image/models.go index 0260529..b04df24 100644 --- a/pkg/cloudapi/image/models.go +++ b/pkg/cloudapi/image/models.go @@ -35,6 +35,9 @@ type ItemImage struct { // Name Name string `json:"name"` + // NetworkInterfaceNaming + NetworkInterfaceNaming string `json:"networkInterfaceNaming"` + // Pool Pool string `json:"pool"` @@ -104,6 +107,9 @@ type RecordImage struct { // Bootable Bootable bool `json:"bootable"` + // CdPresentedTo + CdPresentedTo interface{} `json:"cdPresentedTo"` + // ComputeCI ID ComputeCIID uint64 `json:"computeciId"` @@ -146,6 +152,9 @@ type RecordImage struct { // Name Name string `json:"name"` + // NetworkInterfaceNaming + NetworkInterfaceNaming string `json:"networkInterfaceNaming"` + // Password Password string `json:"password"` diff --git a/pkg/cloudapi/k8ci/list.go b/pkg/cloudapi/k8ci/list.go index 09013d8..dc16d57 100644 --- a/pkg/cloudapi/k8ci/list.go +++ b/pkg/cloudapi/k8ci/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of information about images @@ -36,6 +38,10 @@ type ListRequest struct { // Required: false IncludeDisabled bool `url:"includeDisabled,omitempty" json:"includeDisabled,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,7 @@ type ListRequest struct { // List gets list of all k8ci catalog items available to the current user as a ListK8CI struct func (k K8CI) List(ctx context.Context, req ListRequest) (*ListK8CI, error) { + res, err := k.ListRaw(ctx, req) if err != nil { return nil, err @@ -64,6 +71,11 @@ func (k K8CI) List(ctx context.Context, req ListRequest) (*ListK8CI, error) { // ListRaw gets list of all k8ci catalog items available to the current user as an array of bytes func (k K8CI) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/k8ci/list" res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/k8ci/list_deleted.go b/pkg/cloudapi/k8ci/list_deleted.go index 9e0142f..3fdb485 100644 --- a/pkg/cloudapi/k8ci/list_deleted.go +++ b/pkg/cloudapi/k8ci/list_deleted.go @@ -4,9 +4,11 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) -// ListDeletedRequest struct to get list information about deleted images +// ListDeletedRequest struct to get list information about deleted k8ci items type ListDeletedRequest struct { // Find by ID // Required: false @@ -28,6 +30,10 @@ type ListDeletedRequest struct { // Required: false NetworkPlugins string `url:"netPlugins,omitempty" json:"netPlugins,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -39,6 +45,11 @@ type ListDeletedRequest struct { // ListDeleted gets list all deleted k8ci catalog items available to the current user func (k K8CI) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListK8CI, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/k8ci/listDeleted" res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/k8s/create.go b/pkg/cloudapi/k8s/create.go index 932cfdd..78d047f 100644 --- a/pkg/cloudapi/k8s/create.go +++ b/pkg/cloudapi/k8s/create.go @@ -8,8 +8,6 @@ import ( "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) -// type Params []string - // CreateRequest struct to create kubernetes cluster type CreateRequest struct { // Name of Kubernetes cluster @@ -74,7 +72,7 @@ type CreateRequest struct { // Master node RAM volume in MB // Required: false - MasterRAM uint `url:"masterRam,omitempty" json:"masterRam,omitempty"` + MasterRAM uint64 `url:"masterRam,omitempty" json:"masterRam,omitempty"` // Master node boot disk size in GB If 0 is specified, size is defined by the OS image size // Required: false @@ -90,7 +88,7 @@ type CreateRequest struct { // Worker node RAM volume in MB // Required: false - WorkerRAM uint `url:"workerRam,omitempty" json:"workerRam,omitempty"` + WorkerRAM uint64 `url:"workerRam,omitempty" json:"workerRam,omitempty"` // Worker node boot disk size in GB. If 0 is specified, size is defined by the OS image size // Required: false @@ -111,7 +109,7 @@ type CreateRequest struct { // Custom sysctl values for Load Balancer instance. Applied on boot // Required: false - LbSysctlParams string `url:"lbSysctlParams,omitempty" json:"lbSysctlParams,omitempty"` + LbSysctlParams []map[string]interface{} `url:"lbSysctlParams,omitempty" json:"lbSysctlParams,omitempty"` // Use Highly Available schema for LB deploy // Required: false @@ -166,10 +164,16 @@ type CreateRequest struct { OidcCertificate string `url:"oidcCertificate,omitempty" json:"oidcCertificate,omitempty"` } -// type wrapperCreateRequest struct { -// CreateRequest -// Params []string `url:"lbSysctlParams,omitempty"` -// } +// GetRAM returns RAM field values +func (r CreateRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 2) + + res["MasterRAM"] = r.MasterRAM + res["WorkerRAM"] = r.WorkerRAM + + return res +} // Create creates a new Kubernetes cluster in the specified Resource Group func (k8s K8S) Create(ctx context.Context, req CreateRequest) (string, error) { @@ -178,28 +182,6 @@ func (k8s K8S) Create(ctx context.Context, req CreateRequest) (string, error) { return "", validators.ValidationErrors(validators.GetErrors(err)) } - // var params []string - - // if len(req.LbSysctlParams) != 0 { - // params = make([]string, 0, len(req.LbSysctlParams)) - - // for r := range req.LbSysctlParams { - // b, err := json.Marshal(req.LbSysctlParams[r]) - // if err != nil { - // return "", err - // } - - // params = append(params, string(b)) - // } - // } else { - // params = []string{"[]"} - // } - - // reqWrapped := wrapperCreateRequest{ - // CreateRequest: req, - // Params: params, - // } - url := "/cloudapi/k8s/create" res, err := k8s.client.DecortApiCallMP(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/k8s/list.go b/pkg/cloudapi/k8s/list.go index da307e8..9afe205 100644 --- a/pkg/cloudapi/k8s/list.go +++ b/pkg/cloudapi/k8s/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list information K8S @@ -44,6 +46,10 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -55,6 +61,7 @@ type ListRequest struct { // List gets list of all kubernetes clusters the user has access to as a ListK8SClusters func (k8s K8S) List(ctx context.Context, req ListRequest) (*ListK8SClusters, error) { + res, err := k8s.ListRaw(ctx, req) if err != nil { return nil, err @@ -72,6 +79,11 @@ func (k8s K8S) List(ctx context.Context, req ListRequest) (*ListK8SClusters, err // ListRaw gets list of all kubernetes clusters the user has access to as an array of bytes func (k8s K8S) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/k8s/list" res, err := k8s.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/k8s/list_deleted.go b/pkg/cloudapi/k8s/list_deleted.go index 98317e1..fefda61 100644 --- a/pkg/cloudapi/k8s/list_deleted.go +++ b/pkg/cloudapi/k8s/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted kubernetes cluster @@ -36,6 +38,10 @@ type ListDeletedRequest struct { // Required: false TechStatus string `url:"techStatus,omitempty" json:"techStatus,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,11 @@ type ListDeletedRequest struct { // ListDeleted gets all deleted kubernetes clusters the user has access to func (k8s K8S) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListK8SClusters, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/k8s/listDeleted" res, err := k8s.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/k8s/workers_group_add.go b/pkg/cloudapi/k8s/workers_group_add.go index 426f37a..9b32d2a 100644 --- a/pkg/cloudapi/k8s/workers_group_add.go +++ b/pkg/cloudapi/k8s/workers_group_add.go @@ -62,6 +62,16 @@ type WorkersGroupAddRequest struct { UserData string `url:"userData,omitempty" json:"userData,omitempty"` } +// GetRAM returns RAM field values +func (r WorkersGroupAddRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["WorkerRAM"] = r.WorkerRAM + + return res +} + // WorkersGroupAdd adds workers group to Kubernetes cluster func (k8s K8S) WorkersGroupAdd(ctx context.Context, req WorkersGroupAddRequest) (uint64, error) { err := validators.ValidateRequest(req) diff --git a/pkg/cloudapi/kvmppc/create.go b/pkg/cloudapi/kvmppc/create.go index 3fa59e8..9f602fb 100644 --- a/pkg/cloudapi/kvmppc/create.go +++ b/pkg/cloudapi/kvmppc/create.go @@ -26,6 +26,35 @@ type Interface struct { IPAddr string `url:"ipAddr,omitempty" json:"ipAddr,omitempty"` } +// DataDisk detailed struct for DataDisks field in CreateRequest and CreateBlankRequest +type DataDisk struct { + // Name for disk + // Required: true + DiskName string `url:"diskName" json:"diskName" validate:"required"` + + // Disk size in GB + // Required: true + Size uint64 `url:"size" json:"size" validate:"required"` + + // Storage endpoint provider ID + // By default the same with boot disk + // Required: false + SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"` + + // Pool name + // By default will be chosen automatically + // Required: false + Pool string `url:"pool,omitempty" json:"pool,omitempty"` + + // Optional description + // Required: false + Description string `url:"desc,omitempty" json:"desc,omitempty"` + + // Specify image id for create disk from template + // Required: false + ImageID uint64 `url:"imageId,omitempty" json:"imageId,omitempty"` +} + // CreateRequest struct to create KVM PowerPC VM type CreateRequest struct { // ID of the resource group, which will own this VM @@ -63,6 +92,12 @@ type CreateRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` + // Slice of structs with data disk description. Each disk has parameters: required - diskName, size; optional - sepId, pool, desc and imageId. + // If not specified, compute will be created without disks. + // To create compute without disks, pass initialized empty slice . + // Required: false + DataDisks []DataDisk `url:"-" json:"dataDisks,omitempty" validate:"omitempty,dive"` + // Slice of structs with net interface description. // If not specified, compute will be created with default interface from RG. // To create compute without interfaces, pass initialized empty slice . @@ -90,9 +125,20 @@ type CreateRequest struct { IPAType string `url:"ipaType,omitempty" json:"ipaType,omitempty"` } +// GetRAM returns RAM field values +func (r CreateRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + type wrapperCreateRequest struct { CreateRequest Interfaces []string `url:"interfaces,omitempty"` + DataDisks []string `url:"dataDisks,omitempty"` } // Create creates KVM PowerPC VM based on specified OS image @@ -119,9 +165,25 @@ func (k KVMPPC) Create(ctx context.Context, req CreateRequest) (uint64, error) { interfaces = []string{"[]"} } + var dataDisks []string + + if req.DataDisks != nil && len(req.DataDisks) != 0 { + dataDisks = make([]string, 0, len(req.DataDisks)) + + for i := range req.DataDisks { + b, err := json.Marshal(req.DataDisks[i]) + if err != nil { + return 0, err + } + + dataDisks = append(dataDisks, string(b)) + } + } + reqWrapped := wrapperCreateRequest{ CreateRequest: req, Interfaces: interfaces, + DataDisks: dataDisks, } url := "/cloudapi/kvmppc/create" diff --git a/pkg/cloudapi/kvmppc/create_blank.go b/pkg/cloudapi/kvmppc/create_blank.go index c0b1873..1911ca4 100644 --- a/pkg/cloudapi/kvmppc/create_blank.go +++ b/pkg/cloudapi/kvmppc/create_blank.go @@ -41,6 +41,12 @@ type CreateBlankRequest struct { // Required: true Pool string `url:"pool" json:"pool" validate:"required"` + // Slice of structs with data disk description. Each disk has parameters: required - diskName, size; optional - sepId, pool, desc and imageId. + // If not specified, compute will be created without disks. + // To create compute without disks, pass initialized empty slice . + // Required: false + DataDisks []DataDisk `url:"-" json:"dataDisks,omitempty" validate:"omitempty,dive"` + // Slice of structs with net interface description. // If not specified, compute will be created with default interface from RG. // To create compute without interfaces, pass initialized empty slice . @@ -52,9 +58,20 @@ type CreateBlankRequest struct { Description string `url:"desc,omitempty" json:"desc,omitempty"` } +// GetRAM returns RAM field values +func (r CreateBlankRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + type wrapperCreateBlankRequest struct { CreateBlankRequest Interfaces []string `url:"interfaces,omitempty"` + DataDisks []string `url:"dataDisks,omitempty"` } // CreateBlank creates KVM PowerPC VM from scratch @@ -81,9 +98,25 @@ func (k KVMPPC) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64 interfaces = []string{"[]"} } + var dataDisks []string + + if req.DataDisks != nil && len(req.DataDisks) != 0 { + dataDisks = make([]string, 0, len(req.DataDisks)) + + for i := range req.DataDisks { + b, err := json.Marshal(req.DataDisks[i]) + if err != nil { + return 0, err + } + + dataDisks = append(dataDisks, string(b)) + } + } + reqWrapped := wrapperCreateBlankRequest{ CreateBlankRequest: req, Interfaces: interfaces, + DataDisks: dataDisks, } url := "/cloudapi/kvmppc/createBlank" diff --git a/pkg/cloudapi/kvmx86/create.go b/pkg/cloudapi/kvmx86/create.go index 8d44ea3..245ea0c 100644 --- a/pkg/cloudapi/kvmx86/create.go +++ b/pkg/cloudapi/kvmx86/create.go @@ -26,6 +26,35 @@ type Interface struct { IPAddr string `url:"ipAddr,omitempty" json:"ipAddr,omitempty"` } +// DataDisk detailed struct for DataDisks field in CreateRequest and CreateBlankRequest +type DataDisk struct { + // Name for disk + // Required: true + DiskName string `url:"diskName" json:"diskName" validate:"required"` + + // Disk size in GB + // Required: true + Size uint64 `url:"size" json:"size" validate:"required"` + + // Storage endpoint provider ID + // By default the same with boot disk + // Required: false + SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"` + + // Pool name + // By default will be chosen automatically + // Required: false + Pool string `url:"pool,omitempty" json:"pool,omitempty"` + + // Optional description + // Required: false + Description string `url:"desc,omitempty" json:"desc,omitempty"` + + // Specify image id for create disk from template + // Required: false + ImageID uint64 `url:"imageId,omitempty" json:"imageId,omitempty"` +} + // CreateRequest struct to create KVM x86 VM type CreateRequest struct { // ID of the resource group, which will own this VM @@ -63,6 +92,12 @@ type CreateRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` + // Slice of structs with data disk description. Each disk has parameters: required - diskName, size; optional - sepId, pool, desc and imageId. + // If not specified, compute will be created without disks. + // To create compute without disks, pass initialized empty slice . + // Required: false + DataDisks []DataDisk `url:"-" json:"dataDisks,omitempty" validate:"omitempty,dive"` + // Slice of structs with net interface description. // If not specified, compute will be created with default interface from RG. // To create compute without interfaces, pass initialized empty slice . @@ -98,9 +133,20 @@ type CreateRequest struct { Driver string `url:"driver,omitempty" json:"driver,omitempty" validate:"omitempty,computeDriver"` } +// GetRAM returns RAM field values +func (r CreateRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + type wrapperCreateRequest struct { CreateRequest Interfaces []string `url:"interfaces,omitempty"` + DataDisks []string `url:"dataDisks,omitempty"` } // Create creates KVM x86 VM based on specified OS image @@ -127,9 +173,25 @@ func (k KVMX86) Create(ctx context.Context, req CreateRequest) (uint64, error) { interfaces = []string{"[]"} } + var dataDisks []string + + if req.DataDisks != nil && len(req.DataDisks) != 0 { + dataDisks = make([]string, 0, len(req.DataDisks)) + + for i := range req.DataDisks { + b, err := json.Marshal(req.DataDisks[i]) + if err != nil { + return 0, err + } + + dataDisks = append(dataDisks, string(b)) + } + } + reqWrapped := wrapperCreateRequest{ CreateRequest: req, Interfaces: interfaces, + DataDisks: dataDisks, } url := "/cloudapi/kvmx86/create" diff --git a/pkg/cloudapi/kvmx86/create_blank.go b/pkg/cloudapi/kvmx86/create_blank.go index 9c57ece..8b423fc 100644 --- a/pkg/cloudapi/kvmx86/create_blank.go +++ b/pkg/cloudapi/kvmx86/create_blank.go @@ -41,6 +41,12 @@ type CreateBlankRequest struct { // Required: true Pool string `url:"pool" json:"pool" validate:"required"` + // Slice of structs with data disk description. Each disk has parameters: required - diskName, size; optional - sepId, pool, desc and imageId. + // If not specified, compute will be created without disks. + // To create compute without disks, pass initialized empty slice . + // Required: false + DataDisks []DataDisk `url:"-" json:"dataDisks,omitempty" validate:"omitempty,dive"` + // Slice of structs with net interface description. // If not specified, compute will be created with default interface from RG. // To create compute without interfaces, pass initialized empty slice . @@ -56,9 +62,20 @@ type CreateBlankRequest struct { Description string `url:"desc,omitempty" json:"desc,omitempty"` } +// GetRAM returns RAM field values +func (r CreateBlankRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + type wrapperCreateBlankRequest struct { CreateBlankRequest Interfaces []string `url:"interfaces,omitempty"` + DataDisks []string `url:"dataDisks,omitempty"` } // CreateBlank creates KVM x86 VM from scratch @@ -85,9 +102,25 @@ func (k KVMX86) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64 interfaces = []string{"[]"} } + var dataDisks []string + + if req.DataDisks != nil && len(req.DataDisks) != 0 { + dataDisks = make([]string, 0, len(req.DataDisks)) + + for i := range req.DataDisks { + b, err := json.Marshal(req.DataDisks[i]) + if err != nil { + return 0, err + } + + dataDisks = append(dataDisks, string(b)) + } + } + reqWrapped := wrapperCreateBlankRequest{ CreateBlankRequest: req, Interfaces: interfaces, + DataDisks: dataDisks, } url := "/cloudapi/kvmx86/createBlank" diff --git a/pkg/cloudapi/lb/create.go b/pkg/cloudapi/lb/create.go index ecab87c..bd34ac5 100644 --- a/pkg/cloudapi/lb/create.go +++ b/pkg/cloudapi/lb/create.go @@ -10,8 +10,6 @@ import ( "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) -type Params []string - // CreateRequest struct to create load balancer type CreateRequest struct { // ID of the resource group where this load balancer instance will be located @@ -33,7 +31,7 @@ type CreateRequest struct { // Custom sysctl values for Load Balancer instance. Applied on boot // Required: false - SysctlParams Params `url:"-" json:"sysctlParams,omitempty" validate:"omitempty,dive"` + SysctlParams []map[string]interface{} `url:"-" json:"sysctlParams,omitempty" validate:"omitempty,dive"` // Use Highly Available schema for LB deploy // Required: false @@ -68,14 +66,12 @@ func (l LB) Create(ctx context.Context, req CreateRequest) (uint64, error) { if len(req.SysctlParams) != 0 { params = make([]string, 0, len(req.SysctlParams)) - - for r := range req.SysctlParams { - b, err := json.Marshal(req.SysctlParams[r]) + for _, m := range req.SysctlParams { + encodeStr, err := json.Marshal(m) if err != nil { return 0, err } - - params = append(params, string(b)) + params = append(params, string(encodeStr)) } } else { params = []string{} diff --git a/pkg/cloudapi/lb/list.go b/pkg/cloudapi/lb/list.go index 9c3daea..e9c8432 100644 --- a/pkg/cloudapi/lb/list.go +++ b/pkg/cloudapi/lb/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of load balancers @@ -44,6 +46,10 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -55,6 +61,7 @@ type ListRequest struct { // List gets list of all load balancers as a ListLB struct func (l LB) List(ctx context.Context, req ListRequest) (*ListLB, error) { + res, err := l.ListRaw(ctx, req) if err != nil { return nil, err @@ -72,6 +79,11 @@ func (l LB) List(ctx context.Context, req ListRequest) (*ListLB, error) { // ListRaw gets list of all load balancers as an array of bytes func (l LB) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/lb/list" res, err := l.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/lb/list_deleted.go b/pkg/cloudapi/lb/list_deleted.go index 5a6040e..403436e 100644 --- a/pkg/cloudapi/lb/list_deleted.go +++ b/pkg/cloudapi/lb/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted load balancers @@ -18,7 +20,7 @@ type ListDeletedRequest struct { // Find by account ID // Required: false - AccountID uint64 `url:"accountID,omitempty" json:"accountID,omitempty"` + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` // Find by resource group ID // Required: false @@ -36,6 +38,10 @@ type ListDeletedRequest struct { // Required: false BackIP string `url:"backIp,omitempty" json:"backIp,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,11 @@ type ListDeletedRequest struct { // ListDeleted gets list of deleted load balancers func (l LB) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListLB, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/lb/listDeleted" res, err := l.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/lb/models.go b/pkg/cloudapi/lb/models.go index e04d45f..1b6fd9e 100644 --- a/pkg/cloudapi/lb/models.go +++ b/pkg/cloudapi/lb/models.go @@ -50,6 +50,12 @@ type RecordLB struct { // ID ID uint64 `json:"id"` + // ManagerId + ManagerId uint64 `json:"managerId"` + + // ManagerType + ManagerType string `json:"managerType"` + // Image ID ImageID uint64 `json:"imageId"` @@ -89,6 +95,9 @@ type RecordLB struct { // Updated time UpdatedTime uint64 `json:"updatedTime"` + // UserManaged + UserManaged bool `json:"userManaged"` + // VINS ID VINSID uint64 `json:"vinsId"` } diff --git a/pkg/cloudapi/lb/stop.go b/pkg/cloudapi/lb/stop.go index 8010030..5eeb9ba 100644 --- a/pkg/cloudapi/lb/stop.go +++ b/pkg/cloudapi/lb/stop.go @@ -22,7 +22,7 @@ func (l LB) Stop(ctx context.Context, req StopRequest) (bool, error) { return false, validators.ValidationErrors(validators.GetErrors(err)) } - url := "/cloudapi/lb/start" + url := "/cloudapi/lb/stop" res, err := l.client.DecortApiCall(ctx, http.MethodPost, url, req) if err != nil { diff --git a/pkg/cloudapi/lb/updateSysctParams.go b/pkg/cloudapi/lb/update_sysctl_params.go similarity index 78% rename from pkg/cloudapi/lb/updateSysctParams.go rename to pkg/cloudapi/lb/update_sysctl_params.go index 37c29e9..2b92c4a 100644 --- a/pkg/cloudapi/lb/updateSysctParams.go +++ b/pkg/cloudapi/lb/update_sysctl_params.go @@ -17,7 +17,7 @@ type UpdateSysctParamsRequest struct { // Custom sysctl values for Load Balancer instance. Applied on boot // Required: true - SysctlParams Params `url:"-" json:"sysctlParams" validate:"required,dive"` + SysctlParams []map[string]interface{} `url:"-" json:"sysctlParams" validate:"required,dive"` } type wrapperUpdateSysctParamsRequest struct { @@ -26,7 +26,7 @@ type wrapperUpdateSysctParamsRequest struct { } // UpdateSysctParams updates sysct paarams for lb -func (l LB) UpdateSysctParams(ctx context.Context, req UpdateSysctParamsRequest) (bool, error) { +func (l LB) UpdateSysctlParams(ctx context.Context, req UpdateSysctParamsRequest) (bool, error) { err := validators.ValidateRequest(req) if err != nil { return false, validators.ValidationErrors(validators.GetErrors(err)) @@ -36,14 +36,12 @@ func (l LB) UpdateSysctParams(ctx context.Context, req UpdateSysctParamsRequest) if len(req.SysctlParams) != 0 { params = make([]string, 0, len(req.SysctlParams)) - - for r := range req.SysctlParams { - b, err := json.Marshal(req.SysctlParams[r]) + for _, m := range req.SysctlParams { + encodeStr, err := json.Marshal(m) if err != nil { return false, err } - - params = append(params, string(b)) + params = append(params, string(encodeStr)) } } else { params = []string{} @@ -54,7 +52,7 @@ func (l LB) UpdateSysctParams(ctx context.Context, req UpdateSysctParamsRequest) Params: params, } - url := "/cloudapi/lb/updateSysctParams" + url := "/cloudapi/lb/updateSysctlParams" res, err := l.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) if err != nil { diff --git a/pkg/cloudapi/locations/list.go b/pkg/cloudapi/locations/list.go index de9b560..13fc8df 100644 --- a/pkg/cloudapi/locations/list.go +++ b/pkg/cloudapi/locations/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of locations @@ -31,10 +33,15 @@ type ListRequest struct { // Find by code location // Required: false LocationCode string `url:"locationCode,omitempty" json:"locationCode,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` } // List gets list of all locations as a ListLocations struct func (l Locations) List(ctx context.Context, req ListRequest) (*ListLocations, error) { + res, err := l.ListRaw(ctx, req) if err != nil { return nil, err @@ -52,6 +59,11 @@ func (l Locations) List(ctx context.Context, req ListRequest) (*ListLocations, e // ListRaw gets list of all locations as an array of bytes func (l Locations) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/locations/list" res, err := l.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/pcidevice.go b/pkg/cloudapi/pcidevice.go new file mode 100644 index 0000000..9a15625 --- /dev/null +++ b/pkg/cloudapi/pcidevice.go @@ -0,0 +1,8 @@ +package cloudapi + +import "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/pcidevice" + +// Accessing the PCI Device method group +func (ca *CloudAPI) PCIDevice() *pcidevice.PCIDevice { + return pcidevice.New(ca.client) +} diff --git a/pkg/cloudapi/pcidevice/ids.go b/pkg/cloudapi/pcidevice/ids.go new file mode 100644 index 0000000..f558dbb --- /dev/null +++ b/pkg/cloudapi/pcidevice/ids.go @@ -0,0 +1,10 @@ +package pcidevice + +// IDs gets array of PCIDeviceIDs from ListPCIDevices struct +func (lpd ListPCIDevices) IDs() []uint64 { + res := make([]uint64, 0, len(lpd.Data)) + for _, lb := range lpd.Data { + res = append(res, lb.ID) + } + return res +} diff --git a/pkg/cloudapi/pcidevice/list.go b/pkg/cloudapi/pcidevice/list.go new file mode 100644 index 0000000..1975eb1 --- /dev/null +++ b/pkg/cloudapi/pcidevice/list.go @@ -0,0 +1,76 @@ +package pcidevice + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ListRequest struct to get list of pci devices +type ListRequest struct { + // Find by id + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Find by computeId + // Required: false + ComputeID uint64 `url:"computeId,omitempty" json:"computeId,omitempty"` + + // Find by name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Find by rgId + // Required: false + RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + + // 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 all pci devices as a ListPCIDevices struct +func (p PCIDevice) List(ctx context.Context, req ListRequest) (*ListPCIDevices, error) { + + res, err := p.ListRaw(ctx, req) + if err != nil { + return nil, err + } + + list := ListPCIDevices{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} + +// ListRaw gets list of all pci devices as an array of bytes +func (p PCIDevice) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/pcidevice/list" + + res, err := p.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudapi/pcidevice/models.go b/pkg/cloudapi/pcidevice/models.go new file mode 100644 index 0000000..0a125b0 --- /dev/null +++ b/pkg/cloudapi/pcidevice/models.go @@ -0,0 +1,50 @@ +package pcidevice + +// Main information about PCI device +type ItemPCIDevice struct { + // CKey + CKey string `json:"_ckey"` + + // Meta + Meta []interface{} `json:"_meta"` + + // Compute ID + ComputeID uint64 `json:"computeId"` + + // Description + Description string `json:"description"` + + // GUID + GUID uint64 `json:"guid"` + + // HwPath + HwPath string `json:"hwPath"` + + // ID + ID uint64 `json:"id"` + + // Name + Name string `json:"name"` + + // Resource group ID + RGID uint64 `json:"rgId"` + + // Stack ID + StackID uint64 `json:"stackId"` + + // Status + Status string `json:"status"` + + // System name + SystemName string `json:"systemName"` +} + +// List PCI devices +type ListPCIDevices struct { + // Data + Data []ItemPCIDevice `json:"data"` + + // Entry count + EntryCount uint64 `json:"entryCount"` +} + diff --git a/pkg/cloudapi/pcidevice/pcidevice.go b/pkg/cloudapi/pcidevice/pcidevice.go new file mode 100644 index 0000000..27054c0 --- /dev/null +++ b/pkg/cloudapi/pcidevice/pcidevice.go @@ -0,0 +1,15 @@ +package pcidevice + +import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" + +// Structure for creating request to PCI device +type PCIDevice struct { + client interfaces.Caller +} + +// Builder for PCI device endpoints +func New(client interfaces.Caller) *PCIDevice { + return &PCIDevice{ + client: client, + } +} diff --git a/pkg/cloudapi/pcidevice/serialize.go b/pkg/cloudapi/pcidevice/serialize.go new file mode 100644 index 0000000..bc0908a --- /dev/null +++ b/pkg/cloudapi/pcidevice/serialize.go @@ -0,0 +1,42 @@ +package pcidevice + +import ( + "encoding/json" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/serialization" +) + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (l ListPCIDevices) Serialize(params ...string) (serialization.Serialized, error) { + if len(l.Data) == 0 { + return []byte{}, nil + } + + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(l, prefix, indent) + } + + return json.Marshal(l) +} + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (i ItemPCIDevice) Serialize(params ...string) (serialization.Serialized, error) { + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(i, prefix, indent) + } + + return json.Marshal(i) +} diff --git a/pkg/cloudapi/rg/ids.go b/pkg/cloudapi/rg/ids.go index 83da393..457535c 100644 --- a/pkg/cloudapi/rg/ids.go +++ b/pkg/cloudapi/rg/ids.go @@ -55,12 +55,10 @@ func (lrc ListResourceConsumption) IDs() []uint64 { } // IDs gets array of ResourceGroupIDs from ListAffinityGroup struct -func (lag ListAffinityGroups) IDs() []uint64 { - res := make([]uint64, 0, len(lag.Data)) - for _, ag := range lag.Data { - for _, v := range ag { - res = append(res, v...) - } +func (lag ListAffinityGroup) IDs() []uint64 { + res := make([]uint64, 0, len(lag)) + for _, ag := range lag { + res = append(res, ag.ID) } return res } diff --git a/pkg/cloudapi/rg/list.go b/pkg/cloudapi/rg/list.go index db128d0..af688fe 100644 --- a/pkg/cloudapi/rg/list.go +++ b/pkg/cloudapi/rg/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of resource groups @@ -44,6 +46,10 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -55,6 +61,7 @@ type ListRequest struct { // List gets list of all resource groups the user has access to as a ListResourceGroups struct func (r RG) List(ctx context.Context, req ListRequest) (*ListResourceGroups, error) { + res, err := r.ListRaw(ctx, req) if err != nil { return nil, err @@ -72,6 +79,11 @@ func (r RG) List(ctx context.Context, req ListRequest) (*ListResourceGroups, err // ListRaw gets list of all resource groups the user has access to as an array of bytes func (r RG) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/rg/list" res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/rg/list_computes.go b/pkg/cloudapi/rg/list_computes.go index 78ef722..737c06e 100644 --- a/pkg/cloudapi/rg/list_computes.go +++ b/pkg/cloudapi/rg/list_computes.go @@ -46,6 +46,10 @@ type ListComputesRequest struct { // Required: false ExtNetID uint64 `url:"extNetId,omitempty" json:"extNetId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -57,6 +61,7 @@ type ListComputesRequest struct { // ListComputes gets list of all compute instances under specified resource group, accessible by the user func (r RG) ListComputes(ctx context.Context, req ListComputesRequest) (*ListComputes, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/rg/list_deleted.go b/pkg/cloudapi/rg/list_deleted.go index e7e1ac2..b7b41d9 100644 --- a/pkg/cloudapi/rg/list_deleted.go +++ b/pkg/cloudapi/rg/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list deleted resource groups @@ -36,6 +38,10 @@ type ListDeletedRequest struct { // Required: false LockStatus string `url:"lockStatus,omitempty" json:"lockStatus,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,11 @@ type ListDeletedRequest struct { // ListDeleted gets list all deleted resource groups the user has access to func (r RG) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListResourceGroups, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/rg/listDeleted" res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/rg/list_lb.go b/pkg/cloudapi/rg/list_lb.go index ae7a6ff..ee59a45 100644 --- a/pkg/cloudapi/rg/list_lb.go +++ b/pkg/cloudapi/rg/list_lb.go @@ -24,7 +24,7 @@ type ListLBRequest struct { // Find by account ID // Required: false - AccountID uint64 `url:"accountID,omitempty" json:"accountID,omitempty"` + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` // Find by tech status // Required: false @@ -42,6 +42,10 @@ type ListLBRequest struct { // Required: false BackIP string `url:"backIp,omitempty" json:"backIp,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -53,6 +57,7 @@ type ListLBRequest struct { // ListLB gets list all load balancers in the specified resource group, accessible by the user func (r RG) ListLB(ctx context.Context, req ListLBRequest) (*ListLB, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/rg/list_pfw.go b/pkg/cloudapi/rg/list_pfw.go index b109748..a6a7d92 100644 --- a/pkg/cloudapi/rg/list_pfw.go +++ b/pkg/cloudapi/rg/list_pfw.go @@ -17,6 +17,7 @@ type ListPFWRequest struct { // ListPFW gets list port forward rules for the specified resource group func (r RG) ListPFW(ctx context.Context, req ListPFWRequest) (*ListPortForwards, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/rg/list_vins.go b/pkg/cloudapi/rg/list_vins.go index 0cb4aa5..736d965 100644 --- a/pkg/cloudapi/rg/list_vins.go +++ b/pkg/cloudapi/rg/list_vins.go @@ -30,6 +30,10 @@ type ListVINSRequest struct { // Required: false VINSID uint64 `url:"vinsId,omitempty" json:"vinsId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListVINSRequest struct { // ListVINS gets list all ViNSes under specified resource group, accessible by the user func (r RG) ListVINS(ctx context.Context, req ListVINSRequest) (*ListVINS, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/rg/models.go b/pkg/cloudapi/rg/models.go index 22dc36b..ecba0fc 100644 --- a/pkg/cloudapi/rg/models.go +++ b/pkg/cloudapi/rg/models.go @@ -77,6 +77,9 @@ type RecordResourceGroup struct { // Access Control List ACL ListACL `json:"acl"` + // Compute Features + ComputeFeatures []string `json:"computeFeatures"` + // CPU allocation parameter CPUAllocationParameter string `json:"cpu_allocation_parameter"` @@ -170,6 +173,9 @@ type ItemResourceGroup struct { // Access Control List ACL ListACL `json:"acl"` + // Compute Features + ComputeFeatures []string `json:"computeFeatures"` + // CPU allocation parameter CPUAllocationParameter string `json:"cpu_allocation_parameter"` @@ -331,10 +337,19 @@ type ItemAffinityGroupComputes struct { // List of affinity groups type ListAffinityGroupsComputes []ItemAffinityGroupComputes +// Main information about +type ItemAffinityGroup struct { + ID uint64 `json:"id"` + NodeID uint64 `json:"node_id"` +} + +// List of affinity group +type ListAffinityGroup []ItemAffinityGroup + // List of affinity groups type ListAffinityGroups struct { // Data - Data []map[string][]uint64 `json:"data"` + Data []map[string]ListAffinityGroup `json:"data"` // Entry count EntryCount uint64 `json:"entryCount"` @@ -768,6 +783,12 @@ type ItemVINS struct { // External IP ExternalIP string `json:"externalIP"` + // Extnet ID + ExtnetId uint64 `json:"extnetId"` + + // Free IPs + FreeIPs uint64 `json:"freeIPs"` + // ID ID uint64 `json:"id"` diff --git a/pkg/cloudapi/sizes/list.go b/pkg/cloudapi/sizes/list.go index a41b0ef..41209d2 100644 --- a/pkg/cloudapi/sizes/list.go +++ b/pkg/cloudapi/sizes/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct for list of the available flavors @@ -16,6 +18,10 @@ type ListRequest struct { // Required: false Location string `url:"location,omitempty" json:"location,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -27,6 +33,7 @@ type ListRequest struct { // List gets list of the available flavors as a ListSizes struct, filtering can be based on the user which is doing the request func (s Sizes) List(ctx context.Context, req ListRequest) (*ListSizes, error) { + res, err := s.ListRaw(ctx, req) if err != nil { return nil, err @@ -44,6 +51,11 @@ func (s Sizes) List(ctx context.Context, req ListRequest) (*ListSizes, error) { // ListRaw gets list of the available flavors as an array of bytes func (s Sizes) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/sizes/list" res, err := s.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/stack/list.go b/pkg/cloudapi/stack/list.go index 97645fe..987e58f 100644 --- a/pkg/cloudapi/stack/list.go +++ b/pkg/cloudapi/stack/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of stacks @@ -24,6 +26,10 @@ type ListRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -35,6 +41,7 @@ type ListRequest struct { // List gets list of stacks as a ListStacks struct func (i Stack) List(ctx context.Context, req ListRequest) (*ListStacks, error) { + res, err := i.ListRaw(ctx, req) if err != nil { return nil, err @@ -52,6 +59,11 @@ func (i Stack) List(ctx context.Context, req ListRequest) (*ListStacks, error) { // ListRaw gets list of stacks as an array of bytes func (i Stack) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/stack/list" res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/tasks/list.go b/pkg/cloudapi/tasks/list.go index dd792b0..15ace57 100644 --- a/pkg/cloudapi/tasks/list.go +++ b/pkg/cloudapi/tasks/list.go @@ -4,21 +4,51 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of tasks type ListRequest struct { + // Find by guId + // Required: false + TaskID string `url:"taskId,omitempty" json:"taskId,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Find by completed True or False + // Default: false + // Required: false + Completed bool `url:"completed" json:"completed"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + + // Find all tasks after point in time (unixtime) + // Required: false + UpdateTimeAt uint64 `url:"page,updateTimeAt" json:"updateTimeAt,omitempty"` + + // Find all tasks before point in time (unixtime) + // Required: false + UpdateTimeTo uint64 `url:"page,updateTimeTo" json:"updateTimeTo,omitempty"` + // Page number + // Default: 0 // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` // Page size + // Default: 0 // Required: false Size uint64 `url:"size,omitempty" json:"size,omitempty"` } // List gets list of user API tasks with status PROCESSING as a ListTasks struct func (t Tasks) List(ctx context.Context, req ListRequest) (*ListTasks, error) { + res, err := t.ListRaw(ctx, req) if err != nil { return nil, err @@ -36,6 +66,11 @@ func (t Tasks) List(ctx context.Context, req ListRequest) (*ListTasks, error) { // ListRaw gets list of user API tasks with status PROCESSING as an array of bytes func (t Tasks) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/tasks/list" res, err := t.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/tasks/models.go b/pkg/cloudapi/tasks/models.go index 94bc472..c9133ab 100644 --- a/pkg/cloudapi/tasks/models.go +++ b/pkg/cloudapi/tasks/models.go @@ -1,46 +1,13 @@ package tasks import ( - "encoding/json" + "errors" "fmt" - "strconv" ) -// Global variable for converting field to desired data type -type TaskResult int - -// Method for convert field -func (r *TaskResult) UnmarshalJSON(b []byte) error { - if b[0] == '"' { - b := b[1 : len(b)-1] - if len(b) == 0 { - *r = 0 - return nil - } - n, err := strconv.Atoi(string(b)) - if err != nil { - return err - } - *r = TaskResult(n) - } else if b[0] == '[' { - res := []interface{}{} - if err := json.Unmarshal(b, &res); err != nil { - return err - } - if n, ok := res[0].(float64); ok { - *r = TaskResult(n) - } else { - return fmt.Errorf("could not unmarshal %v into int", res[0]) - } - } else { - n, err := strconv.Atoi(string(b)) - if err != nil { - return err - } - *r = TaskResult(n) - } - - return nil +// Result structure of the task to provide methods +type Result struct { + Result interface{} `json:"result"` } // Detailed information about task @@ -57,8 +24,8 @@ type RecordAsyncTask struct { // List of logs Log []string `json:"log"` - // Final result - Result TaskResult `json:"result"` + // Final Result + Result // Stage Stage string `json:"stage"` @@ -78,37 +45,102 @@ type RecordAsyncTask struct { // Detailed information about task type ItemAsyncTask struct { - // Audit ID - AuditID string `json:"auditId"` + RecordAsyncTask - // Completed - Completed bool `json:"completed"` + // GUID + GUID string `json:"guid"` +} - // Error - Error string `json:"error"` +// List of tasks +type ListTasks struct { + Data []ItemAsyncTask `json:"data"` - // List of logs - Log []string `json:"log"` + EntryCount uint64 `json:"entryCount"` +} - // Final result - Result TaskResult `json:"result"` +// ID returns ID of cluster or WG or any other resource successfully created as a Result of the task. +// It returns error if Result does not contain any resource ID. +func (r Result) ID() (int, error) { + // check id from cluster - it comes as slice, like [1234, "cluster-name"] + slice, ok := r.Result.([]interface{}) + if ok { + if len(slice) == 0 { + return 0, fmt.Errorf("could not get ID from empty slice") + } - // Stage - Stage string `json:"stage"` + idFloat64, ok := slice[0].(float64) + if !ok { + return 0, fmt.Errorf("could not get ID from first slice element (%v)", slice[0]) + } - // Status - Status string `json:"status"` + return int(idFloat64), nil + } - // Update time - UpdateTime uint64 `json:"updateTime"` + // check id from other resources - it comes as id + idFloat64, ok := r.Result.(float64) + if ok { + return int(idFloat64), nil + } - // Updated time - UpdatedTime uint64 `json:"updatedTime"` + return 0, errors.New("could not get ID because result is neither slice nor number (%v)") } -// List of tasks -type ListTasks struct { - Data []ItemAsyncTask `json:"data"` +// Name returns name of cluster or WG successfully created as a Result of the task. +// It returns error if Result does not contain k8s name. +func (r Result) Name() (string, error) { + slice, ok := r.Result.([]interface{}) + if !ok { + return "", fmt.Errorf("could not convert Result (%v) to slice", r.Result) + } - EntryCount uint64 `json:"entryCount"` + if len(slice) < 2 { + return "", fmt.Errorf("could not get name from second slice element") + } + + var name string + name, ok = slice[1].(string) + if !ok { + return "", fmt.Errorf("could not get name from second slice element (%v)", slice[1]) + } + + return name, nil +} + +// ToMaps converts Result to a slice of maps containing back-up information as a result of the task. +// It returns error if Result does not contain back-up information. +func (r Result) ToMaps() ([]map[string]interface{}, error) { + slice, ok := r.Result.([]interface{}) + if !ok { + return nil, fmt.Errorf("could not convert Result (%v) to slice", r.Result) + } + + if len(slice) == 0 { + return nil, fmt.Errorf("could not get maps from empty slice") + } + + result := make([]map[string]interface{}, 0, len(slice)) + for _, s := range slice { + elem, ok := s.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("could not get map[string]interface{} from slice element (%v)", s) + } + result = append(result, elem) + } + + return result, nil +} + +// ToString converts Result to non-empty string. +// It returns error if Result is not a string or is an empty string. +func (r Result) ToString() (string, error) { + status, ok := r.Result.(string) + if !ok { + return "", fmt.Errorf("could not convert Result (%v) to string", r.Result) + } + + if status == "" { + return "", fmt.Errorf("info contains empty string") + } + + return status, nil } diff --git a/pkg/cloudapi/user.go b/pkg/cloudapi/user.go new file mode 100644 index 0000000..26ea4f5 --- /dev/null +++ b/pkg/cloudapi/user.go @@ -0,0 +1,7 @@ +package cloudapi + +import "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/user" + +func (ca *CloudAPI) User() *user.User { + return user.New(ca.client) +} diff --git a/pkg/cloudapi/user/api_list.go b/pkg/cloudapi/user/api_list.go new file mode 100644 index 0000000..74344a8 --- /dev/null +++ b/pkg/cloudapi/user/api_list.go @@ -0,0 +1,41 @@ +package user + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// APIListRequest struct for getting API list. +type APIListRequest struct { + // ID of the user. + // Required: true + UserID string `url:"userId" json:"userId" validate:"required"` +} + +// APIList gets a list of all API functions that a given user has +// access to according to their apiaccess group membership. +func (u User) APIList(ctx context.Context, req APIListRequest) (*APIsEndpoints, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/user/apiList" + + info := APIsEndpoints{} + + res, err := u.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudapi/user/authenticate.go b/pkg/cloudapi/user/authenticate.go new file mode 100644 index 0000000..e626eae --- /dev/null +++ b/pkg/cloudapi/user/authenticate.go @@ -0,0 +1,38 @@ +package user + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// AuthenticateRequest struct to authenticate user. +type AuthenticateRequest struct { + // Username + // Required: true + Username string `url:"username" json:"username" validate:"required"` + + // Password + // Required: true + Password string `url:"password" json:"password" validate:"required"` +} + +// Authenticate evaluates the provided username and password and returns a session key. +// The session key can be used for doing api requests. E.g this is the authkey parameter in every actor request. +// A session key is only vallid for a limited time. +func (u User) Authenticate(ctx context.Context, req AuthenticateRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/user/authenticate" + + res, err := u.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudapi/user/brief.go b/pkg/cloudapi/user/brief.go new file mode 100644 index 0000000..dd3ac65 --- /dev/null +++ b/pkg/cloudapi/user/brief.go @@ -0,0 +1,26 @@ +package user + +import ( + "context" + "encoding/json" + "net/http" +) + +// Brief gets information about user's enabled and disabled resources. +func (u User) Brief(ctx context.Context) (*BriefResources, error) { + url := "/cloudapi/user/brief" + + info := BriefResources{} + + res, err := u.client.DecortApiCall(ctx, http.MethodPost, url, nil) + if err != nil { + return nil, err + } + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudapi/user/get.go b/pkg/cloudapi/user/get.go new file mode 100644 index 0000000..ec995fa --- /dev/null +++ b/pkg/cloudapi/user/get.go @@ -0,0 +1,46 @@ +package user + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// GetRequest struct to get user details. +type GetRequest struct { + // Username + // Required: true + Username string `url:"username" json:"username" validate:"required"` +} + +// Get gets user details as an ItemUser struct. +func (u User) Get(ctx context.Context, req GetRequest) (*ItemUser, error) { + res, err := u.GetRaw(ctx, req) + if err != nil { + return nil, err + } + + item := ItemUser{} + + err = json.Unmarshal(res, &item) + if err != nil { + return nil, err + } + + return &item, nil +} + +// GetRaw gets user details as an array of bytes +func (u User) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/user/get" + + res, err := u.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudapi/user/get_audit.go b/pkg/cloudapi/user/get_audit.go new file mode 100644 index 0000000..72f3de1 --- /dev/null +++ b/pkg/cloudapi/user/get_audit.go @@ -0,0 +1,53 @@ +package user + +import ( + "context" + "encoding/json" + "net/http" +) + +// GetAuditRequest struct for getting user's audits. +type GetAuditRequest struct { + // Find by api call. + // Required: false + Call string `url:"call,omitempty" json:"call,omitempty"` + + // Find by HTTP status code + // Required: false + StatusCode uint64 `url:"statuscode,omitempty" json:"statuscode,omitempty"` + + // Find all audits after point in time (unixtime) + // Required: false + TimestampAt uint64 `url:"timestampAt,omitempty" json:"timestampAt,omitempty"` + + // Find all audits before point in time (unixtime) + // Required: false + TimestampTo uint64 `url:"timestampTo,omitempty" json:"timestampTo,omitempty"` + + // Page number. + // Required: false + Page uint64 `url:"page,omitempty" json:"page,omitempty"` + + // Page size, maximum - 100. + // Required: false + Size uint64 `url:"size,omitempty" json:"size,omitempty"` +} + +// GetAudit gets user's audits. +func (u User) GetAudit(ctx context.Context, req GetAuditRequest) (ListAudits, error) { + url := "/cloudapi/user/getAudit" + + res, err := u.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return ListAudits{}, err + } + + list := ListAudits{} + + err = json.Unmarshal(res, &list) + if err != nil { + return ListAudits{}, err + } + + return list, nil +} diff --git a/pkg/cloudapi/user/get_resource_consumption.go b/pkg/cloudapi/user/get_resource_consumption.go new file mode 100644 index 0000000..c4e79b0 --- /dev/null +++ b/pkg/cloudapi/user/get_resource_consumption.go @@ -0,0 +1,26 @@ +package user + +import ( + "context" + "encoding/json" + "net/http" +) + +// GetResourceConsumption gets amount of consumed and reserved resources (cpu, ram, disk) by current user +func (u User) GetResourceConsumption(ctx context.Context) (*ResourceConsumption, error) { + url := "/cloudapi/user/getResourceConsumption" + + res, err := u.client.DecortApiCall(ctx, http.MethodPost, url, nil) + if err != nil { + return nil, err + } + + item := ResourceConsumption{} + + err = json.Unmarshal(res, &item) + if err != nil { + return nil, err + } + + return &item, nil +} diff --git a/pkg/cloudapi/user/is_valid_invite_user_token.go b/pkg/cloudapi/user/is_valid_invite_user_token.go new file mode 100644 index 0000000..250d05a --- /dev/null +++ b/pkg/cloudapi/user/is_valid_invite_user_token.go @@ -0,0 +1,44 @@ +package user + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// GetRequest struct to check if the inviteusertoken and emailaddress pair are valid and matching. +type IsValidInviteUserTokenRequest struct { + // InviteUserToken + // The token that was previously sent to the invited user email + // Required: true + InviteUserToken string `url:"inviteusertoken" json:"inviteusertoken" validate:"required"` + + // EmailAddress + // Email address for the user + // Required: true + EmailAddress string `url:"emailaddress" json:"emailaddress" validate:"required"` +} + +// IsValidInviteUserToken checks if the inviteusertoken and emailaddress pair are valid and matching. +func (u User) IsValidInviteUserToken(ctx context.Context, req IsValidInviteUserTokenRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/user/isValidInviteUserToken" + + res, err := u.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/user/models.go b/pkg/cloudapi/user/models.go new file mode 100644 index 0000000..b4d01da --- /dev/null +++ b/pkg/cloudapi/user/models.go @@ -0,0 +1,178 @@ +package user + +import "strconv" + +type ItemUser struct { + // Data + Data interface{} `json:"data"` + + // EmailAddresses + EmailAddresses []string `json:"emailaddresses"` + + // Username + Username string `json:"username"` +} + +type ItemAudit struct { + // Call + Call string `json:"Call"` + + // Response time + ResponseTime ResponseTime `json:"Response Time"` + + // StatusCode + StatusCode StatusCode `json:"Status Code"` + + // Time + Time float64 `json:"Time"` +} + +type ListAudits struct { + // Data + Data []ItemAudit `json:"data"` + + // Entry count + EntryCount uint64 `json:"entryCount"` +} + +type ResponseTime float64 + +func (r *ResponseTime) UnmarshalJSON(b []byte) error { + if string(b) == "null" { + *r = ResponseTime(-1) + + return nil + } + + res, err := strconv.ParseFloat(string(b), 64) + if err != nil { + return err + } + + *r = ResponseTime(res) + + return nil +} + +type StatusCode int64 + +func (s *StatusCode) UnmarshalJSON(b []byte) error { + if string(b) == "null" { + *s = StatusCode(-1) + + return nil + } + + res, err := strconv.ParseInt(string(b), 10, 64) + if err != nil { + return err + } + + *s = StatusCode(res) + + return nil +} + +type BriefResources struct { + Accounts Accounts `json:"Accounts,omitempty"` + CSs CSs `json:"CSs,omitempty"` + Computes Computes `json:"Computes,omitempty"` + RGs RGs `json:"RGs,omitempty"` + VMs VMs `json:"VMs,omitempty"` +} + +type Accounts struct { + Disabled uint64 `json:"DISABLED,omitempty"` + Enabled uint64 `json:"ENABLED,omitempty"` +} + +type CSs struct { + Disabled uint64 `json:"DISABLED,omitempty"` + Enabled uint64 `json:"ENABLED,omitempty"` +} + +type Computes struct { + Started uint64 `json:"Started,omitempty"` + Stopped uint64 `json:"Stopped,omitempty"` +} + +type RGs struct { + Disabled uint64 `json:"DISABLED,omitempty"` + Enabled uint64 `json:"ENABLED,omitempty"` +} + +type VMs struct { + Halted uint64 `json:"Halted,omitempty"` + Running uint64 `json:"Running,omitempty"` +} + +type APIsEndpoints struct { + CloudAPI CloudAPIEndpoints `json:"cloudapi,omitempty"` + CloudBroker CloudBrokerEndpoints `json:"cloudbroker,omitempty"` + LibCloud LibCloudEndpoints `json:"libcloud,omitempty"` + System SystemEndpoints `json:"system,omitempty"` +} + +type CloudAPIEndpoints struct { + All bool `json:"ALL,omitempty"` +} + +type CloudBrokerEndpoints struct { + All bool `json:"ALL,omitempty"` +} + +type LibCloudEndpoints struct { + All bool `json:"ALL,omitempty"` +} + +type SystemEndpoints struct { + All bool `json:"ALL,omitempty"` +} + +type ResourceConsumption struct { + // Consumed + Consumed Resources `json:"Consumed"` + + // Reserved + Reserved Resources `json:"Reserved"` + + // Username + Username string `json:"username"` +} + +type Resources struct { + // CPU + CPU uint64 `json:"cpu"` + + // Disksize + DiskSize uint64 `json:"disksize"` + + // DiskSizeMax + DiskSizeMax uint64 `json:"disksizemax"` + + // ExtIPs + ExtIPs uint64 `json:"extips"` + + // ExtTraffic + ExtTraffic uint64 `json:"exttraffic"` + + // GPU + GPU uint64 `json:"gpu"` + + // RAM + RAM uint64 `json:"ram"` + + // SEPs + SEPs map[string]map[string]DiskUsage `json:"seps"` +} + +// Disk usage +type DiskUsage struct { + // Disk size + DiskSize float64 `json:"disksize"` + + // Disk size max + DiskSizeMax float64 `json:"disksizemax"` +} + +type FoundElements []interface{} diff --git a/pkg/cloudapi/user/search.go b/pkg/cloudapi/user/search.go new file mode 100644 index 0000000..18182f6 --- /dev/null +++ b/pkg/cloudapi/user/search.go @@ -0,0 +1,33 @@ +package user + +import ( + "context" + "encoding/json" + "net/http" +) + +// SearchRequest struct for searching user's elements. +type SearchRequest struct { + // Text to search + // Required: true + Text string `url:"text" json:"text" validate:"required"` +} + +// Search searches for user's elements. +func (u User) Search(ctx context.Context, req SearchRequest) (*FoundElements, error) { + url := "/cloudapi/user/search" + + res, err := u.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + list := FoundElements{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} diff --git a/pkg/cloudapi/user/set_data.go b/pkg/cloudapi/user/set_data.go new file mode 100644 index 0000000..f3d5c4a --- /dev/null +++ b/pkg/cloudapi/user/set_data.go @@ -0,0 +1,38 @@ +package user + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// SetDataRequest struct for setting extra user information. +type SetDataRequest struct { + // Data to set to user in json format + // Required: true + Data string `url:"data" json:"data" validation:"required"` +} + +// SetData sets extra user information. +func (u User) SetData(ctx context.Context, req SetDataRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/user/setData" + + res, err := u.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/user/user.go b/pkg/cloudapi/user/user.go new file mode 100644 index 0000000..119eb55 --- /dev/null +++ b/pkg/cloudapi/user/user.go @@ -0,0 +1,15 @@ +package user + +import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" + +// Structure for creating request to User +type User struct { + client interfaces.Caller +} + +// Builder for User endpoints +func New(client interfaces.Caller) *User { + return &User{ + client: client, + } +} diff --git a/pkg/cloudapi/vfpool.go b/pkg/cloudapi/vfpool.go new file mode 100644 index 0000000..dfee4db --- /dev/null +++ b/pkg/cloudapi/vfpool.go @@ -0,0 +1,8 @@ +package cloudapi + +import "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/vfpool" + +// Accessing the VFPool method group +func (ca *CloudAPI) VFPool() *vfpool.VFPool { + return vfpool.New(ca.client) +} diff --git a/pkg/cloudapi/vfpool/filter.go b/pkg/cloudapi/vfpool/filter.go new file mode 100644 index 0000000..78cbbf3 --- /dev/null +++ b/pkg/cloudapi/vfpool/filter.go @@ -0,0 +1,99 @@ +package vfpool + +// FilterByID returns ListVFPool with specified ID. +func (lvfp ListVFPool) FilterByID(id uint64) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + return ivfp.ID == id + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByGID returns ListVFPool with specified GID. +func (lvfp ListVFPool) FilterByGID(gid uint64) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + return ivfp.GID == gid + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByName returns ListVFPool with specified Name. +func (lvfp ListVFPool) FilterByName(name string) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + return ivfp.Name == name + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByDescription returns ListVFPool with specified Description. +func (lvfp ListVFPool) FilterByDescription(description string) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + return ivfp.Description == description + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByStatus returns ListVFPool with specified Status. +func (lvfp ListVFPool) FilterByStatus(status string) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + return ivfp.Status == status + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByAccountAccess returns ListVFPool with specified AccountAccess. +func (lvfp ListVFPool) FilterByAccountAccess(accountAccess uint64) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + for _, i := range ivfp.AccountAccess { + if i == accountAccess { + return true + } + } + return false + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByRGAccess returns ListVFPool with specified RGAccess. +func (lvfp ListVFPool) FilterByRGAccess(rgAccess uint64) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + for _, i := range ivfp.RGAccess { + if i == rgAccess { + return true + } + } + return false + } + + return lvfp.FilterFunc(predicate) +} + +// FilterFunc allows filtering ListVFPool based on a user-specified predicate. +func (lvfp ListVFPool) FilterFunc(predicate func(ItemVFPool) bool) ListVFPool { + var result ListVFPool + + for _, item := range lvfp.Data { + if predicate(item) { + result.Data = append(result.Data, item) + } + } + + result.EntryCount = uint64(len(result.Data)) + + return result +} + +// FindOne returns first found ItemVFPool +// If none was found, returns an empty struct. +func (lvfp ListVFPool) FindOne() ItemVFPool { + if lvfp.EntryCount == 0 { + return ItemVFPool{} + } + + return lvfp.Data[0] +} diff --git a/pkg/cloudapi/vfpool/filter_test.go b/pkg/cloudapi/vfpool/filter_test.go new file mode 100644 index 0000000..66d78a3 --- /dev/null +++ b/pkg/cloudapi/vfpool/filter_test.go @@ -0,0 +1,138 @@ +package vfpool + +import "testing" + +var vfpools = ListVFPool{ + Data: []ItemVFPool{ + { + AccountAccess: []uint64{1, 2}, + Description: "descr", + GID: 1, + ID: 1, + Name: "name", + RGAccess: []uint64{3, 4}, + Status: "ENABLED", + }, + { + AccountAccess: []uint64{}, + Description: "", + GID: 2, + ID: 2, + Name: "name2", + RGAccess: []uint64{}, + Status: "DISABLED", + }, + { + AccountAccess: []uint64{7, 8}, + Description: "", + GID: 215, + ID: 3, + Name: "name3", + RGAccess: []uint64{5, 6}, + Status: "DISABLED", + }, + }, +} + +func TestFilterByID(t *testing.T) { + actual := vfpools.FilterByID(1).FindOne() + + if actual.ID != 1 { + t.Fatal("expected ID 1, found: ", actual.ID) + } +} + +func TestFilterByGID(t *testing.T) { + var gid uint64 = 1 + actual := vfpools.FilterByGID(gid).FindOne() + + if actual.GID != gid { + t.Fatal("expected ", gid, " found: ", actual.GID) + } +} + +func TestFilterByName(t *testing.T) { + name := "name" + actual := vfpools.FilterByName(name).FindOne() + + if actual.Name != name { + t.Fatal("expected ", name, " found: ", actual.Name) + } +} + +func TestFilterByDescription(t *testing.T) { + description := "descr" + actual := vfpools.FilterByDescription(description).FindOne() + + if actual.Description != description { + t.Fatal("expected ", description, " found: ", actual.Description) + } +} + +func TestFilterByStatus(t *testing.T) { + actual := vfpools.FilterByStatus("ENABLED") + + if len(actual.Data) != 1 { + t.Fatal("expected 1 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if item.Status != "ENABLED" { + t.Fatal("expected Status 'ENABLED', found: ", item.Status) + } + } +} + +func TestFilterByAccountAccess(t *testing.T) { + var account uint64 = 1 + actual := vfpools.FilterByAccountAccess(account) + + if len(actual.Data) != 1 { + t.Fatal("expected 1 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + var found bool + for _, a := range item.AccountAccess { + if a == account { + found = true + } + } + + if !found { + t.Fatalf("expected account access %d, found: %v", account, item.AccountAccess) + } + } +} + +func TestFilterByRGAccess(t *testing.T) { + var rg uint64 = 3 + actual := vfpools.FilterByRGAccess(rg) + + if len(actual.Data) != 1 { + t.Fatal("expected 1 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + var found bool + for _, r := range item.RGAccess { + if r == rg { + found = true + } + } + + if !found { + t.Fatalf("expected account access %d, found: %v", rg, item.RGAccess) + } + } +} + +func TestFilterFunc(t *testing.T) { + actual := vfpools.FilterFunc(func(ivfpool ItemVFPool) bool { + return ivfpool.GID == ivfpool.ID + }) + + if len(actual.Data) != 2 { + t.Fatal("expected 2 elements, found: ", len(actual.Data)) + } +} diff --git a/pkg/cloudapi/vfpool/get.go b/pkg/cloudapi/vfpool/get.go new file mode 100644 index 0000000..0c42d1a --- /dev/null +++ b/pkg/cloudapi/vfpool/get.go @@ -0,0 +1,46 @@ +package vfpool + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// GetRequest struct to get detailed information about vfpool device +type GetRequest struct { + // ID of vfpool device + // Required: true + VFPoolID uint64 `url:"id" json:"id" validate:"required"` +} + +// Get gets detailed information about vfpool device as a RecordVFPool struct +func (v VFPool) Get(ctx context.Context, req GetRequest) (*RecordVFPool, error) { + res, err := v.GetRaw(ctx, req) + if err != nil { + return nil, err + } + + info := RecordVFPool{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +// GetRaw gets detailed information about vfpool device as an array of bytes +func (v VFPool) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/vfpool/get" + + res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudapi/vfpool/ids.go b/pkg/cloudapi/vfpool/ids.go new file mode 100644 index 0000000..1a58061 --- /dev/null +++ b/pkg/cloudapi/vfpool/ids.go @@ -0,0 +1,19 @@ +package vfpool + +// IDs gets array of VFPool IDs from ListVFPool struct +func (lv ListVFPool) IDs() []uint64 { + res := make([]uint64, 0, len(lv.Data)) + for _, e := range lv.Data { + res = append(res, e.ID) + } + return res +} + +// IDs gets array of VF IDs from VFSInfoList struct +func (lv VFSInfoList) IDs() []uint64 { + res := make([]uint64, 0, len(lv)) + for _, e := range lv { + res = append(res, e.ID) + } + return res +} diff --git a/pkg/cloudapi/vfpool/list.go b/pkg/cloudapi/vfpool/list.go new file mode 100644 index 0000000..1c1f299 --- /dev/null +++ b/pkg/cloudapi/vfpool/list.go @@ -0,0 +1,83 @@ +package vfpool + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ListRequest struct to get list of vfpool devices +type ListRequest struct { + // Find by ID + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Find by Grid ID + // Required: false + GID uint64 `url:"gid,omitempty" json:"gid,omitempty"` + + // Find by name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Find by description + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Find by account Access + // Required: false + AccountAccess uint64 `url:"accountAccess,omitempty" json:"accountAccess,omitempty"` + + // Find by resource group Access + // Required: false + RGAccess uint64 `url:"rgAccess,omitempty" json:"rgAccess,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + + // 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 all available vfpool devices as a ListVFPool struct +func (v VFPool) List(ctx context.Context, req ListRequest) (*ListVFPool, error) { + + res, err := v.ListRaw(ctx, req) + if err != nil { + return nil, err + } + + list := ListVFPool{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} + +// ListRaw gets list of all available vfpool devices as an array of bytes +func (v VFPool) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/vfpool/list" + + res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudapi/vfpool/models.go b/pkg/cloudapi/vfpool/models.go new file mode 100644 index 0000000..3ecd53b --- /dev/null +++ b/pkg/cloudapi/vfpool/models.go @@ -0,0 +1,116 @@ +package vfpool + +// Main information about vfpool device +type ItemVFPool struct { + // AccountAccess + AccountAccess []uint64 `json:"accountAccess"` + + // CreatedTime + CreatedTime uint64 `json:"createdTime"` + + // Description + Description string `json:"description"` + + // GID + GID uint64 `json:"gid"` + + // GUID + GUID uint64 `json:"guid"` + + // ID + ID uint64 `json:"id"` + + // Name + Name string `json:"name"` + + // RGAccess + RGAccess []uint64 `json:"rgAccess"` + + // Status + Status string `json:"status"` + + // UpdatedTime + UpdatedTime uint64 `json:"updatedTime"` + + // VFS + VFS []VFS `json:"vfs"` +} + +// List of information about vfpool devices +type ListVFPool struct { + Data []ItemVFPool `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} + +// Detailed information about vfpool device +type RecordVFPool struct { + // AccountAccess + AccountAccess []uint64 `json:"accountAccess"` + + // CreatedTime + CreatedTime uint64 `json:"createdTime"` + + // Description + Description string `json:"description"` + + // GID + GID uint64 `json:"gid"` + + // GUID + GUID uint64 `json:"guid"` + + // ID + ID uint64 `json:"id"` + + // Name + Name string `json:"name"` + + // RGAccess + RGAccess []uint64 `json:"rgAccess"` + + // Status + Status string `json:"status"` + + // UpdatedTime + UpdatedTime uint64 `json:"updatedTime"` + + // VFS + VFS []VFS `json:"vfs"` +} + +// VFS struct +type VFS struct { + // NodeID + NodeID uint64 `json:"nodeId"` + + // UpdatedTime + VFList VFList `json:"vfList"` +} + +// VFList struct +type VFList []VFItem + +// VFItem struct +type VFItem struct { + // NicName + NicName string `json:"nicName"` + + // VFSInfo list + VFSInfo VFSInfoList `json:"vfsInfo"` +} + +// VFSInfoList struct +type VFSInfoList []VFSInfoItem + +// VFSInfoItem struct +type VFSInfoItem struct { + // ID + ID uint64 `json:"id"` + + // Claimed + Claimed bool `json:"claimed"` + + // VM ID + VMID uint64 `json:"vmId"` +} diff --git a/pkg/cloudapi/vfpool/serialize.go b/pkg/cloudapi/vfpool/serialize.go new file mode 100644 index 0000000..143d8cb --- /dev/null +++ b/pkg/cloudapi/vfpool/serialize.go @@ -0,0 +1,59 @@ +package vfpool + +import ( + "encoding/json" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/serialization" +) + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (lvfpool ListVFPool) Serialize(params ...string) (serialization.Serialized, error) { + if lvfpool.EntryCount == 0 { + return []byte{}, nil + } + + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(lvfpool, prefix, indent) + } + + return json.Marshal(lvfpool) +} + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (rvfpool RecordVFPool) Serialize(params ...string) (serialization.Serialized, error) { + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(rvfpool, prefix, indent) + } + + return json.Marshal(rvfpool) +} + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (ivfpool ItemVFPool) Serialize(params ...string) (serialization.Serialized, error) { + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(ivfpool, prefix, indent) + } + + return json.Marshal(ivfpool) +} diff --git a/pkg/cloudapi/vfpool/vfpool.go b/pkg/cloudapi/vfpool/vfpool.go new file mode 100644 index 0000000..1541349 --- /dev/null +++ b/pkg/cloudapi/vfpool/vfpool.go @@ -0,0 +1,18 @@ +// API Actor for managing vfpool device +package vfpool + +import ( + "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" +) + +// Structure for creating request to vfpool +type VFPool struct { + client interfaces.Caller +} + +// Builder for vfpool endpoints +func New(client interfaces.Caller) *VFPool { + return &VFPool{ + client, + } +} diff --git a/pkg/cloudapi/vins/create_in_account.go b/pkg/cloudapi/vins/create_in_account.go index cb00d66..d6b0ab6 100644 --- a/pkg/cloudapi/vins/create_in_account.go +++ b/pkg/cloudapi/vins/create_in_account.go @@ -42,6 +42,10 @@ type CreateInAccountRequest struct { // Required: false Description string `url:"desc,omitempty" json:"desc,omitempty"` + // List of DNS ip address + // Required: false + DNSList []string `url:"dnsList" json:"dnsList,omitempty"` + // Number of pre created reservations // Required: false PreReservationsNum uint64 `url:"preReservationsNum,omitempty" json:"preReservationsNum,omitempty"` diff --git a/pkg/cloudapi/vins/create_in_rg.go b/pkg/cloudapi/vins/create_in_rg.go index 8d89fa5..db8bc78 100644 --- a/pkg/cloudapi/vins/create_in_rg.go +++ b/pkg/cloudapi/vins/create_in_rg.go @@ -36,6 +36,10 @@ type CreateInRGRequest struct { // Required: false Description string `url:"desc,omitempty" json:"desc,omitempty"` + // List of DNS ip address + // Required: false + DNSList []string `url:"dnsList" json:"dnsList,omitempty"` + // Number of pre created reservations // Required: false PreReservationsNum uint64 `url:"preReservationsNum,omitempty" json:"preReservationsNum,omitempty"` diff --git a/pkg/cloudapi/vins/dns_apply.go b/pkg/cloudapi/vins/dns_apply.go new file mode 100644 index 0000000..41ab07e --- /dev/null +++ b/pkg/cloudapi/vins/dns_apply.go @@ -0,0 +1,43 @@ +package vins + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DNSApplyRequest struct to apply new DNS list in VINS +type DNSApplyRequest struct { + // VINS ID + // Required: true + VINSID uint64 `url:"vinsId" json:"vinsId" validate:"required"` + + // List of DNS ip address + // Required: false + DNSList []string `url:"dnsList" json:"dnsList"` +} + +// DNSApply applies new DNS list in VINS +func (v VINS) DNSApply(ctx context.Context, req DNSApplyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudapi/vins/dnsApply" + + 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/cloudapi/vins/ip_release.go b/pkg/cloudapi/vins/ip_release.go index c00adbb..e975d18 100644 --- a/pkg/cloudapi/vins/ip_release.go +++ b/pkg/cloudapi/vins/ip_release.go @@ -26,6 +26,7 @@ type IPReleaseRequest struct { // IPRelese delete IP reservation matched by specified IP & MAC address combination. // If both IP and MAC address are empty strings, all IP reservations will be deleted. func (v VINS) IPRelese(ctx context.Context, req IPReleaseRequest) (bool, error) { + err := validators.ValidateRequest(req) if err != nil { return false, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/vins/ip_reserve.go b/pkg/cloudapi/vins/ip_reserve.go index b741d29..c40e1cd 100644 --- a/pkg/cloudapi/vins/ip_reserve.go +++ b/pkg/cloudapi/vins/ip_reserve.go @@ -40,6 +40,7 @@ type IPReserveRequest struct { // IPReserve creates reservation on ViNS DHCP func (v VINS) IPReserve(ctx context.Context, req IPReserveRequest) (string, error) { + err := validators.ValidateRequest(req) if err != nil { return "", validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudapi/vins/list.go b/pkg/cloudapi/vins/list.go index 81af517..cda0f11 100644 --- a/pkg/cloudapi/vins/list.go +++ b/pkg/cloudapi/vins/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of VINSes @@ -32,6 +34,10 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includeDeleted,omitempty" json:"includeDeleted,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -43,6 +49,7 @@ type ListRequest struct { // List gets list of VINSes available for current user as a ListVINS struct func (v VINS) List(ctx context.Context, req ListRequest) (*ListVINS, error) { + res, err := v.ListRaw(ctx, req) if err != nil { return nil, err @@ -60,6 +67,11 @@ func (v VINS) List(ctx context.Context, req ListRequest) (*ListVINS, error) { // ListRaw gets list of VINSes available for current user as an array of bytes func (v VINS) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/vins/list" res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/vins/list_deleted.go b/pkg/cloudapi/vins/list_deleted.go index 49f4426..0c7d552 100644 --- a/pkg/cloudapi/vins/list_deleted.go +++ b/pkg/cloudapi/vins/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted VINSes @@ -28,6 +30,10 @@ type ListDeletedRequest struct { // Required: false ExtIP string `url:"extIp,omitempty" json:"extIp,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -39,6 +45,11 @@ type ListDeletedRequest struct { // ListDeleted gets list of deleted VINSes available for current user func (v VINS) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListVINS, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudapi/vins/listDeleted" res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudapi/vins/models.go b/pkg/cloudapi/vins/models.go index 6bae94c..4c27771 100644 --- a/pkg/cloudapi/vins/models.go +++ b/pkg/cloudapi/vins/models.go @@ -23,6 +23,12 @@ type ItemVINS struct { // External IP ExternalIP string `json:"externalIP"` + // Extnet ID + ExtnetId uint64 `json:"extnetId"` + + // Free IPs + FreeIPs uint64 `json:"freeIPs"` + // ID ID uint64 `json:"id"` @@ -53,8 +59,10 @@ type ItemVINS struct { // List of VINSes type ListVINS struct { + // Data Data []ItemVINS `json:"data"` + // Entry count EntryCount uint64 `json:"entryCount"` } @@ -282,6 +290,9 @@ type ItemVNFInterface struct { // Network type NetType string `json:"netType"` + // NodeID + NodeID int64 `json:"nodeId"` + // PCI slot PCISlot int64 `json:"pciSlot"` diff --git a/pkg/cloudapi/vins/nat_rule_add.go b/pkg/cloudapi/vins/nat_rule_add.go index e5767ec..9982dee 100644 --- a/pkg/cloudapi/vins/nat_rule_add.go +++ b/pkg/cloudapi/vins/nat_rule_add.go @@ -18,14 +18,14 @@ type NATRuleAddRequest struct { // Required: true IntIP string `url:"intIp" json:"intIp" validate:"required"` - // Internal IP port number to use for this rule - // Required: true - IntPort uint `url:"intPort" json:"intPort" validate:"required"` - // External IP start port to use for this rule // Required: true ExtPortStart uint `url:"extPortStart" json:"extPortStart" validate:"required"` + // Internal IP port number to use for this rule + // Required: false + IntPort uint `url:"intPort,omitempty" json:"intPort,omitempty"` + // External IP end port to use for this rule // Required: false ExtPortEnd uint `url:"extPortEnd,omitempty" json:"extPortEnd,omitempty"` diff --git a/pkg/cloudbroker/account/create.go b/pkg/cloudbroker/account/create.go index bcb8ff0..97e1530 100644 --- a/pkg/cloudbroker/account/create.go +++ b/pkg/cloudbroker/account/create.go @@ -54,6 +54,11 @@ type CreateRequest struct { // i.e.: ["sep1_poolName1", "sep2_poolName2", etc] // Required: false UniqPools []string `url:"uniqPools,omitempty" json:"uniqPools,omitempty"` + + // Advanced compute features, + // one of: hugepages, numa, cpupin, vfnic + // Required: false + ComputeFeatures []string `url:"computeFeatures,omitempty" json:"computeFeatures,omitempty" validate:"omitempty,computeFeatures"` } // Create creates account diff --git a/pkg/cloudbroker/account/grant_access_templates.go b/pkg/cloudbroker/account/grant_access_templates.go new file mode 100644 index 0000000..17bdc7b --- /dev/null +++ b/pkg/cloudbroker/account/grant_access_templates.go @@ -0,0 +1,42 @@ +package account + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// GrantAccessTemplatesRequest struct to share images with account +type GrantAccessTemplatesRequest struct { + // ID an account + // Required: true + AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` + + // list of image IDs + // Required: true + ImageIDs []uint64 `url:"imageIds" json:"imageIds" validate:"required"` +} + +// GrantAccessTemplates shares specified images with specified account +func (a Account) GrantAccessTemplates(ctx context.Context, req GrantAccessTemplatesRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/account/grantAccessTemplates" + + 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 5cb0b79..13548f8 100644 --- a/pkg/cloudbroker/account/list.go +++ b/pkg/cloudbroker/account/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of accounts @@ -24,6 +26,10 @@ type ListRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -35,6 +41,7 @@ type ListRequest struct { // List gets list of all accounts the user has access to as a ListAccounts struct func (a Account) List(ctx context.Context, req ListRequest) (*ListAccounts, error) { + res, err := a.ListRaw(ctx, req) if err != nil { return nil, err @@ -52,6 +59,11 @@ func (a Account) List(ctx context.Context, req ListRequest) (*ListAccounts, erro // ListRaw gets list of all accounts the user has access to as an array of bytes func (a Account) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/account/list" res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/account/list_available_templates.go b/pkg/cloudbroker/account/list_available_templates.go new file mode 100644 index 0000000..a6671fb --- /dev/null +++ b/pkg/cloudbroker/account/list_available_templates.go @@ -0,0 +1,41 @@ +package account + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ListAvailableTemplatesRequest struct to list templates who sharedWith include accountId +type ListAvailableTemplatesRequest struct { + // ID an account + // Required: true + AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` +} + +// ListAvailableTemplates lists templates who sharedWith include accountId +func (a Account) ListAvailableTemplates(ctx context.Context, req ListAvailableTemplatesRequest) ([]uint64, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/account/listAvailableTemplates" + + res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + list := make([]uint64, 0) + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return list, nil +} diff --git a/pkg/cloudbroker/account/list_computes.go b/pkg/cloudbroker/account/list_computes.go index fe9017c..bcd0173 100644 --- a/pkg/cloudbroker/account/list_computes.go +++ b/pkg/cloudbroker/account/list_computes.go @@ -46,6 +46,10 @@ type ListComputesRequest struct { // Required: false ExtNetID uint64 `url:"extNetId,omitempty" json:"extNetId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -57,6 +61,7 @@ type ListComputesRequest struct { // ListComputes gets list of all compute instances under specified account, accessible by the user func (a Account) ListComputes(ctx context.Context, req ListComputesRequest) (*ListComputes, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/account/list_deleted.go b/pkg/cloudbroker/account/list_deleted.go index 4d4cc42..2e30a36 100644 --- a/pkg/cloudbroker/account/list_deleted.go +++ b/pkg/cloudbroker/account/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted accounts @@ -20,6 +22,10 @@ type ListDeletedRequest struct { // Required: false ACL string `url:"acl,omitempty" json:"acl,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -31,6 +37,11 @@ type ListDeletedRequest struct { // ListDeleted gets list all deleted accounts the user has access to func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListAccounts, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/account/listDeleted" res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/account/list_disks.go b/pkg/cloudbroker/account/list_disks.go index cd6eea5..f54a3e4 100644 --- a/pkg/cloudbroker/account/list_disks.go +++ b/pkg/cloudbroker/account/list_disks.go @@ -30,6 +30,10 @@ type ListDisksRequest struct { // Required: false Type string `url:"type,omitempty" json:"type,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListDisksRequest struct { // ListDisks gets list of all currently unattached disks under specified account func (a Account) ListDisks(ctx context.Context, req ListDisksRequest) (*ListDisks, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/account/list_flip_groups.go b/pkg/cloudbroker/account/list_flip_groups.go index 6a62d74..c97e8a4 100644 --- a/pkg/cloudbroker/account/list_flip_groups.go +++ b/pkg/cloudbroker/account/list_flip_groups.go @@ -38,6 +38,10 @@ type ListFLIPGroupsRequest struct { // Required: false FLIPGroupID uint64 `url:"flipGroupId,omitempty" json:"flipGroupId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -49,6 +53,7 @@ type ListFLIPGroupsRequest struct { // ListFLIPGroups gets list of all FLIPGroups under specified account, accessible by the user func (a Account) ListFLIPGroups(ctx context.Context, req ListFLIPGroupsRequest) (*ListFLIPGroups, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/account/list_rg.go b/pkg/cloudbroker/account/list_rg.go index 75da776..ded19bb 100644 --- a/pkg/cloudbroker/account/list_rg.go +++ b/pkg/cloudbroker/account/list_rg.go @@ -41,10 +41,15 @@ type ListRGRequest struct { // Find by status // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` } // ListRG gets list of all resource groups under specified account, accessible by the user func (a Account) ListRG(ctx context.Context, req ListRGRequest) (*ListRG, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/account/list_vins.go b/pkg/cloudbroker/account/list_vins.go index 9270bfd..2e380ae 100644 --- a/pkg/cloudbroker/account/list_vins.go +++ b/pkg/cloudbroker/account/list_vins.go @@ -30,6 +30,10 @@ type ListVINSRequest struct { // Required: false ExtIP string `url:"extIp,omitempty" json:"extIp,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListVINSRequest struct { // ListVINS gets list of all ViNSes under specified account, accessible by the user func (a Account) ListVINS(ctx context.Context, req ListVINSRequest) (*ListVINS, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/account/models.go b/pkg/cloudbroker/account/models.go index 805bcf8..6c998ac 100644 --- a/pkg/cloudbroker/account/models.go +++ b/pkg/cloudbroker/account/models.go @@ -143,6 +143,9 @@ type InfoAccount struct { // Company URL CompanyURL string `json:"companyurl"` + // Compute Features + ComputeFeatures []string `json:"computeFeatures"` + // CPU allocation parameter CPUAllocationParameter string `json:"cpu_allocation_parameter"` @@ -530,6 +533,12 @@ type ItemVINS struct { // External IP ExternalIP string `json:"externalIP"` + // Extnet ID + ExtnetId uint64 `json:"extnetId"` + + // Free IPs + FreeIPs uint64 `json:"freeIPs"` + // ID ID uint64 `json:"id"` diff --git a/pkg/cloudbroker/account/revoke_access_templates.go b/pkg/cloudbroker/account/revoke_access_templates.go new file mode 100644 index 0000000..b0793db --- /dev/null +++ b/pkg/cloudbroker/account/revoke_access_templates.go @@ -0,0 +1,42 @@ +package account + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// RevokeAccessTemplatesRequest struct to unshare images with account +type RevokeAccessTemplatesRequest struct { + // ID an account + // Required: true + AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` + + // list of image IDs + // Required: true + ImageIDs []uint64 `url:"imageIds" json:"imageIds" validate:"required"` +} + +// RevokeAccessTemplates unshares specified images with specified account +func (a Account) RevokeAccessTemplates(ctx context.Context, req RevokeAccessTemplatesRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/account/revokeAccessTemplates" + + 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/set_cpu_allocation_parameter.go b/pkg/cloudbroker/account/set_cpu_allocation_parameter.go index 8409c25..2aeb600 100644 --- a/pkg/cloudbroker/account/set_cpu_allocation_parameter.go +++ b/pkg/cloudbroker/account/set_cpu_allocation_parameter.go @@ -11,7 +11,7 @@ import ( type SetCPUAllocationParameterRequest struct { // Account ID // Required: true - AccountID uint64 `url:"accountId" json:"accoutnId" validate:"required"` + AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` // CPU allocation parameter. // If "strict" VM can't be run if not enough CPU resources. diff --git a/pkg/cloudbroker/account/set_cpu_allocation_ratio.go b/pkg/cloudbroker/account/set_cpu_allocation_ratio.go index f620337..4dcb0e1 100644 --- a/pkg/cloudbroker/account/set_cpu_allocation_ratio.go +++ b/pkg/cloudbroker/account/set_cpu_allocation_ratio.go @@ -11,7 +11,7 @@ import ( type SetCPUAllocationRatioRequest struct { // Account ID // Required: true - AccountID uint64 `url:"accountId" json:"accoutnId" validate:"required"` + AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` // CPU allocation ratio, i.e. one pCPU = ratio*vCPU // if don't set, default value = 0 diff --git a/pkg/cloudbroker/account/update_compute_features.go b/pkg/cloudbroker/account/update_compute_features.go new file mode 100644 index 0000000..6bd659a --- /dev/null +++ b/pkg/cloudbroker/account/update_compute_features.go @@ -0,0 +1,43 @@ +package account + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// UpdateComputeFeaturesRequest struct to update advanced compute features +type UpdateComputeFeaturesRequest struct { + // ID of account + // Required: true + AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` + + // Advanced compute features, + // one of: hugepages, numa, cpupin, vfnic + // Required: false + ComputeFeatures []string `url:"computeFeatures,omitempty" json:"computeFeatures,omitempty" validate:"omitempty,computeFeatures"` +} + +// UpdateComputeFeatures updates advanced compute features +func (a Account) UpdateComputeFeatures(ctx context.Context, req UpdateComputeFeaturesRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/account/updateComputeFeatures" + + 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/apiaccess/list.go b/pkg/cloudbroker/apiaccess/list.go index c4d7550..ee723bf 100644 --- a/pkg/cloudbroker/apiaccess/list.go +++ b/pkg/cloudbroker/apiaccess/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of all non deleted apiaccess instances. @@ -32,6 +34,10 @@ type ListRequest struct { // Required: false CreatedBefore uint64 `url:"createdBefore,omitempty" json:"createdBefore,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -43,6 +49,7 @@ type ListRequest struct { // List gets list of all non deleted apiaccess instances as a ListAPIAccess struct func (a APIAccess) List(ctx context.Context, req ListRequest) (*ListAPIAccess, error) { + res, err := a.ListRaw(ctx, req) if err != nil { return nil, err @@ -60,6 +67,11 @@ func (a APIAccess) List(ctx context.Context, req ListRequest) (*ListAPIAccess, e // ListRaw gets list of all non deleted apiaccess instances as an array of bytes func (a APIAccess) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/apiaccess/list" res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/apiaccess/list_deleted.go b/pkg/cloudbroker/apiaccess/list_deleted.go index 08e2522..e93bf5c 100644 --- a/pkg/cloudbroker/apiaccess/list_deleted.go +++ b/pkg/cloudbroker/apiaccess/list_deleted.go @@ -4,10 +4,16 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct for getting list of all deleted apiaccess instances. type ListDeletedRequest struct { + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number. // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -19,6 +25,11 @@ type ListDeletedRequest struct { // ListDeleted gets list of all deleted apiaccess instances. func (a APIAccess) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListAPIAccess, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/apiaccess/listDeleted" info := ListAPIAccess{} diff --git a/pkg/cloudbroker/apiaccess/models.go b/pkg/cloudbroker/apiaccess/models.go index 220d175..465c9e0 100644 --- a/pkg/cloudbroker/apiaccess/models.go +++ b/pkg/cloudbroker/apiaccess/models.go @@ -124,7 +124,7 @@ type CloudBrokerEndpoints struct { Health []string `json:"health,omitempty"` IaaS []string `json:"iaas,omitempty"` Image []string `json:"image,omitempty"` - Job []string `json:"job,omitempty"` + Job interface{} `json:"job,omitempty"` K8CI []string `json:"k8ci,omitempty"` K8S []string `json:"k8s,omitempty"` KVMPPC []string `json:"kvmppc,omitempty"` @@ -141,7 +141,7 @@ type CloudBrokerEndpoints struct { PGPU []string `json:"pgpu,omitempty"` Prometheus []string `json:"prometheus,omitempty"` QOS []string `json:"qos,omitempty"` - Resmon []string `json:"resmon,omitempty"` + Resmon interface{} `json:"resmon,omitempty"` RG []string `json:"rg,omitempty"` Sep []string `json:"sep,omitempty"` Stack []string `json:"stack,omitempty"` diff --git a/pkg/cloudbroker/apiaccess/user_list.go b/pkg/cloudbroker/apiaccess/user_list.go index b5fe3e2..f02e9bc 100644 --- a/pkg/cloudbroker/apiaccess/user_list.go +++ b/pkg/cloudbroker/apiaccess/user_list.go @@ -13,6 +13,14 @@ type UserListRequest struct { // APIAccess group ID // Required: true APIAccessID uint64 `url:"apiaccessId" json:"apiaccessId" 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"` } // UserList gets a list of users currently included in the specified group. diff --git a/pkg/cloudbroker/audit/audit.go b/pkg/cloudbroker/audit/audit.go index 17904f3..26f69ef 100644 --- a/pkg/cloudbroker/audit/audit.go +++ b/pkg/cloudbroker/audit/audit.go @@ -8,8 +8,8 @@ type Audit struct { } // Builder for audit endpoint -func New(client interfaces.Caller) *Audit { +func New(client interfaces.Caller) *Audit{ return &Audit{ client: client, } -} +} \ No newline at end of file diff --git a/pkg/cloudbroker/audit/linked_jobs.go b/pkg/cloudbroker/audit/linked_jobs.go index cfe17ba..ebf773e 100644 --- a/pkg/cloudbroker/audit/linked_jobs.go +++ b/pkg/cloudbroker/audit/linked_jobs.go @@ -43,4 +43,4 @@ func (a Audit) GetRawLinkedJobs(ctx context.Context, req LinkedJobsRequest) ([]b res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) return res, err -} +} \ No newline at end of file diff --git a/pkg/cloudbroker/audit/list.go b/pkg/cloudbroker/audit/list.go index e7a7cc6..cf05fcb 100644 --- a/pkg/cloudbroker/audit/list.go +++ b/pkg/cloudbroker/audit/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to give list of account audits @@ -25,9 +27,17 @@ type ListRequest struct { // Required: false Call string `url:"call,omitempty" json:"call,omitempty"` - // Find by HTTP status code + // Find by HTTP min status code + // Required: false + MinStatusCode uint64 `url:"minStatusCode,omitempty" json:"minStatusCode,omitempty"` + + // Find by HTTP max status code + // Required: false + MaxStatusCode uint64 `url:"maxStatusCode,omitempty" json:"maxStatusCode,omitempty"` + + // Sort by one of supported fields, format +|-(field) // Required: false - StatusCode uint64 `url:"statusCode,omitempty" json:"statusCode,omitempty"` + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` // Page number // Required: false @@ -40,6 +50,7 @@ type ListRequest struct { // List gets audit records for the specified account object func (a Audit) List(ctx context.Context, req ListRequest) (*ListAudits, error) { + res, err := a.ListRaw(ctx, req) if err != nil { return nil, err @@ -57,6 +68,11 @@ func (a Audit) List(ctx context.Context, req ListRequest) (*ListAudits, error) { // ListRaw gets list of audit records an array of bytes func (a Audit) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/audit/list" res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/audit/models.go b/pkg/cloudbroker/audit/models.go index 73588f9..af78ecd 100644 --- a/pkg/cloudbroker/audit/models.go +++ b/pkg/cloudbroker/audit/models.go @@ -82,6 +82,9 @@ type ItemLinkedJobs struct { // CMD CMD string `json:"cmd"` + // GUID + GUID string `json:"guid"` + // NID NID uint64 `json:"nid"` diff --git a/pkg/cloudbroker/backup/list_backup_paths.go b/pkg/cloudbroker/backup/list_backup_paths.go index 66bf748..15f1b29 100644 --- a/pkg/cloudbroker/backup/list_backup_paths.go +++ b/pkg/cloudbroker/backup/list_backup_paths.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "net/http" + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) @@ -15,6 +16,7 @@ type ListBackupPathsRequest struct { // ListBackupPaths gets list of backup paths func (b Backup) ListBackupPaths(ctx context.Context, req ListBackupPathsRequest) ([]string, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/compute/affinity_relations.go b/pkg/cloudbroker/compute/affinity_relations.go index 16ef53c..b43f11d 100644 --- a/pkg/cloudbroker/compute/affinity_relations.go +++ b/pkg/cloudbroker/compute/affinity_relations.go @@ -13,10 +13,6 @@ type AffinityRelationsRequest struct { // ID of the compute instance // Required: true ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` - - // Affinity group label - // Required: false - AffinityLabel string `url:"affinityLabel,omitempty" json:"affinityLabel,omitempty"` } // AffinityRelations gets dict of computes divided by affinity and anti affinity rules diff --git a/pkg/cloudbroker/compute/affinity_rule_add.go b/pkg/cloudbroker/compute/affinity_rule_add.go index 7de9794..78f2402 100644 --- a/pkg/cloudbroker/compute/affinity_rule_add.go +++ b/pkg/cloudbroker/compute/affinity_rule_add.go @@ -41,6 +41,7 @@ type AffinityRuleAddRequest struct { // Value that must match the key to be taken into account when analyzing this rule // Required: false + // Not required on purpose: despite required tag on platform, empty string is allowed Value string `url:"value" json:"value"` } diff --git a/pkg/cloudbroker/compute/affinity_rule_remove.go b/pkg/cloudbroker/compute/affinity_rule_remove.go index 4571a54..7f5057a 100644 --- a/pkg/cloudbroker/compute/affinity_rule_remove.go +++ b/pkg/cloudbroker/compute/affinity_rule_remove.go @@ -39,6 +39,7 @@ type AffinityRuleRemoveRequest struct { // Value that must match the key to be taken into account when analyzing this rule // Required: false + // Not required on purpose: despite required tag on platform, empty string is allowed Value string `url:"value" json:"value"` } diff --git a/pkg/cloudbroker/compute/anti_affinity_rule_add.go b/pkg/cloudbroker/compute/anti_affinity_rule_add.go index 538e568..b73b7de 100644 --- a/pkg/cloudbroker/compute/anti_affinity_rule_add.go +++ b/pkg/cloudbroker/compute/anti_affinity_rule_add.go @@ -39,6 +39,7 @@ type AntiAffinityRuleAddRequest struct { // Value that must match the key to be taken into account when analyzing this rule // Required: false + // Not required on purpose: despite required tag on platform, empty string is allowed Value string `url:"value" json:"value"` } diff --git a/pkg/cloudbroker/compute/anti_affinity_rule_remove.go b/pkg/cloudbroker/compute/anti_affinity_rule_remove.go index b409739..7589a78 100644 --- a/pkg/cloudbroker/compute/anti_affinity_rule_remove.go +++ b/pkg/cloudbroker/compute/anti_affinity_rule_remove.go @@ -39,6 +39,7 @@ type AntiAffinityRuleRemoveRequest struct { // Value that must match the key to be taken into account when analyzing this rule // Required: false + // Not required on purpose: despite required tag on platform, empty string is allowed Value string `url:"value" json:"value"` } diff --git a/pkg/cloudbroker/compute/boot_disk_set.go b/pkg/cloudbroker/compute/boot_disk_set.go new file mode 100644 index 0000000..eb782ea --- /dev/null +++ b/pkg/cloudbroker/compute/boot_disk_set.go @@ -0,0 +1,42 @@ +package compute + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// BootDiskSetRequest struct to set boot disk for compute +type BootDiskSetRequest struct { + // ID of compute instance + // Required: true + ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + + // ID of the disk to set as boot + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// BootDiskSet sets boot disk for compute +func (c Compute) BootDiskSet(ctx context.Context, req BootDiskSetRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/compute/bootDiskSet" + + 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 new file mode 100644 index 0000000..d394976 --- /dev/null +++ b/pkg/cloudbroker/compute/create_template_from_blank.go @@ -0,0 +1,112 @@ +package compute + +import ( + "context" + "net/http" + "strconv" + "strings" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// CreateTemplateFromBlankRequest struct to create template from boot disk of current compute +type CreateTemplateFromBlankRequest struct { + // ID of the compute to create template from + // Required: true + ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + + // Name of the rescue disk + // Required: true + Name string `url:"name" json:"name" validate:"required"` + + // Boot type of image BIOS or UEFI + // Required: true + BootType string `url:"boottype" json:"boottype" validate:"imageBootType"` + + // Image type linux, windows or other + // Required: true + ImageType string `url:"imagetype" json:"imagetype" validate:"imageType"` + + // Username for the image + // Required: false + Username string `url:"username,omitempty" json:"username,omitempty"` + + // Password for the image + // Required: false + Password string `url:"password,omitempty" json:"password,omitempty"` + + // Account ID to make the image exclusive + // Required: false + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + + // SEP ID + // Required: false + SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"` + + // Pool for image create + // Required: false + PoolName string `url:"poolName,omitempty" json:"poolName,omitempty"` + + // Does this machine supports hot resize + // Default: false + // Required: false + HotResize bool `url:"hotresize" json:"hotresize"` +} + +type wrapperCreateTemplateFromBlankRequest struct { + CreateTemplateFromBlankRequest + AsyncMode bool `url:"asyncMode"` +} + +// CreateTemplateFromBlank creates template from boot disk of current compute in sync mode. +// It returns id of created compute and error. +func (c Compute) CreateTemplateFromBlank(ctx context.Context, req CreateTemplateFromBlankRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + reqWrapped := wrapperCreateTemplateFromBlankRequest{ + CreateTemplateFromBlankRequest: req, + AsyncMode: false, + } + + url := "/cloudbroker/compute/createTemplateFromBlank" + + res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) + if err != nil { + return 0, err + } + + result, err := strconv.ParseUint(string(res), 10, 64) + if err != nil { + return 0, err + } + + return result, nil +} + +// CreateTemplateFromBlankAsync creates template from boot disk of current compute in async mode. +// It returns guid of task and error. +func (c Compute) CreateTemplateFromBlankAsync(ctx context.Context, req CreateTemplateFromBlankRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + reqWrapped := wrapperCreateTemplateFromBlankRequest{ + CreateTemplateFromBlankRequest: req, + AsyncMode: true, + } + + url := "/cloudbroker/compute/createTemplateFromBlank" + + res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) + if err != nil { + return "", err + } + + result := strings.ReplaceAll(string(res), "\"", "") + + return result, nil +} diff --git a/pkg/cloudbroker/compute/disk_migrate.go b/pkg/cloudbroker/compute/disk_migrate.go new file mode 100644 index 0000000..1559984 --- /dev/null +++ b/pkg/cloudbroker/compute/disk_migrate.go @@ -0,0 +1,53 @@ +package compute + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DiskMigrateRequest struct to migrate compute's disk to target disk +type DiskMigrateRequest struct { + // ID of compute instance + // Required: true + ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + + // ID source disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` + + // ID target disk + // Required: true + TargetDiskID uint64 `url:"targetDiskId" json:"targetDiskId" validate:"required"` + + // Migration mode. 1 - Data migration and domain update were already completed by third-party software. + // Use this if target disk already connected to compute and you only need to save changes for next reboot. + // Required: true + Mode int64 `url:"mode" json:"mode" validate:"required"` +} + +// DiskMigrate - migrate compute's disk to target disk. Source disk will be detached, target disk will be attached to the same PCI slot. +// (WARNING) Current realisation is limited. No actual data migration will be performed. +// Use this API if target disk already connected to compute and you only need to save changes for next reboot (mode: 1). +func (c Compute) DiskMigrate(ctx context.Context, req DiskMigrateRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/compute/diskMigrate" + + 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/disk_switch_to_replication.go b/pkg/cloudbroker/compute/disk_switch_to_replication.go new file mode 100644 index 0000000..41b5886 --- /dev/null +++ b/pkg/cloudbroker/compute/disk_switch_to_replication.go @@ -0,0 +1,46 @@ +package compute + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DiskSwitchToReplicationRequest struct to switch disk to it's replication +type DiskSwitchToReplicationRequest struct { + // ID of compute instance + // Required: true + ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` + + // ID of the disk to switch + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` + + // Delete replication relationship + // Required: false + StopReplication bool `url:"stopReplication" json:"stopReplication"` +} + +// DiskSwitchToReplication switches disk to it's replication +func (c Compute) DiskSwitchToReplication(ctx context.Context, req DiskSwitchToReplicationRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/compute/diskSwitchToReplication" + + 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/get_custom_fields.go b/pkg/cloudbroker/compute/get_custom_fields.go new file mode 100644 index 0000000..be1ebf2 --- /dev/null +++ b/pkg/cloudbroker/compute/get_custom_fields.go @@ -0,0 +1,40 @@ +package compute + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// GetCustomFieldsRequest struct to get Compute's customFields +type GetCustomFieldsRequest struct { + // Compute ID + // Required: true + ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` +} + +// GetCustomFields gets Compute's customFields +func (c Compute) GetCustomFields(ctx context.Context, req GetCustomFieldsRequest) (interface{}, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/compute/getCustomFields" + + res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + var info interface{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudbroker/compute/list.go b/pkg/cloudbroker/compute/list.go index b8f0a2d..097789f 100644 --- a/pkg/cloudbroker/compute/list.go +++ b/pkg/cloudbroker/compute/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of available computes @@ -52,6 +54,10 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -64,6 +70,7 @@ type ListRequest struct { // List gets list of the available computes as a ListComputes struct. // Filtering based on status is possible func (c Compute) List(ctx context.Context, req ListRequest) (*ListComputes, error) { + res, err := c.ListRaw(ctx, req) if err != nil { return nil, err @@ -81,6 +88,11 @@ func (c Compute) List(ctx context.Context, req ListRequest) (*ListComputes, erro // ListRaw gets list of the available computes as an array of bytes func (c Compute) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/compute/list" res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/compute/list_deleted.go b/pkg/cloudbroker/compute/list_deleted.go index 2ae9b95..f5d4696 100644 --- a/pkg/cloudbroker/compute/list_deleted.go +++ b/pkg/cloudbroker/compute/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get deleted computes list @@ -44,6 +46,10 @@ type ListDeletedRequest struct { // Required: false ExtNetID uint64 `url:"extNetId,omitempty" json:"extNetId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -55,6 +61,11 @@ type ListDeletedRequest struct { // ListDeleted gets list all deleted computes func (c Compute) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListComputes, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/compute/listDeleted" res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/compute/list_pci_device.go b/pkg/cloudbroker/compute/list_pci_device.go index d31a1d7..366a63a 100644 --- a/pkg/cloudbroker/compute/list_pci_device.go +++ b/pkg/cloudbroker/compute/list_pci_device.go @@ -22,14 +22,18 @@ type ListPCIDeviceRequest struct { // Required: false DevID uint64 `url:"devId,omitempty" json:"devId,omitempty"` - // Find by type + // Find by name // Required: false - Type string `url:"type,omitempty" json:"type,omitempty"` + Name string `url:"name,omitempty" json:"name,omitempty"` // Find by status // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListPCIDeviceRequest struct { // ListPCIDevice gets list of PCI device func (c Compute) ListPCIDevice(ctx context.Context, req ListPCIDeviceRequest) (*ListPCIDevices, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/compute/list_vgpu.go b/pkg/cloudbroker/compute/list_vgpu.go index 5a023b4..b412d9b 100644 --- a/pkg/cloudbroker/compute/list_vgpu.go +++ b/pkg/cloudbroker/compute/list_vgpu.go @@ -26,6 +26,10 @@ type ListVGPURequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListVGPURequest struct { // ListVGPU gets list of GPU for compute func (c Compute) ListVGPU(ctx context.Context, req ListVGPURequest) (*ListVGPUs, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/compute/models.go b/pkg/cloudbroker/compute/models.go index 4b39686..8cfbcb4 100644 --- a/pkg/cloudbroker/compute/models.go +++ b/pkg/cloudbroker/compute/models.go @@ -439,6 +439,9 @@ type ItemDisk struct { // Reality device number RealityDeviceNumber uint64 `json:"realityDeviceNumber"` + // Replication + Replication interface{} `json:"replication"` + // Reference ID ReferenceID string `json:"referenceId"` @@ -496,6 +499,9 @@ type ItemInterface struct { // Default GW DefGW string `json:"defGw"` + // Enabled + Enabled bool `json:"enabled"` + // FLIPGroup ID FLIPGroupID uint64 `json:"flipgroupId"` @@ -523,6 +529,9 @@ type ItemInterface struct { // Network type NetType string `json:"netType"` + // NodeID + NodeID int64 `json:"nodeId"` + // PCI slot PCISlot int64 `json:"pciSlot"` @@ -604,6 +613,9 @@ type InfoCompute struct { // Compute CI ID ComputeCIID uint64 `json:"computeciId"` + // CPU Pin + CPUPin bool `json:"cpupin"` + // Number of CPU CPUs uint64 `json:"cpus"` @@ -637,6 +649,9 @@ type InfoCompute struct { // GUID GUID uint64 `json:"guid"` + // HPBacked + HPBacked bool `json:"hpBacked"` + // ID ID uint64 `json:"id"` @@ -667,6 +682,12 @@ type InfoCompute struct { // Need reboot NeedReboot bool `json:"needReboot"` + // Numa Affinity + NumaAffinity string `json:"numaAffinity"` + + //NumaNodeId + NumaNodeId int64 `json:"numaNodeId"` + // List OS users OSUsers ListOSUsers `json:"osUsers"` @@ -742,11 +763,215 @@ type InfoCompute struct { // Detailed information about compute type RecordCompute struct { + // Account ID + AccountID uint64 `json:"accountId"` + + // Account name + AccountName string `json:"accountName"` + + // Access Control List + ACL []interface{} `json:"acl"` + + // Affinity label + AffinityLabel string `json:"affinityLabel"` + + // Affinity rules + AffinityRules ListRules `json:"affinityRules"` + + // Affinity weight + AffinityWeight uint64 `json:"affinityWeight"` + + // Anti affinity rules + AntiAffinityRules ListRules `json:"antiAffinityRules"` + + // Architecture + Arch string `json:"arch"` + + // Boot order + BootOrder []string `json:"bootOrder"` + + // Boot disk size + BootDiskSize uint64 `json:"bootdiskSize"` + + // cd Image Id + CdImageId uint64 `json:"cdImageId"` + + // Clone reference + CloneReference uint64 `json:"cloneReference"` + + // List clone IDs + Clones []uint64 `json:"clones"` + + // Compute CI ID + ComputeCIID uint64 `json:"computeciId"` + + // CPU Pin + CPUPin bool `json:"cpupin"` + + // Number of CPU + CPUs uint64 `json:"cpus"` + + // Created by + CreatedBy string `json:"createdBy"` + + // Created time + CreatedTime uint64 `json:"createdTime"` + + // Custom fields + CustomFields map[string]interface{} `json:"customFields"` + + // Deleted by + DeletedBy string `json:"deletedBy"` + + // Deleted time + DeletedTime uint64 `json:"deletedTime"` + + // Description + Description string `json:"desc"` + + // Devices + Devices interface{} `json:"devices"` + // List disks Disks ListDisks `json:"disks"` - // Main information about compute - InfoCompute + // Driver + Driver string `json:"driver"` + + // Grid ID + GID uint64 `json:"gid"` + + // GUID + GUID uint64 `json:"guid"` + + // HPBacked + HPBacked bool `json:"hpBacked"` + + // ID + ID uint64 `json:"id"` + + // Image ID + ImageID uint64 `json:"imageId"` + + // ImageName + ImageName string `json:"imageName"` + + // List interfaces + Interfaces ListInterfaces `json:"interfaces"` + + // Lock status + LockStatus string `json:"lockStatus"` + + // Manager ID + ManagerID uint64 `json:"managerId"` + + // Manager type + ManagerType string `json:"managerType"` + + // Migration job + MigrationJob uint64 `json:"migrationjob"` + + // Milestones + Milestones uint64 `json:"milestones"` + + // Name + Name string `json:"name"` + + // Natable VINS ID + NatableVINSID uint64 `json:"natableVinsId"` + + // Natable VINS IP + NatableVINSIP string `json:"natableVinsIp"` + + // Natable VINS Name + NatableVINSName string `json:"natableVinsName"` + + // Natable VINS network + NatableVINSNetwork string `json:"natableVinsNetwork"` + + // Natable VINS network name + NatableVINSNetworkName string `json:"natableVinsNetworkName"` + + // Need reboot + NeedReboot bool `json:"needReboot"` + + // NumaAffinity + NumaAffinity string `json:"numaAffinity"` + + //NumaNodeId + NumaNodeId int64 `json:"numaNodeId"` + + // List OS users + OSUsers ListOSUsers `json:"osUsers"` + + // Pinned + Pinned bool `json:"pinned"` + + // Number of RAM + RAM uint64 `json:"ram"` + + // Reference ID + ReferenceID string `json:"referenceId"` + + // Registered + Registered bool `json:"registered"` + + // Resource name + ResName string `json:"resName"` + + // Resource group ID + RGID uint64 `json:"rgId"` + + // Resource group name + RGName string `json:"rgName"` + + // SnapSets + SnapSets ListSnapshots `json:"snapSets"` + + // Stack ID + StackID uint64 `json:"stackId"` + + // Stack name + StackName string `json:"stackName"` + + // Stateless SEP ID + StatelessSEPID int64 `json:"statelessSepId"` + + // Stateless SEP Type + StatelessSEPType string `json:"statelessSepType"` + + // Status + Status string `json:"status"` + + // Tags + Tags map[string]interface{} `json:"tags"` + + // Tech status + TechStatus string `json:"techStatus"` + + // Total disk size + TotalDiskSize uint64 `json:"totalDisksSize"` + + // Updated by + UpdatedBy string `json:"updatedBy"` + + // Updated time + UpdatedTime uint64 `json:"updatedTime"` + + // User managed + UserManaged bool `json:"userManaged"` + + // Userdata + Userdata interface{} `json:"userdata"` + + // List VGPU IDs + VGPUs []uint64 `json:"vgpus"` + + // Virtual image ID + VirtualImageID uint64 `json:"virtualImageId"` + + // VirtualImageName + VirtualImageName string `json:"virtualImageName"` } // Information about of disk IDs @@ -781,11 +1006,11 @@ type ListComputes struct { // Data Data []ItemCompute `json:"data"` - // Entru Count - EntryCount uint64 `json:"entrycount"` + // EntryCount + EntryCount uint64 `json:"entryCount"` } -// Short information about audir +// Short information about audit type ItemAudit struct { // Epoch Epoch float64 `json:"epoch"` @@ -848,8 +1073,65 @@ type ListPCIDevices struct { // List VGPUs type ListVGPUs struct { // Data - Data []interface{} `json:"data"` + Data []ItemVGPU `json:"data"` // Entry count EntryCount uint64 `json:"entryCount"` } + +// Main information about vgpu device +type ItemVGPU struct { + // Account ID + AccountID uint64 `json:"accountId"` + + // Created Time + CreatedTime uint64 `json:"createdTime"` + + // Deleted Time + DeletedTime uint64 `json:"deletedTime"` + + // GID + GID uint64 `json:"gid"` + + // GUID + GUID uint64 `json:"guid"` + + // ID + ID uint64 `json:"id"` + + // Last Claimed By + LastClaimedBy uint64 `json:"lastClaimedBy"` + + // Last Update Time + LastUpdateTime uint64 `json:"lastUpdateTime"` + + // Mode + Mode string `json:"mode"` + + // PCI Slot + PCISlot uint64 `json:"pciSlot"` + + // PGPUID + PGPUID uint64 `json:"pgpuid"` + + // Profile ID + ProfileID uint64 `json:"profileId"` + + // RAM + RAM uint64 `json:"ram"` + + // Reference ID + ReferenceID string `json:"referenceId"` + + // RG ID + RGID uint64 `json:"rgId"` + + // Status + Status string `json:"status"` + + // Type + Type string `json:"type"` + + // VM ID + VMID uint64 `json:"vmid"` +} diff --git a/pkg/cloudbroker/compute/pfw_add.go b/pkg/cloudbroker/compute/pfw_add.go index 749c453..9afee7d 100644 --- a/pkg/cloudbroker/compute/pfw_add.go +++ b/pkg/cloudbroker/compute/pfw_add.go @@ -24,8 +24,8 @@ type PFWAddRequest struct { PublicPortEnd int64 `url:"publicPortEnd,omitempty" json:"publicPortEnd,omitempty"` // Internal base port number - // Required: true - LocalBasePort uint64 `url:"localBasePort" json:"localBasePort" validate:"required"` + // Required: false + LocalBasePort uint64 `url:"localBasePort,omitempty" json:"localBasePort,omitempty"` // Network protocol // Should be one of: diff --git a/pkg/cloudbroker/compute/resize.go b/pkg/cloudbroker/compute/resize.go index eff6f2d..9a113c4 100644 --- a/pkg/cloudbroker/compute/resize.go +++ b/pkg/cloudbroker/compute/resize.go @@ -33,6 +33,16 @@ type ResizeRequest struct { Reason string `url:"reason,omitempty" json:"reason,omitempty"` } +// GetRAM returns RAM field values +func (r ResizeRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + // Resize resizes compute instance func (c Compute) Resize(ctx context.Context, req ResizeRequest) (bool, error) { err := validators.ValidateRequest(req) diff --git a/pkg/cloudbroker/disks/from_platform_disk.go b/pkg/cloudbroker/disks/from_platform_disk.go new file mode 100644 index 0000000..d0450b4 --- /dev/null +++ b/pkg/cloudbroker/disks/from_platform_disk.go @@ -0,0 +1,127 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + "strings" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// FromPlatformDiskRequest struct to create template from platform disk +type FromPlatformDiskRequest struct { + // ID of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` + + // Name of the rescue disk + // Required: true + Name string `url:"name" json:"name" validate:"required"` + + // Boot type of image BIOS or UEFI + // Required: true + BootType string `url:"boottype" json:"boottype" validate:"imageBootType"` + + // Image type linux, windows or other + // Required: true + ImageType string `url:"imagetype" json:"imagetype" validate:"imageType"` + + // Binary architecture of this image + // Should be: + // - X86_64 + // - PPC64_LE + // Required: true + Architecture string `url:"architecture" json:"architecture" validate:"imageArchitecture"` + + // Username for the image + // Required: false + Username string `url:"username,omitempty" json:"username,omitempty"` + + // Password for the image + // Required: false + Password string `url:"password,omitempty" json:"password,omitempty"` + + // Account ID to make the image exclusive + // Required: false + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + + // SEP ID + // Required: false + SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"` + + // Pool for image create + // Required: false + PoolName string `url:"poolName,omitempty" json:"poolName,omitempty"` + + // List of types of compute suitable for image + // Example: [ "KVM_X86" ] + // Required: false + Drivers []string `url:"drivers" json:"drivers" validate:"min=1,max=2,imageDrivers"` + + // Does this machine supports hot resize + // Required: false + HotResize bool `url:"hotresize" json:"hotresize"` + + // Bootable image + // Required: true + Bootable bool `url:"bootable" json:"bootable"` +} + +type wrapperFromPlatformDiskRequest struct { + FromPlatformDiskRequest + AsyncMode bool `url:"asyncMode"` +} + +// FromPlatformDisk creates template from platform disk in sync mode. +// It returns id of created disk and error. +func (d Disks) FromPlatformDisk(ctx context.Context, req FromPlatformDiskRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/disks/fromPlatformDisk" + + reqWrapped := wrapperFromPlatformDiskRequest{ + FromPlatformDiskRequest: req, + AsyncMode: false, + } + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) + if err != nil { + return 0, err + } + + result, err := strconv.ParseUint(string(res), 10, 64) + if err != nil { + return 0, err + } + + return result, nil +} + +// FromPlatformDiskAsync creates template from platform disk in async mode. +// It returns guid of task and error. +func (d Disks) FromPlatformDiskAsync(ctx context.Context, req FromPlatformDiskRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/disks/fromPlatformDisk" + + reqWrapped := wrapperFromPlatformDiskRequest{ + FromPlatformDiskRequest: req, + AsyncMode: true, + } + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) + if err != nil { + return "", err + } + + result := strings.ReplaceAll(string(res), "\"", "") + + return result, nil +} diff --git a/pkg/cloudbroker/disks/list.go b/pkg/cloudbroker/disks/list.go index 2ac6bc2..d5b40fd 100644 --- a/pkg/cloudbroker/disks/list.go +++ b/pkg/cloudbroker/disks/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list/list_deleted of disks @@ -48,6 +50,10 @@ type ListRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -76,6 +82,11 @@ func (d Disks) List(ctx context.Context, req ListRequest) (*ListDisks, error) { // ListRaw gets list of the created disks belonging to an account as an array of bytes func (d Disks) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/disks/list" res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/disks/list_deleted.go b/pkg/cloudbroker/disks/list_deleted.go index 7fa8582..c68b436 100644 --- a/pkg/cloudbroker/disks/list_deleted.go +++ b/pkg/cloudbroker/disks/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted disks @@ -36,6 +38,10 @@ type ListDeletedRequest struct { // Required: false Type string `url:"type,omitempty" json:"type,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,11 @@ type ListDeletedRequest struct { // ListDeleted gets list of the deleted disks based on filter func (d Disks) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListDisks, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/disks/listDeleted" res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/disks/list_types.go b/pkg/cloudbroker/disks/list_types.go index c87f4fa..b3770e5 100644 --- a/pkg/cloudbroker/disks/list_types.go +++ b/pkg/cloudbroker/disks/list_types.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListTypesRequest struct to get list of types of disks @@ -12,6 +14,10 @@ type ListTypesRequest struct { // Required: false Detailed bool `url:"detailed" json:"detailed"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -23,6 +29,11 @@ type ListTypesRequest struct { // ListTypes gets list of defined disk types func (d Disks) ListTypes(ctx context.Context, req ListTypesRequest) (*ListTypes, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/disks/listTypes" res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/disks/list_unattached.go b/pkg/cloudbroker/disks/list_unattached.go index 0b509a8..67be75a 100644 --- a/pkg/cloudbroker/disks/list_unattached.go +++ b/pkg/cloudbroker/disks/list_unattached.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListUnattachedRequest struct to get list of unattached disk @@ -40,6 +42,10 @@ type ListUnattachedRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -51,6 +57,11 @@ type ListUnattachedRequest struct { // ListUnattached gets list of unattached disks func (d Disks) ListUnattached(ctx context.Context, req ListUnattachedRequest) (*ListUnattachedDisks, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/disks/listUnattached" res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/disks/models.go b/pkg/cloudbroker/disks/models.go index d114412..fbd35b8 100644 --- a/pkg/cloudbroker/disks/models.go +++ b/pkg/cloudbroker/disks/models.go @@ -137,6 +137,9 @@ type InfoDisk struct { // Reference ID ReferenceID string `json:"referenceId"` + // Replication + Replication interface{} `json:"replication"` + // Resource ID ResID string `json:"resId"` diff --git a/pkg/cloudbroker/disks/replicate.go b/pkg/cloudbroker/disks/replicate.go new file mode 100644 index 0000000..64917bb --- /dev/null +++ b/pkg/cloudbroker/disks/replicate.go @@ -0,0 +1,52 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicateRequest struct to create an empty disk in chosen SEP and pool combination. +type ReplicateRequest struct { + // Id of the disk to replicate. This disk will become master in replication + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` + + // Name of replica disk to create + // Required: true + Name string `url:"name" json:"name" validate:"required"` + + // ID of SEP to create slave disk + // Required: true + SepID uint64 `url:"sepId" json:"sepId" validate:"required"` + + // Pool name to create slave disk in + // Required: true + PoolName string `url:"poolName" json:"poolName" validate:"required"` +} + +// 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) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/disks/replicate" + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, 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/disks/replication_resume.go b/pkg/cloudbroker/disks/replication_resume.go new file mode 100644 index 0000000..cde360c --- /dev/null +++ b/pkg/cloudbroker/disks/replication_resume.go @@ -0,0 +1,38 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationResume struct to resume suspended replication +type ReplicationResumeRequest struct { + // Id of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// ReplicationResume resume suspended replication +func (d Disks) ReplicationResume(ctx context.Context, req ReplicationResumeRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/disks/replicationResume" + + 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/replication_reverse.go b/pkg/cloudbroker/disks/replication_reverse.go new file mode 100644 index 0000000..bdfe1e9 --- /dev/null +++ b/pkg/cloudbroker/disks/replication_reverse.go @@ -0,0 +1,38 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationReverseRequest struct to change role between disks replications +type ReplicationReverseRequest struct { + // Id of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// ReplicationReverse change role between disks replications +func (d Disks) ReplicationReverse(ctx context.Context, req ReplicationReverseRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/disks/replicationReverse" + + 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/replication_start.go b/pkg/cloudbroker/disks/replication_start.go new file mode 100644 index 0000000..ed21089 --- /dev/null +++ b/pkg/cloudbroker/disks/replication_start.go @@ -0,0 +1,43 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationStartRequest struct to starts replication between two chosen disks +type ReplicationStartRequest struct { + // Id of the disk to replicate. Primary disk in replication + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` + + // ID of target disk. Secondary disk in replication + // Required: true + TargetDiskID uint64 `url:"targetDiskId" json:"targetDiskId" validate:"required"` +} + +// ReplicationStart starts replication between two chosen disks. It's required for both disks to have same size to avoid replication conflicts +// Note: Source disk's SEP and target SEP supported only of TATLIN type. +func (d Disks) ReplicationStart(ctx context.Context, req ReplicationStartRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/disks/replicationStart" + + 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/replication_status.go b/pkg/cloudbroker/disks/replication_status.go new file mode 100644 index 0000000..4072d7f --- /dev/null +++ b/pkg/cloudbroker/disks/replication_status.go @@ -0,0 +1,37 @@ +package disks + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationStatusRequest struct to get replication status +type ReplicationStatusRequest struct { + // Id of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// ReplicationStatus get replication status +func (d Disks) ReplicationStatus(ctx context.Context, req ReplicationStatusRequest) (interface{}, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/disks/replicationStatus" + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + // result, err := strconv.ParseBool(string(res)) + // if err != nil { + // return nil, err + // } + + return res, nil +} diff --git a/pkg/cloudbroker/disks/replication_stop.go b/pkg/cloudbroker/disks/replication_stop.go new file mode 100644 index 0000000..86a805e --- /dev/null +++ b/pkg/cloudbroker/disks/replication_stop.go @@ -0,0 +1,38 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationStopRequest struct to remove replication between disks completely +type ReplicationStopRequest struct { + // Id of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// ReplicationStop remove replication between disks completely +func (d Disks) ReplicationStop(ctx context.Context, req ReplicationStopRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/disks/replicationStop" + + 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/replication_suspend.go b/pkg/cloudbroker/disks/replication_suspend.go new file mode 100644 index 0000000..a28b397 --- /dev/null +++ b/pkg/cloudbroker/disks/replication_suspend.go @@ -0,0 +1,38 @@ +package disks + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ReplicationSuspendRequest struct to pause replication with possibility to resume from pause moment +type ReplicationSuspendRequest struct { + // Id of the disk + // Required: true + DiskID uint64 `url:"diskId" json:"diskId" validate:"required"` +} + +// ReplicationSuspend pause replication with possibility to resume from pause moment +func (d Disks) ReplicationSuspend(ctx context.Context, req ReplicationSuspendRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/disks/replicationSuspend" + + 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/extnet/list.go b/pkg/cloudbroker/extnet/list.go index aa150cc..0f44c49 100644 --- a/pkg/cloudbroker/extnet/list.go +++ b/pkg/cloudbroker/extnet/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of external network @@ -36,6 +38,10 @@ type ListRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,7 @@ type ListRequest struct { // List gets list of all available external networks as a ListExtNet struct func (e ExtNet) List(ctx context.Context, req ListRequest) (*ListExtNet, error) { + res, err := e.ListRaw(ctx, req) if err != nil { return nil, err @@ -64,6 +71,11 @@ func (e ExtNet) List(ctx context.Context, req ListRequest) (*ListExtNet, error) // ListRaw gets list of all available external networks as an array of bytes func (e ExtNet) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/extnet/list" res, err := e.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/flipgroup/list.go b/pkg/cloudbroker/flipgroup/list.go index c91ce30..5505c39 100644 --- a/pkg/cloudbroker/flipgroup/list.go +++ b/pkg/cloudbroker/flipgroup/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of FLIPGroup available to the current user @@ -28,6 +30,10 @@ type ListRequest struct { // Required: false ByIP string `url:"byIp,omitempty" json:"byIp,omitempty"` + // Find by accountId + // Required: false + AccountId uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + // Find by resource group ID // Required: false RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"` @@ -36,6 +42,10 @@ type ListRequest struct { // Required: false ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -43,10 +53,19 @@ type ListRequest struct { // Page size // Required: false Size uint64 `url:"size,omitempty" json:"size,omitempty"` + + // Find by connId + // Required: false + ConnId uint64 `url:"connId,omitempty" json:"connId,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` } // List gets list of FLIPGroup managed cluster instances available to the current user as a ListFLIPGroups struct func (f FLIPGroup) List(ctx context.Context, req ListRequest) (*ListFLIPGroups, error) { + res, err := f.ListRaw(ctx, req) if err != nil { return nil, err @@ -64,6 +83,11 @@ func (f FLIPGroup) List(ctx context.Context, req ListRequest) (*ListFLIPGroups, // ListRaw gets list of FLIPGroup managed cluster instances available to the current user as an array of bytes func (f FLIPGroup) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/flipgroup/list" res, err := f.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/grid/add_custom_backup_path.go b/pkg/cloudbroker/grid/add_custom_backup_path.go new file mode 100644 index 0000000..f89522c --- /dev/null +++ b/pkg/cloudbroker/grid/add_custom_backup_path.go @@ -0,0 +1,42 @@ +package grid + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// AddCustomBackupPathRequest struct to add new path to the list of custom backup paths +type AddCustomBackupPathRequest struct { + // ID of the grid + // Required: true + GID uint64 `url:"gridId" json:"gridId" validate:"required"` + + // Absolute path + // Required: true + Path string `url:"path" json:"path" validate:"required"` +} + +// AddCustomBackupPath add new path to the list of custom backup paths +func (g Grid) AddCustomBackupPath(ctx context.Context, req AddCustomBackupPathRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/grid/addCustomBackupPath" + + res, err := g.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/grid/list.go b/pkg/cloudbroker/grid/list.go index b9ebc7c..b651a6c 100644 --- a/pkg/cloudbroker/grid/list.go +++ b/pkg/cloudbroker/grid/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of locations @@ -16,6 +18,10 @@ type ListRequest struct { // Required: false Name string `url:"name,omitempty" json:"name,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -27,6 +33,7 @@ type ListRequest struct { // List gets list of all locations as a ListGrids struct func (g Grid) List(ctx context.Context, req ListRequest) (*ListGrids, error) { + res, err := g.ListRaw(ctx, req) if err != nil { return nil, err @@ -44,6 +51,11 @@ func (g Grid) List(ctx context.Context, req ListRequest) (*ListGrids, error) { // ListRaw gets list of all locations as an array of bytes func (g Grid) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/grid/list" res, err := g.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/grid/remove_custom_backup_path.go b/pkg/cloudbroker/grid/remove_custom_backup_path.go new file mode 100644 index 0000000..40743dc --- /dev/null +++ b/pkg/cloudbroker/grid/remove_custom_backup_path.go @@ -0,0 +1,42 @@ +package grid + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// RemoveCustomBackupPathRequest struct to remove path from the list of custom backup paths +type RemoveCustomBackupPathRequest struct { + // ID of the grid + // Required: true + GID uint64 `url:"gridId" json:"gridId" validate:"required"` + + // Absolute path + // Required: true + Path string `url:"path" json:"path" validate:"required"` +} + +// RemoveCustomBackupPath remove path from the list of custom backup paths +func (g Grid) RemoveCustomBackupPath(ctx context.Context, req RemoveCustomBackupPathRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/grid/removeCustomBackupPath" + + res, err := g.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/grid/rename.go b/pkg/cloudbroker/grid/rename.go index 7f886a5..bae4f67 100644 --- a/pkg/cloudbroker/grid/rename.go +++ b/pkg/cloudbroker/grid/rename.go @@ -16,7 +16,7 @@ type RenameRequest struct { // New name // Required: true - Name string `url:"Name" json:"Name" validate:"required"` + Name string `url:"name" json:"name" validate:"required"` } // Rename renames a grid diff --git a/pkg/cloudbroker/grid/set_password_policy.go b/pkg/cloudbroker/grid/set_password_policy.go new file mode 100644 index 0000000..edf3b26 --- /dev/null +++ b/pkg/cloudbroker/grid/set_password_policy.go @@ -0,0 +1,58 @@ +package grid + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// SetPasswordPolicyRequest struct to set password policy for a grid +type SetPasswordPolicyRequest struct { + // ID of the grid + // Required: true + GID uint64 `url:"gridId" json:"gridId" validate:"required"` + + // Available numbers in the password + // Default value : true + // Required: true + Digits bool `url:"digits" json:"digits"` + + // Available special characters in the password + // Default value : false + // Required: true + SpecialSymbols bool `url:"specialSymbols" json:"specialSymbols"` + + // Number of characters in the password + // Default value : 9 + // Required: true + PasswordLength uint64 `url:"passwordLength" json:"passwordLength" validate:"required"` + + // Capital letters in the password are available + // Default value : true + // Required: true + Uppercase bool `url:"uppercase" json:"uppercase"` +} + +// RemoveCustomBackupPath set set password policy for a grid +func (g Grid) SetPasswordPolicy(ctx context.Context, req SetPasswordPolicyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/grid/setPasswordPolicy" + + res, err := g.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/group/list.go b/pkg/cloudbroker/group/list.go index 6ae1362..c436678 100644 --- a/pkg/cloudbroker/group/list.go +++ b/pkg/cloudbroker/group/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of group instances. @@ -16,6 +18,10 @@ type ListRequest struct { // Required: false User string `url:"user,omitempty" json:"user,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number. // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -31,6 +37,7 @@ type ListRequest struct { // List gets list of group instances as a ListGroups struct func (g Group) List(ctx context.Context, req ListRequest) (*ListGroups, error) { + res, err := g.ListRaw(ctx, req) if err != nil { return nil, err @@ -48,6 +55,11 @@ func (g Group) List(ctx context.Context, req ListRequest) (*ListGroups, error) { // ListRaw gets list of group instances as an array of bytes func (g Group) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/group/list" res, err := g.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/image/computeci_unset.go b/pkg/cloudbroker/image/computeci_unset.go index 3581918..286ab3d 100644 --- a/pkg/cloudbroker/image/computeci_unset.go +++ b/pkg/cloudbroker/image/computeci_unset.go @@ -22,7 +22,7 @@ func (i Image) ComputeCIUnset(ctx context.Context, req ComputeCIUnsetRequest) (b return false, validators.ValidationErrors(validators.GetErrors(err)) } - url := "/cloudbroker/image/сomputeciUnset" + url := "/cloudbroker/image/computeciUnset" res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req) if err != nil { diff --git a/pkg/cloudbroker/image/create_image.go b/pkg/cloudbroker/image/create_image.go index 5ee9315..3d02f41 100644 --- a/pkg/cloudbroker/image/create_image.go +++ b/pkg/cloudbroker/image/create_image.go @@ -27,7 +27,7 @@ type CreateRequest struct { // - bios // - UEFI // Required: true - BootType string `url:"boottype" json:"boottype" validate:"imageBootType"` + BootType string `url:"boottype" json:"boottype" validate:"required,imageBootType"` // Image type // Should be one of: @@ -35,7 +35,14 @@ type CreateRequest struct { // - windows // - or other // Required: true - ImageType string `url:"imagetype" json:"imagetype" validate:"imageType"` + ImageType string `url:"imagetype" json:"imagetype" validate:"required,imageType"` + + // Select a network interface naming pattern for your Linux machine. eth - onboard, ens - pci slot naming + // Should be: + // - eth + // - ens (default value) + // Required: false + NetworkInterfaceNaming string `url:"networkInterfaceNaming,omitempty" json:"networkInterfaceNaming,omitempty" validate:"omitempty,networkInterfaceNaming"` // Does this machine supports hot resize // Required: false @@ -78,7 +85,7 @@ type CreateRequest struct { // List of types of compute suitable for image // Example: [ "KVM_X86" ] - // Required: true + // Required: required Drivers []string `url:"drivers" json:"drivers" validate:"min=1,max=2,imageDrivers"` // Bootable image or not diff --git a/pkg/cloudbroker/image/edit.go b/pkg/cloudbroker/image/edit.go index f7f0bfc..655296d 100644 --- a/pkg/cloudbroker/image/edit.go +++ b/pkg/cloudbroker/image/edit.go @@ -14,6 +14,13 @@ type EditRequest struct { // Required: true ImageID uint64 `url:"imageId" json:"imageId" validate:"required"` + // Select a network interface naming pattern for your Linux machine. eth - onboard, ens - pci slot naming + // Should be: + // - eth + // - ens (default value) + // Required: false + NetworkInterfaceNaming string `url:"networkInterfaceNaming,omitempty" json:"networkInterfaceNaming,omitempty" validate:"omitempty,networkInterfaceNaming"` + // Name for the image // Required: false Name string `url:"name,omitempty" json:"name,omitempty"` diff --git a/pkg/cloudbroker/image/filter.go b/pkg/cloudbroker/image/filter.go index 44295e5..d85504b 100644 --- a/pkg/cloudbroker/image/filter.go +++ b/pkg/cloudbroker/image/filter.go @@ -2,7 +2,7 @@ package image // FilterById returns ListImages with specified ID. func (li ListImages) FilterByID(id uint64) ListImages { - predicate := func(ri RecordImage) bool { + predicate := func(ri ItemImage) bool { return ri.ID == id } @@ -11,7 +11,7 @@ func (li ListImages) FilterByID(id uint64) ListImages { // FilterByName returns ListImages with specified Name. func (li ListImages) FilterByName(name string) ListImages { - predicate := func(ri RecordImage) bool { + predicate := func(ri ItemImage) bool { return ri.Name == name } @@ -20,7 +20,7 @@ func (li ListImages) FilterByName(name string) ListImages { // FilterByStatus returns ListImages with specified Status. func (li ListImages) FilterByStatus(status string) ListImages { - predicate := func(ri RecordImage) bool { + predicate := func(ri ItemImage) bool { return ri.Status == status } @@ -29,7 +29,7 @@ func (li ListImages) FilterByStatus(status string) ListImages { // FilterByTechStatus returns ListImages with specified TechStatus. func (li ListImages) FilterByTechStatus(techStatus string) ListImages { - predicate := func(ri RecordImage) bool { + predicate := func(ri ItemImage) bool { return ri.TechStatus == techStatus } @@ -38,7 +38,7 @@ func (li ListImages) FilterByTechStatus(techStatus string) ListImages { // FilterByBootType returns ListImages with specified BootType. func (li ListImages) FilterByBootType(bootType string) ListImages { - predicate := func(ri RecordImage) bool { + predicate := func(ri ItemImage) bool { return ri.BootType == bootType } @@ -46,7 +46,7 @@ func (li ListImages) FilterByBootType(bootType string) ListImages { } // FilterFunc allows filtering ListImages based on a user-specified predicate. -func (li ListImages) FilterFunc(predicate func(RecordImage) bool) ListImages { +func (li ListImages) FilterFunc(predicate func(ItemImage) bool) ListImages { var result ListImages for _, item := range li.Data { @@ -60,9 +60,9 @@ func (li ListImages) FilterFunc(predicate func(RecordImage) bool) ListImages { // FindOne returns first found RecordImage // If none was found, returns an empty struct. -func (li ListImages) FindOne() RecordImage { +func (li ListImages) FindOne() ItemImage { if len(li.Data) == 0 { - return RecordImage{} + return ItemImage{} } return li.Data[0] diff --git a/pkg/cloudbroker/image/filter_test.go b/pkg/cloudbroker/image/filter_test.go index 8c91556..079bdcb 100644 --- a/pkg/cloudbroker/image/filter_test.go +++ b/pkg/cloudbroker/image/filter_test.go @@ -3,16 +3,9 @@ package image import "testing" var images = ListImages{ - Data: []RecordImage{ + Data: []ItemImage{ { - UNCPath: "", - CKey: "", - Meta: []interface{}{ - "osismodel", - "cloudbroker", - "image", - 1, - }, + UNCPath: "", AccountID: 0, ACL: []ACL{}, Architecture: "X86_64", @@ -55,14 +48,7 @@ var images = ListImages{ Virtual: false, }, { - UNCPath: "", - CKey: "", - Meta: []interface{}{ - "osismodel", - "cloudbroker", - "image", - 1, - }, + UNCPath: "", AccountID: 0, ACL: []ACL{}, Architecture: "X86_64", @@ -105,14 +91,7 @@ var images = ListImages{ Virtual: true, }, { - UNCPath: "", - CKey: "", - Meta: []interface{}{ - "osismodel", - "cloudbroker", - "image", - 1, - }, + UNCPath: "", AccountID: 1, ACL: []ACL{}, Architecture: "X86_64", @@ -202,7 +181,7 @@ func TestFilterByBootType(t *testing.T) { } func TestFilterFunc(t *testing.T) { - actual := images.FilterFunc(func(ri RecordImage) bool { + actual := images.FilterFunc(func(ri ItemImage) bool { return ri.Virtual == true }) diff --git a/pkg/cloudbroker/image/grant_access.go b/pkg/cloudbroker/image/grant_access.go new file mode 100644 index 0000000..ce2971c --- /dev/null +++ b/pkg/cloudbroker/image/grant_access.go @@ -0,0 +1,42 @@ +package image + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// GrantAccessRequest struct to share image with accounts +type GrantAccessRequest struct { + // ID of the image to share + // Required: true + ImageID uint64 `url:"imageId" json:"imageId" validate:"required"` + + // ID of the accounts for share image + // Required: true + AccountIDs []uint64 `url:"accounts" json:"accounts" validate:"required"` +} + +// GrantAccess shares specified image with specified accounts +func (i Image) GrantAccess(ctx context.Context, req GrantAccessRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/image/grantAccess" + + 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/list.go b/pkg/cloudbroker/image/list.go index 7c0e077..0e83852 100644 --- a/pkg/cloudbroker/image/list.go +++ b/pkg/cloudbroker/image/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of available images @@ -56,6 +58,10 @@ type ListRequest struct { // Required: false Bootable bool `url:"bootable,omitempty" json:"bootable,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -67,6 +73,7 @@ type ListRequest struct { // List gets list of information about images as a ListImages struct func (i Image) List(ctx context.Context, req ListRequest) (*ListImages, error) { + res, err := i.ListRaw(ctx, req) if err != nil { return nil, err @@ -84,6 +91,11 @@ func (i Image) List(ctx context.Context, req ListRequest) (*ListImages, error) { // ListRaw gets list of information about images as an array of bytes func (i Image) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/image/list" res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/image/list_stacks.go b/pkg/cloudbroker/image/list_stacks.go index 38b695d..0bf4b3d 100644 --- a/pkg/cloudbroker/image/list_stacks.go +++ b/pkg/cloudbroker/image/list_stacks.go @@ -33,10 +33,15 @@ type ListStacksRequest struct { // Find by type // Required: false Type string `url:"type,omitempty" json:"type,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` } // ListStacks gets list stack by image ID func (i Image) ListStacks(ctx context.Context, req ListStacksRequest) (*ListStacks, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/image/models.go b/pkg/cloudbroker/image/models.go index 14824da..6e72dfa 100644 --- a/pkg/cloudbroker/image/models.go +++ b/pkg/cloudbroker/image/models.go @@ -5,11 +5,128 @@ type RecordImage struct { // UNC path UNCPath string `json:"UNCPath"` - // CKey - CKey string `json:"_ckey"` + // Account ID + AccountID uint64 `json:"accountId"` - // Meta - Meta []interface{} `json:"_meta"` + // Access Control List + ACL ListACL `json:"acl"` + + // Architecture + Architecture string `json:"architecture"` + + // Boot type + BootType string `json:"bootType"` + + // Bootable + Bootable bool `json:"bootable"` + + // CdPresentedTo + CdPresentedTo interface{} `json:"cdPresentedTo"` + + // Compute CI ID + ComputeCIID uint64 `json:"computeciId"` + + // Deleted time + DeletedTime uint64 `json:"deletedTime"` + + // Description + Description string `json:"desc"` + + // Drivers + Drivers []string `json:"drivers"` + + // Enabled + Enabled bool `json:"enabled"` + + // Grid ID + GID uint64 `json:"gid"` + + // GUID + GUID uint64 `json:"guid"` + + // List history + History ListHistory `json:"history"` + + // Hot resize + HotResize bool `json:"hotResize"` + + // ID + ID uint64 `json:"id"` + + // Last modified + LastModified uint64 `json:"lastModified"` + + // Link to + LinkTo uint64 `json:"linkTo"` + + // Milestones + Milestones uint64 `json:"milestones"` + + // Name + Name string `json:"name"` + + // NetworkInterfaceNaming + NetworkInterfaceNaming string `json:"networkInterfaceNaming"` + + // Password + Password string `json:"password"` + + // Pool + Pool string `json:"pool"` + + // Present to + PresentTo []uint64 `json:"presentTo"` + + // Provider name + ProviderName string `json:"provider_name"` + + // Purge attempts + PurgeAttempts uint64 `json:"purgeAttempts"` + + // Reference ID + ReferenceID string `json:"referenceId"` + + // Resource ID + ResID string `json:"resId"` + + // Resource name + ResName string `json:"resName"` + + // Rescue CD + RescueCD bool `json:"rescuecd"` + + // SEP ID + SEPID uint64 `json:"sepId"` + + // List shared with + SharedWith []uint64 `json:"sharedWith"` + + // Size + Size uint64 `json:"size"` + + // Status + Status string `json:"status"` + + // Tech status + TechStatus string `json:"techStatus"` + + // Type + Type string `json:"type"` + + // URL + URL string `json:"url"` + + // Username + Username string `json:"username"` + + // Version + Version string `json:"version"` +} + +// Detailed information about item of images list +type ItemImage struct { + // UNC path + UNCPath string `json:"UNCPath"` // Account ID AccountID uint64 `json:"accountId"` @@ -26,6 +143,9 @@ type RecordImage struct { // Bootable Bootable bool `json:"bootable"` + // CdPresentedTo + CdPresentedTo interface{} `json:"cdPresentedTo"` + // Compute CI ID ComputeCIID uint64 `json:"computeciId"` @@ -68,6 +188,9 @@ type RecordImage struct { // Name Name string `json:"name"` + // NetworkInterfaceNaming + NetworkInterfaceNaming string `json:"networkInterfaceNaming"` + // Password Password string `json:"password"` @@ -129,7 +252,7 @@ type RecordImage struct { // List images type ListImages struct { // Data - Data []RecordImage `json:"data"` + Data []ItemImage `json:"data"` // Entry count EntryCount uint64 `json:"entryCount"` diff --git a/pkg/cloudbroker/image/revoke_access.go b/pkg/cloudbroker/image/revoke_access.go new file mode 100644 index 0000000..741f83e --- /dev/null +++ b/pkg/cloudbroker/image/revoke_access.go @@ -0,0 +1,42 @@ +package image + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// RevokeAccessRequest struct to unshare image with accounts +type RevokeAccessRequest struct { + // ID of the image to unshare + // Required: true + ImageID uint64 `url:"imageId" json:"imageId" validate:"required"` + + // ID of the accounts for unshare image + // Required: true + AccountIDs []uint64 `url:"accounts" json:"accounts" validate:"required"` +} + +// RevokeAccess unshares specified image with specified accounts +func (i Image) RevokeAccess(ctx context.Context, req RevokeAccessRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/image/revokeAccess" + + 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/sync_create_image.go b/pkg/cloudbroker/image/sync_create_image.go index 0c54a6f..e8db3fe 100644 --- a/pkg/cloudbroker/image/sync_create_image.go +++ b/pkg/cloudbroker/image/sync_create_image.go @@ -27,7 +27,7 @@ type SyncCreateRequest struct { // - bios // - UEFI // Required: true - BootType string `url:"boottype" json:"boottype" validate:"imageBootType"` + BootType string `url:"boottype" json:"boottype" validate:"required,imageBootType"` // Image type // Should be one of: @@ -35,7 +35,14 @@ type SyncCreateRequest struct { // - windows // - or other // Required: true - ImageType string `url:"imagetype" json:"imagetype" validate:"imageType"` + ImageType string `url:"imagetype" json:"imagetype" validate:"required,imageType"` + + // Select a network interface naming pattern for your Linux machine. eth - onboard, ens - pci slot naming + // Should be: + // - eth + // - ens (default value) + // Required: false + NetworkInterfaceNaming string `url:"networkInterfaceNaming,omitempty" json:"networkInterfaceNaming,omitempty" validate:"omitempty,networkInterfaceNaming"` // Does this machine supports hot resize // Required: false diff --git a/pkg/cloudbroker/k8ci/access_add.go b/pkg/cloudbroker/k8ci/access_add.go index 499895a..a134f80 100644 --- a/pkg/cloudbroker/k8ci/access_add.go +++ b/pkg/cloudbroker/k8ci/access_add.go @@ -19,7 +19,7 @@ type AccessAddRequest struct { } // Add accountId to sharedWith access list for k8ci. -func (k K8CI) AccessAdd(ctx context.Context, req AccessAddRequest) (string, error) { +func (k K8CI) AccessAdd (ctx context.Context, req AccessAddRequest) (string, error) { err := validators.ValidateRequest(req) if err != nil { return "", validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/k8ci/access_remove.go b/pkg/cloudbroker/k8ci/access_remove.go index 8b2c2c9..c1a675f 100644 --- a/pkg/cloudbroker/k8ci/access_remove.go +++ b/pkg/cloudbroker/k8ci/access_remove.go @@ -19,7 +19,7 @@ type AccessRemoveRequest struct { } // Remove accountId from sharedWith access list for k8ci. -func (k K8CI) AccessRemove(ctx context.Context, req AccessRemoveRequest) (string, error) { +func (k K8CI) AccessRemove (ctx context.Context, req AccessRemoveRequest) (string, error) { err := validators.ValidateRequest(req) if err != nil { return "", validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/k8ci/list.go b/pkg/cloudbroker/k8ci/list.go index 9a7fe1f..538e3fb 100644 --- a/pkg/cloudbroker/k8ci/list.go +++ b/pkg/cloudbroker/k8ci/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list information about images @@ -36,6 +38,10 @@ type ListRequest struct { // Required: false IncludeDisabled bool `url:"includeDisabled,omitempty" json:"includeDisabled,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,7 @@ type ListRequest struct { // List gets list of all k8ci catalog items available to the current user as a ListK8CI struct func (k K8CI) List(ctx context.Context, req ListRequest) (*ListK8CI, error) { + res, err := k.ListRaw(ctx, req) if err != nil { return nil, err @@ -64,6 +71,12 @@ func (k K8CI) List(ctx context.Context, req ListRequest) (*ListK8CI, error) { // ListRaw gets list of all k8ci catalog items available to the current user as an array of bytes func (k K8CI) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/k8ci/list" res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/k8ci/list_deleted.go b/pkg/cloudbroker/k8ci/list_deleted.go index a7261ae..ee66bda 100644 --- a/pkg/cloudbroker/k8ci/list_deleted.go +++ b/pkg/cloudbroker/k8ci/list_deleted.go @@ -4,13 +4,15 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) -// ListDeletedRequest struct to get list information about deleted images +// ListDeletedRequest struct to get list information about deleted k8ci items type ListDeletedRequest struct { // Find by ID // Required: false - ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + ByID uint64 `url:"k8cId,omitempty" json:"k8cId,omitempty"` // Find by name // Required: false @@ -26,7 +28,11 @@ type ListDeletedRequest struct { // Find by network plugin // Required: false - NetworkPlugins string `url:"netPlugins,omitempty" json:"masterDrnetPluginsiver,omitempty"` + NetworkPlugins string `url:"netPlugins,omitempty" json:"netPlugins,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` // Page number // Required: false @@ -39,6 +45,12 @@ type ListDeletedRequest struct { // ListDeleted gets list all deleted k8ci catalog items available to the current user func (k K8CI) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListK8CI, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/k8ci/listDeleted" res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/k8s/create.go b/pkg/cloudbroker/k8s/create.go index bc1650f..8100a18 100644 --- a/pkg/cloudbroker/k8s/create.go +++ b/pkg/cloudbroker/k8s/create.go @@ -8,8 +8,6 @@ import ( "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) -// type Params []string - // CreateRequest struct to create K8S type CreateRequest struct { // Name of kubernetes cluster @@ -29,7 +27,7 @@ type CreateRequest struct { WorkerGroupName string `url:"workerGroupName" json:"workerGroupName" validate:"required,workerGroupName"` // Network plugin - // Must be one of these values: flunnel, weavenet, calico + // Must be one of these values: flannel, weavenet, calico // Required: true NetworkPlugin string `url:"networkPlugin" json:"networkPlugin" validate:"required,networkPlugin"` @@ -113,7 +111,7 @@ type CreateRequest struct { // Custom sysctl values for Load Balancer instance. Applied on boot // Required: false - LbSysctlParams string `url:"lbSysctlParams,omitempty" json:"lbSysctlParams,omitempty"` + LbSysctlParams []map[string]interface{} `url:"lbSysctlParams,omitempty" json:"lbSysctlParams,omitempty"` // Use Highly Available schema for LB deploy // Required: false @@ -168,40 +166,25 @@ type CreateRequest struct { OidcCertificate string `url:"oidcCertificate,omitempty" json:"oidcCertificate,omitempty"` } -// type wrapperCreateRequest struct { -// CreateRequest -// Params []string `url:"lbSysctlParams,omitempty"` -// } +// GetRAM returns RAM values +func (r CreateRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 2) + + res["MasterRAM"] = r.MasterRAM + res["WorkerRAM"] = r.WorkerRAM + + return res +} // Create creates a new kubernetes cluster in the specified resource group func (k K8S) Create(ctx context.Context, req CreateRequest) (string, error) { + err := validators.ValidateRequest(req) if err != nil { return "", validators.ValidationErrors(validators.GetErrors(err)) } - // var params []string - - // if len(req.LbSysctlParams) != 0 { - // params = make([]string, 0, len(req.LbSysctlParams)) - - // for r := range req.LbSysctlParams { - // b, err := json.Marshal(req.LbSysctlParams[r]) - // if err != nil { - // return "", err - // } - - // params = append(params, string(b)) - // } - // } else { - // params = []string{} - // } - - // reqWrapped := wrapperCreateRequest{ - // CreateRequest: req, - // Params: params, - // } - url := "/cloudbroker/k8s/create" res, err := k.client.DecortApiCallMP(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/k8s/list.go b/pkg/cloudbroker/k8s/list.go index cc0682f..a677d84 100644 --- a/pkg/cloudbroker/k8s/list.go +++ b/pkg/cloudbroker/k8s/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list information K8S @@ -44,6 +46,10 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -55,6 +61,7 @@ type ListRequest struct { // List gets list of all kubernetes clusters as a ListK8S struct func (k K8S) List(ctx context.Context, req ListRequest) (*ListK8S, error) { + res, err := k.ListRaw(ctx, req) if err != nil { return nil, err @@ -72,6 +79,12 @@ func (k K8S) List(ctx context.Context, req ListRequest) (*ListK8S, error) { // ListRaw gets list of all kubernetes clusters as an array of bytes func (k K8S) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/k8s/list" res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/k8s/list_deleted.go b/pkg/cloudbroker/k8s/list_deleted.go index fc72264..7e3516c 100644 --- a/pkg/cloudbroker/k8s/list_deleted.go +++ b/pkg/cloudbroker/k8s/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted kubernetes cluster @@ -36,6 +38,10 @@ type ListDeletedRequest struct { // Required: false TechStatus string `url:"techStatus,omitempty" json:"techStatus,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -48,6 +54,11 @@ type ListDeletedRequest struct { // ListDeleted gets all deleted kubernetes clusters func (k K8S) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListK8S, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/k8s/listDeleted" res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/k8s/workers_group_add.go b/pkg/cloudbroker/k8s/workers_group_add.go index d9373a9..6fa5e74 100644 --- a/pkg/cloudbroker/k8s/workers_group_add.go +++ b/pkg/cloudbroker/k8s/workers_group_add.go @@ -64,6 +64,16 @@ type WorkersGroupAddRequest struct { UserData string `url:"userData,omitempty" json:"userData,omitempty"` } +// GetRAM returns RAM field values +func (r WorkersGroupAddRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["WorkerRAM"] = r.WorkerRAM + + return res +} + // WorkersGroupAdd adds workers group to kubernetes cluster func (k K8S) WorkersGroupAdd(ctx context.Context, req WorkersGroupAddRequest) (string, error) { err := validators.ValidateRequest(req) diff --git a/pkg/cloudbroker/kvmppc/create.go b/pkg/cloudbroker/kvmppc/create.go index 9bc0f6d..4c5e564 100644 --- a/pkg/cloudbroker/kvmppc/create.go +++ b/pkg/cloudbroker/kvmppc/create.go @@ -26,6 +26,35 @@ type Interface struct { IPAddr string `url:"ipAddr,omitempty" json:"ipAddr,omitempty"` } +// DataDisk detailed struct for DataDisks field in CreateRequest, CreateBlankRequest and MassCreateRequest +type DataDisk struct { + // Name for disk + // Required: true + DiskName string `url:"diskName" json:"diskName" validate:"required"` + + // Disk size in GB + // Required: true + Size uint64 `url:"size" json:"size" validate:"required"` + + // Storage endpoint provider ID + // By default the same with boot disk + // Required: false + SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"` + + // Pool name + // By default will be chosen automatically + // Required: false + Pool string `url:"pool,omitempty" json:"pool,omitempty"` + + // Optional description + // Required: false + Description string `url:"desc,omitempty" json:"desc,omitempty"` + + // Specify image id for create disk from template + // Required: false + ImageID uint64 `url:"imageId,omitempty" json:"imageId,omitempty"` +} + // CreateRequest struct to create KVM PowerPC VM type CreateRequest struct { // ID of the resource group, which will own this VM @@ -63,6 +92,12 @@ type CreateRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` + // Slice of structs with data disk description. Each disk has parameters: required - diskName, size; optional - sepId, pool, desc and imageId. + // If not specified, compute will be created without disks. + // To create compute without disks, pass initialized empty slice . + // Required: false + DataDisks []DataDisk `url:"-" json:"dataDisks,omitempty" validate:"omitempty,dive"` + // Slice of structs with net interface description. // If not specified, compute will be created with default interface from RG. // To create compute without interfaces, pass initialized empty slice . @@ -98,9 +133,20 @@ type CreateRequest struct { Reason string `url:"reason,omitempty" json:"reason,omitempty"` } +// GetRAM returns RAM field values +func (r CreateRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + type wrapperCreateRequest struct { CreateRequest Interfaces []string `url:"interfaces,omitempty"` + DataDisks []string `url:"dataDisks,omitempty"` } // Create creates KVM PowerPC VM based on specified OS image @@ -127,9 +173,25 @@ func (k KVMPPC) Create(ctx context.Context, req CreateRequest) (uint64, error) { interfaces = []string{"[]"} } + var dataDisks []string + + if req.DataDisks != nil && len(req.DataDisks) != 0 { + dataDisks = make([]string, 0, len(req.DataDisks)) + + for i := range req.DataDisks { + b, err := json.Marshal(req.DataDisks[i]) + if err != nil { + return 0, err + } + + dataDisks = append(dataDisks, string(b)) + } + } + reqWrapped := wrapperCreateRequest{ CreateRequest: req, Interfaces: interfaces, + DataDisks: dataDisks, } url := "/cloudbroker/kvmppc/create" diff --git a/pkg/cloudbroker/kvmppc/create_blank.go b/pkg/cloudbroker/kvmppc/create_blank.go index 545235e..e93e50e 100644 --- a/pkg/cloudbroker/kvmppc/create_blank.go +++ b/pkg/cloudbroker/kvmppc/create_blank.go @@ -41,6 +41,12 @@ type CreateBlankRequest struct { // Required: true Pool string `url:"pool" json:"pool" validate:"required"` + // Slice of structs with data disk description. Each disk has parameters: required - diskName, size; optional - sepId, pool, desc and imageId. + // If not specified, compute will be created without disks. + // To create compute without disks, pass initialized empty slice . + // Required: false + DataDisks []DataDisk `url:"-" json:"dataDisks,omitempty" validate:"omitempty,dive"` + // Slice of structs with net interface description. // If not specified, compute will be created with default interface from RG. // To create compute without interfaces, pass initialized empty slice . @@ -52,9 +58,20 @@ type CreateBlankRequest struct { Description string `url:"desc,omitempty" json:"desc,omitempty"` } +// GetRAM returns RAM field values +func (r CreateBlankRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + type wrapperCreateBlankRequest struct { CreateBlankRequest Interfaces []string `url:"interfaces,omitempty"` + DataDisks []string `url:"dataDisks,omitempty"` } // CreateBlank creates KVM PowerPC VM from scratch @@ -81,9 +98,25 @@ func (k KVMPPC) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64 interfaces = []string{"[]"} } + var dataDisks []string + + if req.DataDisks != nil && len(req.DataDisks) != 0 { + dataDisks = make([]string, 0, len(req.DataDisks)) + + for i := range req.DataDisks { + b, err := json.Marshal(req.DataDisks[i]) + if err != nil { + return 0, err + } + + dataDisks = append(dataDisks, string(b)) + } + } + reqWrapped := wrapperCreateBlankRequest{ CreateBlankRequest: req, Interfaces: interfaces, + DataDisks: dataDisks, } url := "/cloudbroker/kvmppc/createBlank" @@ -99,5 +132,4 @@ func (k KVMPPC) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64 } return result, nil - } diff --git a/pkg/cloudbroker/kvmppc/mass_create.go b/pkg/cloudbroker/kvmppc/mass_create.go index 45ea95b..2375a8a 100644 --- a/pkg/cloudbroker/kvmppc/mass_create.go +++ b/pkg/cloudbroker/kvmppc/mass_create.go @@ -48,6 +48,12 @@ type MassCreateRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` + // Slice of structs with data disk description. Each disk has parameters: required - diskName, size; optional - sepId, pool, desc and imageId. + // If not specified, compute will be created without disks. + // To create compute without disks, pass initialized empty slice . + // Required: false + DataDisks []DataDisk `url:"-" json:"dataDisks,omitempty" validate:"omitempty,dive"` + // Slice of structs with net interface description. // If not specified, compute will be created with default interface from RG. // To create compute without interfaces, pass initialized empty slice. @@ -71,9 +77,20 @@ type MassCreateRequest struct { Reason string `url:"reason,omitempty" json:"reason,omitempty"` } +// GetRAM returns RAM field values +func (r MassCreateRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + type wrapperMassCreateRequest struct { MassCreateRequest Interfaces []string `url:"interfaces,omitempty"` + DataDisks []string `url:"dataDisks,omitempty"` } // MassCreate creates KVM PPC computes based on specified OS image @@ -100,9 +117,25 @@ func (k KVMPPC) MassCreate(ctx context.Context, req MassCreateRequest) ([]uint64 interfaces = []string{"[]"} } + var dataDisks []string + + if req.DataDisks != nil && len(req.DataDisks) != 0 { + dataDisks = make([]string, 0, len(req.DataDisks)) + + for i := range req.DataDisks { + b, err := json.Marshal(req.DataDisks[i]) + if err != nil { + return nil, err + } + + dataDisks = append(dataDisks, string(b)) + } + } + reqWrapped := wrapperMassCreateRequest{ MassCreateRequest: req, Interfaces: interfaces, + DataDisks: dataDisks, } url := "/cloudbroker/kvmppc/massCreate" diff --git a/pkg/cloudbroker/kvmx86/create.go b/pkg/cloudbroker/kvmx86/create.go index eb9c8e0..f97d4b9 100644 --- a/pkg/cloudbroker/kvmx86/create.go +++ b/pkg/cloudbroker/kvmx86/create.go @@ -26,6 +26,35 @@ type Interface struct { IPAddr string `url:"ipAddr,omitempty" json:"ipAddr,omitempty"` } +// DataDisk detailed struct for DataDisks field in CreateRequest, CreateBlankRequest and MassCreateRequest +type DataDisk struct { + // Name for disk + // Required: true + DiskName string `url:"diskName" json:"diskName" validate:"required"` + + // Disk size in GB + // Required: true + Size uint64 `url:"size" json:"size" validate:"required"` + + // Storage endpoint provider ID + // By default the same with boot disk + // Required: false + SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"` + + // Pool name + // By default will be chosen automatically + // Required: false + Pool string `url:"pool,omitempty" json:"pool,omitempty"` + + // Optional description + // Required: false + Description string `url:"desc,omitempty" json:"desc,omitempty"` + + // Specify image id for create disk from template + // Required: false + ImageID uint64 `url:"imageId,omitempty" json:"imageId,omitempty"` +} + // CreateRequest struct to create KVM x86 VM type CreateRequest struct { // ID of the resource group, which will own this VM @@ -63,6 +92,12 @@ type CreateRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` + // Slice of structs with data disk description. Each disk has parameters: required - diskName, size; optional - sepId, pool, desc and imageId. + // If not specified, compute will be created without disks. + // To create compute without disks, pass initialized empty slice . + // Required: false + DataDisks []DataDisk `url:"-" json:"dataDisks,omitempty" validate:"omitempty,dive"` + // Slice of structs with net interface description. // If not specified, compute will be created with default interface from RG. // To create compute without interfaces, pass initialized empty slice . @@ -106,9 +141,20 @@ type CreateRequest struct { Reason string `url:"reason,omitempty" json:"reason,omitempty"` } +// GetRAM returns RAM field values +func (r CreateRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + type wrapperCreateRequest struct { CreateRequest Interfaces []string `url:"interfaces,omitempty"` + DataDisks []string `url:"dataDisks,omitempty"` } // Create creates KVM PowerPC VM based on specified OS image @@ -135,9 +181,25 @@ func (k KVMX86) Create(ctx context.Context, req CreateRequest) (uint64, error) { interfaces = []string{"[]"} } + var dataDisks []string + + if req.DataDisks != nil && len(req.DataDisks) != 0 { + dataDisks = make([]string, 0, len(req.DataDisks)) + + for i := range req.DataDisks { + b, err := json.Marshal(req.DataDisks[i]) + if err != nil { + return 0, err + } + + dataDisks = append(dataDisks, string(b)) + } + } + reqWrapped := wrapperCreateRequest{ CreateRequest: req, Interfaces: interfaces, + DataDisks: dataDisks, } url := "/cloudbroker/kvmx86/create" diff --git a/pkg/cloudbroker/kvmx86/create_blank.go b/pkg/cloudbroker/kvmx86/create_blank.go index 4afcfa7..05fc414 100644 --- a/pkg/cloudbroker/kvmx86/create_blank.go +++ b/pkg/cloudbroker/kvmx86/create_blank.go @@ -41,6 +41,12 @@ type CreateBlankRequest struct { // Required: true Pool string `url:"pool" json:"pool" validate:"required"` + // Slice of structs with data disk description. Each disk has parameters: required - diskName, size; optional - sepId, pool, desc and imageId. + // If not specified, compute will be created without disks. + // To create compute without disks, pass initialized empty slice . + // Required: false + DataDisks []DataDisk `url:"-" json:"dataDisks,omitempty" validate:"omitempty,dive"` + // Slice of structs with net interface description. // If not specified, compute will be created with default interface from RG. // To create compute without interfaces, pass initialized empty slice . @@ -56,9 +62,20 @@ type CreateBlankRequest struct { Driver string `url:"driver,omitempty" json:"driver,omitempty"` } +// GetRAM returns RAM field values +func (r CreateBlankRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + type wrapperCreateBlankRequest struct { CreateBlankRequest Interfaces []string `url:"interfaces,omitempty"` + DataDisks []string `url:"dataDisks,omitempty"` } // CreateBlank creates KVM x86 VM from scratch @@ -85,9 +102,25 @@ func (k KVMX86) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64 interfaces = []string{"[]"} } + var dataDisks []string + + if req.DataDisks != nil && len(req.DataDisks) != 0 { + dataDisks = make([]string, 0, len(req.DataDisks)) + + for i := range req.DataDisks { + b, err := json.Marshal(req.DataDisks[i]) + if err != nil { + return 0, err + } + + dataDisks = append(dataDisks, string(b)) + } + } + reqWrapped := wrapperCreateBlankRequest{ CreateBlankRequest: req, Interfaces: interfaces, + DataDisks: dataDisks, } url := "/cloudbroker/kvmx86/createBlank" diff --git a/pkg/cloudbroker/kvmx86/mass_create.go b/pkg/cloudbroker/kvmx86/mass_create.go index 17390a4..24986a2 100644 --- a/pkg/cloudbroker/kvmx86/mass_create.go +++ b/pkg/cloudbroker/kvmx86/mass_create.go @@ -48,6 +48,12 @@ type MassCreateRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` + // Slice of structs with data disk description. Each disk has parameters: required - diskName, size; optional - sepId, pool, desc and imageId. + // If not specified, compute will be created without disks. + // To create compute without disks, pass initialized empty slice . + // Required: false + DataDisks []DataDisk `url:"-" json:"dataDisks,omitempty" validate:"omitempty,dive"` + // Slice of structs with net interface description. // If not specified, compute will be created with default interface from RG. // To create compute without interfaces, pass initialized empty slice . @@ -71,9 +77,20 @@ type MassCreateRequest struct { Reason string `url:"reason,omitempty" json:"reason,omitempty"` } +// GetRAM returns RAM field values +func (r MassCreateRequest) GetRAM() map[string]uint64 { + + res := make(map[string]uint64, 1) + + res["RAM"] = r.RAM + + return res +} + type wrapperMassCreateRequest struct { MassCreateRequest Interfaces []string `url:"interfaces,omitempty"` + DataDisks []string `url:"dataDisks,omitempty"` } // MassCreate creates KVM x86 computes based on specified OS image @@ -100,9 +117,25 @@ func (k KVMX86) MassCreate(ctx context.Context, req MassCreateRequest) ([]uint64 interfaces = []string{"[]"} } + var dataDisks []string + + if req.DataDisks != nil && len(req.DataDisks) != 0 { + dataDisks = make([]string, 0, len(req.DataDisks)) + + for i := range req.DataDisks { + b, err := json.Marshal(req.DataDisks[i]) + if err != nil { + return nil, err + } + + dataDisks = append(dataDisks, string(b)) + } + } + reqWrapped := wrapperMassCreateRequest{ MassCreateRequest: req, Interfaces: interfaces, + DataDisks: dataDisks, } url := "/cloudbroker/kvmx86/massCreate" diff --git a/pkg/cloudbroker/lb/create.go b/pkg/cloudbroker/lb/create.go index 79bb4c5..cb91c9c 100644 --- a/pkg/cloudbroker/lb/create.go +++ b/pkg/cloudbroker/lb/create.go @@ -10,8 +10,6 @@ import ( "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) -type Params []string - // CreateRequest struct to create load balancer type CreateRequest struct { // ID of the resource group where this load balancer instance will be located @@ -33,7 +31,7 @@ type CreateRequest struct { // Custom sysctl values for Load Balancer instance. Applied on boot // Required: false - SysctlParams Params `url:"-" json:"sysctlParams,omitempty" validate:"omitempty,dive"` + SysctlParams []map[string]interface{} `url:"-" json:"sysctlParams,omitempty" validate:"omitempty,dive"` // Use Highly Available schema for LB deploy // Required: false @@ -68,14 +66,12 @@ func (lb LB) Create(ctx context.Context, req CreateRequest) (uint64, error) { if len(req.SysctlParams) != 0 { params = make([]string, 0, len(req.SysctlParams)) - - for r := range req.SysctlParams { - b, err := json.Marshal(req.SysctlParams[r]) + for _, m := range req.SysctlParams { + encodeStr, err := json.Marshal(m) if err != nil { return 0, err } - - params = append(params, string(b)) + params = append(params, string(encodeStr)) } } else { params = []string{} diff --git a/pkg/cloudbroker/lb/list.go b/pkg/cloudbroker/lb/list.go index 75e0f46..f554e97 100644 --- a/pkg/cloudbroker/lb/list.go +++ b/pkg/cloudbroker/lb/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of load balancers @@ -18,7 +20,7 @@ type ListRequest struct { // Find by account ID // Required: false - AccountID uint64 `url:"accountID,omitempty" json:"accountID,omitempty"` + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` // Find by resource group ID // Required: false @@ -44,6 +46,10 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -55,6 +61,7 @@ type ListRequest struct { // List gets list of all load balancers as a ListLB struct func (lb LB) List(ctx context.Context, req ListRequest) (*ListLB, error) { + res, err := lb.ListRaw(ctx, req) if err != nil { return nil, err @@ -72,6 +79,12 @@ func (lb LB) List(ctx context.Context, req ListRequest) (*ListLB, error) { // ListRaw gets list of all load balancers as an array of bytes func (lb LB) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/lb/list" res, err := lb.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/lb/list_deleted.go b/pkg/cloudbroker/lb/list_deleted.go index d698226..3193dbd 100644 --- a/pkg/cloudbroker/lb/list_deleted.go +++ b/pkg/cloudbroker/lb/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted load balancers @@ -18,7 +20,7 @@ type ListDeletedRequest struct { // Find by account ID // Required: false - AccountID uint64 `url:"accountID,omitempty" json:"accountID,omitempty"` + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` // Find by resource group ID // Required: false @@ -36,6 +38,10 @@ type ListDeletedRequest struct { // Required: false BackIP string `url:"backIp,omitempty" json:"backIp,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,12 @@ type ListDeletedRequest struct { // ListDeleted gets list of deleted load balancers func (lb LB) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListLB, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/lb/listDeleted" res, err := lb.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/lb/models.go b/pkg/cloudbroker/lb/models.go index 5c92501..d91c54b 100644 --- a/pkg/cloudbroker/lb/models.go +++ b/pkg/cloudbroker/lb/models.go @@ -192,6 +192,12 @@ type RecordLB struct { // Image ID ImageID uint64 `json:"imageId"` + // Manager Id + ManagerId uint64 `json:"managerId"` + + // Manager Type + ManagerType string `json:"managerType"` + // Milestones Milestones uint64 `json:"milestones"` @@ -219,6 +225,9 @@ type RecordLB struct { // Tech status TechStatus string `json:"techStatus"` + // User Managed flag + UserManaged bool `json:"userManaged"` + // VINS ID VINSID uint64 `json:"vinsId"` } @@ -276,12 +285,21 @@ type ItemLBList struct { // ID ID uint64 `json:"id"` + // ManagerId + ManagerId uint64 `json:"managerId"` + + // Name + ManagerType string `json:"managerType"` + // Milestones Milestones uint64 `json:"milestones"` // Name Name string `json:"name"` + // PartK8s + PartK8s bool `json:"partK8s"` + // Primary node PrimaryNode Node `json:"primaryNode"` @@ -309,6 +327,9 @@ type ItemLBList struct { // Updated time UpdatedTime uint64 `json:"updatedTime"` + // User managed flag + UserManaged bool `json:"userManaged"` + // VINS ID VINSID uint64 `json:"vinsId"` } diff --git a/pkg/cloudbroker/lb/restart.go b/pkg/cloudbroker/lb/restart.go index 1da718a..37d4fed 100644 --- a/pkg/cloudbroker/lb/restart.go +++ b/pkg/cloudbroker/lb/restart.go @@ -13,6 +13,11 @@ type RestartRequest struct { // ID of the load balancer instance to restart // Required: true LBID uint64 `url:"lbId" json:"lbId" validate:"required"` + + // restart secondary and primary nodes sequentially in HA mode + // Default: true + // Required: false + Safe bool `url:"safe" json:"safe"` } // Restart restarts specified load balancer instance diff --git a/pkg/cloudbroker/lb/updateSysctParams.go b/pkg/cloudbroker/lb/update_sysctl_params.go similarity index 78% rename from pkg/cloudbroker/lb/updateSysctParams.go rename to pkg/cloudbroker/lb/update_sysctl_params.go index 351b89d..8efe836 100644 --- a/pkg/cloudbroker/lb/updateSysctParams.go +++ b/pkg/cloudbroker/lb/update_sysctl_params.go @@ -17,7 +17,7 @@ type UpdateSysctParamsRequest struct { // Custom sysctl values for Load Balancer instance. Applied on boot // Required: true - SysctlParams Params `url:"-" json:"sysctlParams" validate:"required,dive"` + SysctlParams []map[string]interface{} `url:"-" json:"sysctlParams" validate:"required,dive"` } type wrapperUpdateSysctParamsRequest struct { @@ -26,24 +26,21 @@ type wrapperUpdateSysctParamsRequest struct { } // UpdateSysctParams method will create a new load balancer instance -func (l LB) UpdateSysctParams(ctx context.Context, req UpdateSysctParamsRequest) (bool, error) { +func (l LB) UpdateSysctlParams(ctx context.Context, req UpdateSysctParamsRequest) (bool, error) { err := validators.ValidateRequest(req) if err != nil { return false, validators.ValidationErrors(validators.GetErrors(err)) } - var params []string if len(req.SysctlParams) != 0 { params = make([]string, 0, len(req.SysctlParams)) - - for r := range req.SysctlParams { - b, err := json.Marshal(req.SysctlParams[r]) + for _, m := range req.SysctlParams { + encodeStr, err := json.Marshal(m) if err != nil { return false, err } - - params = append(params, string(b)) + params = append(params, string(encodeStr)) } } else { params = []string{} @@ -54,7 +51,7 @@ func (l LB) UpdateSysctParams(ctx context.Context, req UpdateSysctParamsRequest) Params: params, } - url := "/cloudbroker/lb/updateSysctParams" + url := "/cloudbroker/lb/updateSysctlParams" res, err := l.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) if err != nil { diff --git a/pkg/cloudbroker/node.go b/pkg/cloudbroker/node.go new file mode 100644 index 0000000..dd7fdb2 --- /dev/null +++ b/pkg/cloudbroker/node.go @@ -0,0 +1,8 @@ +package cloudbroker + +import "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/node" + +// Accessing the Node method group +func (cb *CloudBroker) Node() *node.Node { + return node.New(cb.client) +} diff --git a/pkg/cloudbroker/node/apply_ipmi_action.go b/pkg/cloudbroker/node/apply_ipmi_action.go new file mode 100644 index 0000000..5408710 --- /dev/null +++ b/pkg/cloudbroker/node/apply_ipmi_action.go @@ -0,0 +1,37 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ApplyIpmiActionRequest struct to apply ipmi action on node +type ApplyIpmiActionRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` + + // Action + // on of actions power_on shutdown force_shutdown reboot + // Required: true + Action string `url:"action" json:"action" validate:"required,action"` +} + +// ApplyIpmiAction applies ipmi action on node +func (n Node) ApplyIpmiAction(ctx context.Context, req ApplyIpmiActionRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/applyIpmiAction" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/node/consumption.go b/pkg/cloudbroker/node/consumption.go new file mode 100644 index 0000000..d0667e6 --- /dev/null +++ b/pkg/cloudbroker/node/consumption.go @@ -0,0 +1,40 @@ +package node + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ConsumptionRequest struct to get node summary by resources and consumption +type ConsumptionRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` +} + +// Consumption gets node summary by resources and consumption +func (n Node) Consumption(ctx context.Context, req ConsumptionRequest) (*ConsumptionInfo, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/consumption" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + info := ConsumptionInfo{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudbroker/node/decommission.go b/pkg/cloudbroker/node/decommission.go new file mode 100644 index 0000000..04bb291 --- /dev/null +++ b/pkg/cloudbroker/node/decommission.go @@ -0,0 +1,37 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DecommissionRequest struct to set node status to DECOMMISSIONED +type DecommissionRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` + + // Force node decommission + // Default: false + // Required: false + Force bool `url:"force" json:"force"` +} + +// Decommission sets node status to DECOMMISSIONED +func (n Node) Decommission(ctx context.Context, req DecommissionRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/decommission" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/node/enable.go b/pkg/cloudbroker/node/enable.go new file mode 100644 index 0000000..315d7e9 --- /dev/null +++ b/pkg/cloudbroker/node/enable.go @@ -0,0 +1,40 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// EnableRequest struct to enable node from maintenance status to enabled +type EnableRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` + + // Message + // Required: false + Message string `url:"message,omitempty" json:"message,omitempty"` + + // Reason + // Required: false + Reason string `url:"reason,omitempty" json:"reason,omitempty"` +} + +// Enable enables node from maintenance status to enabled +func (n Node) Enable(ctx context.Context, req EnableRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/enable" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/node/enable_nodes.go b/pkg/cloudbroker/node/enable_nodes.go new file mode 100644 index 0000000..d3fe2cf --- /dev/null +++ b/pkg/cloudbroker/node/enable_nodes.go @@ -0,0 +1,40 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// EnableNodesRequest struct to enable nodes from maintenance status to enabled +type EnableNodesRequest struct { + // List of Node IDs + // Required: true + NIDs []uint64 `url:"nids" json:"nids" validate:"required"` + + // Message + // Required: false + Message string `url:"message,omitempty" json:"message,omitempty"` + + // Reason + // Required: false + Reason string `url:"reason,omitempty" json:"reason,omitempty"` +} + +// EnableNodes enables nodes from maintenance status to enabled +func (n Node) EnableNodes(ctx context.Context, req EnableNodesRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/enableNodes" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/node/filter.go b/pkg/cloudbroker/node/filter.go new file mode 100644 index 0000000..3de72d3 --- /dev/null +++ b/pkg/cloudbroker/node/filter.go @@ -0,0 +1,99 @@ +package node + +// FilterByID returns ListNodes with specified ID. +func (ln ListNodes) FilterByID(id uint64) ListNodes { + predicate := func(in ItemNode) bool { + return in.ID == id + } + + return ln.FilterFunc(predicate) +} + +// FilterByName returns ListNodes with specified Name. +func (ln ListNodes) FilterByName(name string) ListNodes { + predicate := func(in ItemNode) bool { + return in.Name == name + } + + return ln.FilterFunc(predicate) +} + +// FilterByVersion return ListNodes with specified version. +func (ln ListNodes) FilterByVersion(version string) ListNodes { + predicate := func(in ItemNode) bool { + return in.Version == version + } + + return ln.FilterFunc(predicate) +} + +// FilterByRelease returns ListNodes with specified Release. +func (ln ListNodes) FilterByRelease(release string) ListNodes { + predicate := func(in ItemNode) bool { + return in.Release == release + } + + return ln.FilterFunc(predicate) +} + +// FilterBySepID returns ListNodes with specified Sep ID. +func (ln ListNodes) FilterBySepID(sepId uint64) ListNodes { + predicate := func(in ItemNode) bool { + for _, s := range in.Seps { + if s == sepId { + return true + } + } + return false + } + + return ln.FilterFunc(predicate) +} + +// FilterByRole returns ListNodes with specified Role. +func (ln ListNodes) FilterByRole(role string) ListNodes { + predicate := func(in ItemNode) bool { + for _, r := range in.Roles { + if r == role { + return true + } + } + return false + } + + return ln.FilterFunc(predicate) +} + +// FilterByStatus return ListNodes with specified status. +func (ln ListNodes) FilterByStatus(status string) ListNodes { + predicate := func(in ItemNode) bool { + return in.Status == status + } + + return ln.FilterFunc(predicate) +} + +// FilterFunc allows filtering ListNodes based on a user-specified predicate. +func (ln ListNodes) FilterFunc(predicate func(ItemNode) bool) ListNodes { + var result ListNodes + + for _, item := range ln.Data { + if predicate(item) { + result.Data = append(result.Data, item) + } + } + + result.EntryCount = uint64(len(result.Data)) + + return result +} + +// FindOne returns first found ItemNode. +// If none was found, returns an empty struct. +func (ln ListNodes) FindOne() ItemNode { + if len(ln.Data) == 0 { + return ItemNode{} + } + + return ln.Data[0] +} diff --git a/pkg/cloudbroker/node/filter_test.go b/pkg/cloudbroker/node/filter_test.go new file mode 100644 index 0000000..c01894e --- /dev/null +++ b/pkg/cloudbroker/node/filter_test.go @@ -0,0 +1,155 @@ +package node + +import "testing" + +var nodes = ListNodes{ + Data: []ItemNode{ + { + GID: 212, + GUID: "1", + ID: 1, + Name: "node_1", + Release: "1.7_x86-64", + Roles: []string{"node", "controllernode"}, + Seps: []uint64{1, 2, 3}, + Status: "ENABLED", + Version: "4.0.0", + }, + { + GID: 212, + GUID: "2", + ID: 2, + Name: "node_2", + Release: "", + Roles: []string{"node"}, + Seps: []uint64{4, 5}, + Status: "CREATED", + Version: "3.8.8", + }, + { + GID: 212, + GUID: "3", + ID: 3, + Name: "node_3", + Release: "", + Roles: []string{"physical"}, + Seps: []uint64{1}, + Status: "CREATED", + Version: "3.8.9", + }, + }, + EntryCount: 3, +} + +func TestFilterByID(t *testing.T) { + var testId uint64 = 1 + actual := nodes.FilterByID(testId).FindOne() + + if actual.ID != testId { + t.Fatalf("expected ID %d, found: %d", testId, actual.ID) + } +} + +func TestFilterByName(t *testing.T) { + testName := "node_1" + actual := nodes.FilterByName(testName).FindOne() + + if actual.Name != testName { + t.Fatalf("expected Name '%s', found: %s", testName, actual.Name) + } +} + +func TestFilterByVersion(t *testing.T) { + testVersion := "4.0.0" + actual := nodes.FilterByVersion(testVersion).FindOne() + + if actual.Version != testVersion { + t.Fatalf("expected Version '%s', found: %s", testVersion, actual.Version) + } +} + +func TestFilterByRelease(t *testing.T) { + testRelease := "1.7_x86-64" + actual := nodes.FilterByRelease(testRelease).FindOne() + + if actual.Release != testRelease { + t.Fatalf("expected Release '%s', found: %s", testRelease, actual.Release) + } +} + +func TestFilterBySepID(t *testing.T) { + var testSepId uint64 = 1 + actual := nodes.FilterBySepID(testSepId) + + if len(actual.Data) != 2 { + t.Fatal("expected 2 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + var found bool + + for _, sep := range item.Seps { + if sep == testSepId { + found = true + } + } + + if !found { + t.Fatalf("expected SepID %d, found seps: %v", testSepId, item.Seps) + } + } +} + +func TestFilterByRole(t *testing.T) { + testRole := "node" + actual := nodes.FilterByRole(testRole) + + if len(actual.Data) != 2 { + t.Fatal("expected 2 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + var found bool + + for _, role := range item.Roles { + if role == testRole { + found = true + } + } + + if !found { + t.Fatalf("expected Role %s, found roles: %v", testRole, item.Roles) + } + } +} + +func TestFilterByStatus(t *testing.T) { + testStatus := "CREATED" + actual := nodes.FilterByStatus(testStatus) + + if len(actual.Data) != 2 { + t.Fatal("expected 2 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if item.Status != testStatus { + t.Fatalf("expected Status '%s', found: %s", testStatus, item.Status) + } + } +} + +func TestFilterFunc(t *testing.T) { + actual := nodes.FilterFunc(func(in ItemNode) bool { + return len(in.Roles) > 0 + }) + + if len(actual.Data) < 1 { + t.Fatal("expected 3, found: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if len(item.Roles) < 1 { + t.Fatal("expected Roles to contain at least 1 element, found empty") + } + } +} diff --git a/pkg/cloudbroker/node/get.go b/pkg/cloudbroker/node/get.go new file mode 100644 index 0000000..4a329c0 --- /dev/null +++ b/pkg/cloudbroker/node/get.go @@ -0,0 +1,46 @@ +package node + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// GetRequest struct to get detailed information about node +type GetRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` +} + +// Get gets node summary as a RecordNode struct +func (n Node) Get(ctx context.Context, req GetRequest) (*RecordNode, error) { + res, err := n.GetRaw(ctx, req) + if err != nil { + return nil, err + } + + info := RecordNode{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +// GetRaw gets node summary as an array of bytes +func (n Node) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/get" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudbroker/node/ids.go b/pkg/cloudbroker/node/ids.go new file mode 100644 index 0000000..03ed5ef --- /dev/null +++ b/pkg/cloudbroker/node/ids.go @@ -0,0 +1,10 @@ +package node + +// IDs gets array of Node IDs from ListNodes struct +func (ln ListNodes) IDs() []uint64 { + res := make([]uint64, 0, len(ln.Data)) + for _, n := range ln.Data { + res = append(res, n.ID) + } + return res +} diff --git a/pkg/cloudbroker/node/list.go b/pkg/cloudbroker/node/list.go new file mode 100644 index 0000000..3cca38c --- /dev/null +++ b/pkg/cloudbroker/node/list.go @@ -0,0 +1,84 @@ +package node + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ListRequest struct to get list of nodes +type ListRequest struct { + // Find by node ID + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Find by node name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Find by node version + // Required: false + Version string `url:"version,omitempty" json:"version,omitempty"` + + // Find by node release + // Required: false + Release string `url:"release,omitempty" json:"release,omitempty"` + + // Find by sep ID + // Required: false + SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"` + + // Find by node roles + // Required: false + Role string `url:"role,omitempty" json:"role,omitempty"` + + // Find by node status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + + // 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 all nodes as a ListNodes struct +func (n Node) List(ctx context.Context, req ListRequest) (*ListNodes, error) { + + res, err := n.ListRaw(ctx, req) + if err != nil { + return nil, err + } + + list := ListNodes{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} + +// ListRaw gets list of all nodes as an array of bytes +func (n Node) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/list" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudbroker/node/maintenance.go b/pkg/cloudbroker/node/maintenance.go new file mode 100644 index 0000000..4c1964c --- /dev/null +++ b/pkg/cloudbroker/node/maintenance.go @@ -0,0 +1,50 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// MaintenanceRequest struct to place node in maintenance state +type MaintenanceRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` + + // VM Action + // Default: stop + // Required: false + VMAction string `url:"vmaction,omitempty" json:"vmaction,omitempty" validate:"omitempty,vmaction"` + + // Offline + // Default: false + // Required: false + Offline bool `url:"offline" json:"offline"` + + // VDiskAction + // Required: false + VDiskAction string `url:"vdiskaction,omitempty" json:"vdiskaction,omitempty"` + + // Reason + // Required: false + Reason string `url:"reason,omitempty" json:"reason,omitempty"` +} + +// Maintenance places node in maintenance state +func (n Node) Maintenance(ctx context.Context, req MaintenanceRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/maintenance" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/node/models.go b/pkg/cloudbroker/node/models.go new file mode 100644 index 0000000..9bf0f20 --- /dev/null +++ b/pkg/cloudbroker/node/models.go @@ -0,0 +1,316 @@ +package node + +// Node summary +type RecordNode struct { + // Consumption + Consumption ConsumptionInfo `json:"consumption"` + + // CPU Info + CpuInfo CpuInfo `json:"cpuInfo"` + + // CPU Allocation Ratio + CPUAllocationRatio float64 `json:"cpu_allocation_ratio"` + + // GID + GID uint64 `json:"gid"` + + // Node ID + ID uint64 `json:"id"` + + // IPAddr + IPAddr []string `json:"ipaddr"` + + // Isolated Cpus + IsolatedCpus []interface{} `json:"isolatedCpus"` + + // Name + Name string `json:"name"` + + // NeedReboot + NeedReboot bool `json:"needReboot"` + + // Nic Info + NicInfo ListNicInfo `json:"nicInfo"` + + // NumaTopology + NumaTopology NumaTopologyInfo `json:"numaTopology"` + + // ReservedCPUs + ReservedCPUs []interface{} `json:"reservedCpus"` + + // Roles + Roles []string `json:"roles"` + + // SriovEnabled + SriovEnabled bool `json:"sriovEnabled"` + + // StackID + StackID uint64 `json:"stackId"` + + // Status + Status string `json:"status"` + + // Version + Version string `json:"version"` +} + +// Resource consumption of the node +type ConsumptionInfo struct { + // Consumed resources + Consumed ConsumedResourcesInfo `json:"consumed"` + + // Free resources + Free FreeResourcesInfo `json:"free"` + + // Hostname + Hostname string `json:"hostname"` + + // Reserved resources + Reserved ResourcesInfo `json:"reserved"` + + // Total resources + Total ResourcesInfo `json:"total"` +} + +// Free Resources Info +type FreeResourcesInfo struct { + // RAM + RAM float64 `json:"RAM"` +} + +// Resources Info +type ResourcesInfo struct { + // RAM + RAM uint64 `json:"RAM"` +} + +// Consumed Resources Info +type ConsumedResourcesInfo struct { + // RAM + RAM uint64 `json:"RAM"` + + // Computes + Computes uint64 `json:"computes"` + + // Routers + Routers uint64 `json:"routers"` + + // VCPU + VCPU uint64 `json:"vCPU"` +} + +// Information about node CPU +type CpuInfo struct { + // Clock Speed + ClockSpeed uint64 `json:"clockSpeed"` + + // CoreCount + CoreCount uint64 `json:"coreCount"` + + // PhysCount + PhysCount uint64 `json:"physCount"` +} + +// Main information about node +type ItemNode struct { + // Additional packages + AdditionalPkgs []interface{} `json:"additionalpkgs"` + + // CPU Info + CpuInfo CpuInfo `json:"cpuInfo"` + + // Description + Description string `json:"description"` + + // GID + GID uint64 `json:"gid"` + + // GUID + GUID string `json:"guid"` + + // Hostkey + HostKey string `json:"hostkey"` + + // ID + ID uint64 `json:"id"` + + // IPAddr + IPAddr []string `json:"ipaddr"` + + // Isolated Cpus + IsolatedCpus []interface{} `json:"isolatedCpus"` + + // Last check + LastCheck uint64 `json:"lastcheck"` + + // Machine GUID + MachineGUID string `json:"machineguid"` + + // Mainboard SN + MainboardSN string `json:"mainboardSN"` + + // Memory + Memory uint64 `json:"memory"` + + // Milestones + Milestones uint64 `json:"milestones"` + + // Model + Model string `json:"model"` + + // Name + Name string `json:"name"` + + // NeedReboot + NeedReboot bool `json:"needReboot"` + + // NetAddr + NetAddr ListNetAddr `json:"netaddr"` + + // Network mode + NetworkMode string `json:"networkmode"` + + // Nic Info + NicInfo ListNicInfo `json:"nicInfo"` + + // Node UUID + NodeUUID string `json:"nodeUUID"` + + // NumaTopology + NumaTopology NumaTopologyInfo `json:"numaTopology"` + + // PeerBackup + PeerBackup uint64 `json:"peer_backup"` + + // PeerLog + PeerLog uint64 `json:"peer_log"` + + // PeerStats + PeerStats uint64 `json:"peer_stats"` + + // Pgpus + Pgpus []uint64 `json:"pgpus"` + + // PublicKeys + PublicKeys []string `json:"publickeys"` + + // Release + Release string `json:"release"` + + // ReservedCPUs + ReservedCPUs []interface{} `json:"reservedCpus"` + + // Roles + Roles []string `json:"roles"` + + // Seps + Seps []uint64 `json:"seps"` + + // SerialNum + SerialNum string `json:"serialNum"` + + // SriovEnabled + SriovEnabled bool `json:"sriovEnabled"` + + // StackID + StackID uint64 `json:"stackId"` + + // Status + Status string `json:"status"` + + // Tags + Tags []string `json:"tags"` + + // Type + Type string `json:"type"` + + // Version + Version string `json:"version"` +} + +// Numa Topology Info +type NumaTopologyInfo struct { + // NodeNum + NodeNum uint64 `json:"nodenum"` + + // Nodes + Nodes map[string]NodeInfo `json:"nodes"` +} + +// Node Info from NumaTopologyInfo +type NodeInfo struct { + // CPUList + CPUList []uint64 `json:"cpulist"` + + // Memory + Memory ItemMemory `json:"memory"` +} + +type ItemMemory struct { + // 1G + OneG uint64 `json:"1G"` + + // 2M + TwoM uint64 `json:"2M"` + + // Total + Total uint64 `json:"total"` +} + +type ListNicInfo []ItemNicInfo + +// Item Nic Info +type ItemNicInfo struct { + // Driver + Driver string `json:"driver"` + + // MaxVFS + MaxVFS uint64 `json:"maxvfs"` + + // NumaNode + NumaNode int64 `json:"numaNode"` + + // NumVFS + NumVFS uint64 `json:"numvfs"` + + // OSName + OSName string `json:"osName"` + + // PCISlot + PCISlot string `json:"pciSlot"` + + // VFList + VFList []interface{} `json:"vflist"` +} + +type ListNetAddr []ItemNetAddr + +// Item Net Addr +type ItemNetAddr struct { + // CIDR + CIDR []string `json:"cidr"` + + // Index + Index uint64 `json:"index"` + + // IP + IP []string `json:"ip"` + + // Mac + Mac string `json:"mac"` + + // MTU + MTU uint64 `json:"mtu"` + + // Name + Name string `json:"name"` +} + +// List of nodes +type ListNodes struct { + // Data + Data []ItemNode `json:"data"` + + // Entry count + EntryCount uint64 `json:"entryCount"` +} diff --git a/pkg/cloudbroker/node/node.go b/pkg/cloudbroker/node/node.go new file mode 100644 index 0000000..3091b57 --- /dev/null +++ b/pkg/cloudbroker/node/node.go @@ -0,0 +1,18 @@ +// API Actors for managing node. These actors are the final API for end users to manage nodes +package node + +import ( + "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" +) + +// Structure for creating request to node +type Node struct { + client interfaces.Caller +} + +// Builder for node endpoints +func New(client interfaces.Caller) *Node { + return &Node{ + client: client, + } +} diff --git a/pkg/cloudbroker/node/restrict.go b/pkg/cloudbroker/node/restrict.go new file mode 100644 index 0000000..66fd1b0 --- /dev/null +++ b/pkg/cloudbroker/node/restrict.go @@ -0,0 +1,37 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// RestrictRequest struct to set node status to 'RESTRICTED' +type RestrictRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` + + // Migrate node + // Default: false + // Required: false + Migrate bool `url:"migrate" json:"migrate"` +} + +// Restrict sets node status to 'RESTRICTED' and migrates node if migrate=True +func (n Node) Restrict(ctx context.Context, req RestrictRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/restrict" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/node/serialize.go b/pkg/cloudbroker/node/serialize.go new file mode 100644 index 0000000..91f85dd --- /dev/null +++ b/pkg/cloudbroker/node/serialize.go @@ -0,0 +1,59 @@ +package node + +import ( + "encoding/json" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/serialization" +) + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (ln ListNodes) Serialize(params ...string) (serialization.Serialized, error) { + if len(ln.Data) == 0 { + return []byte{}, nil + } + + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(ln, prefix, indent) + } + + return json.Marshal(ln) +} + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (in ItemNode) Serialize(params ...string) (serialization.Serialized, error) { + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(in, prefix, indent) + } + + return json.Marshal(in) +} + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (rn RecordNode) Serialize(params ...string) (serialization.Serialized, error) { + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(rn, prefix, indent) + } + + return json.Marshal(rn) +} diff --git a/pkg/cloudbroker/node/set_core_isolation.go b/pkg/cloudbroker/node/set_core_isolation.go new file mode 100644 index 0000000..88d77be --- /dev/null +++ b/pkg/cloudbroker/node/set_core_isolation.go @@ -0,0 +1,36 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// SetCoreIsolationRequest struct to isolate selected cores on node boot +type SetCoreIsolationRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` + + // List of core number to isolate + // Required: false + CoreList []uint64 `url:"coreList,omitempty" json:"coreList,omitempty"` +} + +// SetCoreIsolation isolates selected cores on node boot +func (n Node) SetCoreIsolation(ctx context.Context, req SetCoreIsolationRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/setCoreIsolation" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/node/set_huge_pages.go b/pkg/cloudbroker/node/set_huge_pages.go new file mode 100644 index 0000000..e96d15e --- /dev/null +++ b/pkg/cloudbroker/node/set_huge_pages.go @@ -0,0 +1,40 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// SetHugePagesRequest struct to set on-boot Huge Pages configuration +type SetHugePagesRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` + + // Number of 2M hugepages to claim + // Required: true + HugePages2M uint64 `url:"hugepages2M" json:"hugepages2M" validate:"required"` + + // Number of 1G hugepages to claim + // Required: true + HugePages1G uint64 `url:"hugepages1G" json:"hugepages1G" validate:"required"` +} + +// SetHugePages sets on-boot Huge Pages configuration +func (n Node) SetHugePages(ctx context.Context, req SetHugePagesRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/setHugePages" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/node/set_sriov_status.go b/pkg/cloudbroker/node/set_sriov_status.go new file mode 100644 index 0000000..c407c30 --- /dev/null +++ b/pkg/cloudbroker/node/set_sriov_status.go @@ -0,0 +1,36 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// SetSRIOVStatusRequest struct to set Single-root input/output virtualization kernel config on node +type SetSRIOVStatusRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` + + // Enabled + // Required: true + Enabled bool `url:"enabled" json:"enabled" validate:"required"` +} + +// SetSRIOVStatus sets Single-root input/output virtualization kernel config on node +func (n Node) SetSRIOVStatus(ctx context.Context, req SetSRIOVStatusRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/setsriovstatus" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/node/set_vfs_number.go b/pkg/cloudbroker/node/set_vfs_number.go new file mode 100644 index 0000000..2e5b312 --- /dev/null +++ b/pkg/cloudbroker/node/set_vfs_number.go @@ -0,0 +1,44 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// SetVFsNumberRequest struct to set number of VFs for individual NIC on node +type SetVFsNumberRequest struct { + // Node ID + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` + + // PCI address or NIC name + // Required: true + NicID string `url:"nicId" json:"nicId" validate:"required"` + + // Number of VF to assign + // Required: true + VFNum uint64 `url:"vfNum" json:"vfNum" validate:"required"` + + // Trust + // Required: true + Trust bool `url:"trust" json:"trust" validate:"required"` +} + +// SetVFsNumber sets number of VFs for individual NIC on node +func (n Node) SetVFsNumber(ctx context.Context, req SetVFsNumberRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/setVFsNumber" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/node/update.go b/pkg/cloudbroker/node/update.go new file mode 100644 index 0000000..dd66992 --- /dev/null +++ b/pkg/cloudbroker/node/update.go @@ -0,0 +1,32 @@ +package node + +import ( + "context" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// UpdateRequest struct to update node for actual version +type UpdateRequest struct { + // List of Node IDs + // Required: true + NID uint64 `url:"nid" json:"nid" validate:"required"` +} + +// Update updates node for actual version +func (n Node) Update(ctx context.Context, req UpdateRequest) (string, error) { + err := validators.ValidateRequest(req) + if err != nil { + return "", validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/node/update" + + res, err := n.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return "", err + } + + return string(res), nil +} diff --git a/pkg/cloudbroker/pcidevice/list.go b/pkg/cloudbroker/pcidevice/list.go index fc7ea3c..78cc305 100644 --- a/pkg/cloudbroker/pcidevice/list.go +++ b/pkg/cloudbroker/pcidevice/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of pci devices @@ -28,6 +30,10 @@ type ListRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -39,6 +45,7 @@ type ListRequest struct { // List gets list of all pci devices as a ListPCIDevices struct func (p PCIDevice) List(ctx context.Context, req ListRequest) (*ListPCIDevices, error) { + res, err := p.ListRaw(ctx, req) if err != nil { return nil, err @@ -56,6 +63,12 @@ func (p PCIDevice) List(ctx context.Context, req ListRequest) (*ListPCIDevices, // ListRaw gets list of all pci devices as an array of bytes func (p PCIDevice) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/pcidevice/list" res, err := p.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/rg/create.go b/pkg/cloudbroker/rg/create.go index 2f40ff0..949e7b7 100644 --- a/pkg/cloudbroker/rg/create.go +++ b/pkg/cloudbroker/rg/create.go @@ -82,7 +82,12 @@ type CreateRequest struct { // List of strings with pools i.e.: ["sep1_poolName1", "sep2_poolName2"] // Required: false - UniqPools []string `url:"unuqPools,omitempty" json:"unuqPools,omitempty"` + UniqPools []string `url:"uniqPools,omitempty" json:"uniqPools,omitempty"` + + // Advanced compute features, + // one of: hugepages, numa, cpupin, vfnic + // Required: false + ComputeFeatures []string `url:"computeFeatures,omitempty" json:"computeFeatures,omitempty" validate:"omitempty,computeFeatures"` } // Create creates resource group diff --git a/pkg/cloudbroker/rg/list.go b/pkg/cloudbroker/rg/list.go index 46162af..59a5967 100644 --- a/pkg/cloudbroker/rg/list.go +++ b/pkg/cloudbroker/rg/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of resource groups @@ -44,6 +46,10 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -55,6 +61,7 @@ type ListRequest struct { // List gets list of all resource groups the user has access to as a ListRG struct func (r RG) List(ctx context.Context, req ListRequest) (*ListRG, error) { + res, err := r.ListRaw(ctx, req) if err != nil { return nil, err @@ -72,6 +79,12 @@ func (r RG) List(ctx context.Context, req ListRequest) (*ListRG, error) { // ListRaw gets list of all resource groups the user has access to as an array of bytes func (r RG) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/rg/list" res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/rg/list_computes.go b/pkg/cloudbroker/rg/list_computes.go index d76c406..fe69007 100644 --- a/pkg/cloudbroker/rg/list_computes.go +++ b/pkg/cloudbroker/rg/list_computes.go @@ -46,6 +46,10 @@ type ListComputesRequest struct { // Required: false ExtNetID uint64 `url:"extNetId,omitempty" json:"extNetId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -57,6 +61,7 @@ type ListComputesRequest struct { // ListComputes gets list of all compute instances under specified resource group, accessible by the user func (r RG) ListComputes(ctx context.Context, req ListComputesRequest) (*ListComputes, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/rg/list_deleted.go b/pkg/cloudbroker/rg/list_deleted.go index 8fb5884..e6ff357 100644 --- a/pkg/cloudbroker/rg/list_deleted.go +++ b/pkg/cloudbroker/rg/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted resource groups @@ -36,6 +38,10 @@ type ListDeletedRequest struct { // Required: false LockStatus string `url:"lockStatus,omitempty" json:"lockStatus,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -47,6 +53,12 @@ type ListDeletedRequest struct { // ListDeleted gets list all deleted resource groups the user has access to func (r RG) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListRG, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/rg/listDeleted" res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/rg/list_lb.go b/pkg/cloudbroker/rg/list_lb.go index d4e1c20..ea87acd 100644 --- a/pkg/cloudbroker/rg/list_lb.go +++ b/pkg/cloudbroker/rg/list_lb.go @@ -24,7 +24,7 @@ type ListLBRequest struct { // Find by account ID // Required: false - AccountID uint64 `url:"accountID,omitempty" json:"accountID,omitempty"` + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` // Find by tech status // Required: false @@ -42,6 +42,10 @@ type ListLBRequest struct { // Required: false BackIP string `url:"backIp,omitempty" json:"backIp,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -53,6 +57,7 @@ type ListLBRequest struct { // ListLB gets list of all load balancers in the specified resource group, accessible by the user func (r RG) ListLB(ctx context.Context, req ListLBRequest) (*ListLB, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/rg/list_pfw.go b/pkg/cloudbroker/rg/list_pfw.go index 4340b91..2b4dd7c 100644 --- a/pkg/cloudbroker/rg/list_pfw.go +++ b/pkg/cloudbroker/rg/list_pfw.go @@ -17,6 +17,7 @@ type ListPFWRequest struct { // ListPFW gets list of port forward rules for the specified resource group func (r RG) ListPFW(ctx context.Context, req ListPFWRequest) (*ListPFW, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/rg/list_vins.go b/pkg/cloudbroker/rg/list_vins.go index c4c8119..f3419ff 100644 --- a/pkg/cloudbroker/rg/list_vins.go +++ b/pkg/cloudbroker/rg/list_vins.go @@ -30,6 +30,10 @@ type ListVINSRequest struct { // Required: false VINSID uint64 `url:"vinsId,omitempty" json:"vinsId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -41,6 +45,7 @@ type ListVINSRequest struct { // ListVINS gets list of all ViNSes under specified resource group, accessible by the user func (r RG) ListVINS(ctx context.Context, req ListVINSRequest) (*ListVINS, error) { + err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/rg/models.go b/pkg/cloudbroker/rg/models.go index 26d7a9a..698b744 100644 --- a/pkg/cloudbroker/rg/models.go +++ b/pkg/cloudbroker/rg/models.go @@ -145,6 +145,9 @@ type ItemRG struct { // List ACL ACL ListACL `json:"acl"` + // Compute Features + ComputeFeatures []string `json:"computeFeatures"` + // CPU allocation parameter CPUAllocationParameter string `json:"cpu_allocation_parameter"` @@ -394,6 +397,12 @@ type ItemVINS struct { // External IP ExternalIP string `json:"externalIP"` + // Extnet ID + ExtnetId uint64 `json:"extnetId"` + + // Free IPs + FreeIPs uint64 `json:"freeIPs"` + // ID ID uint64 `json:"id"` diff --git a/pkg/cloudbroker/rg/update_compute_features.go b/pkg/cloudbroker/rg/update_compute_features.go new file mode 100644 index 0000000..2a52013 --- /dev/null +++ b/pkg/cloudbroker/rg/update_compute_features.go @@ -0,0 +1,43 @@ +package rg + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// UpdateComputeFeaturesRequest struct to update advanced compute features +type UpdateComputeFeaturesRequest struct { + // Resource group ID + // Required: true + RGID uint64 `url:"rgId" json:"rgId" validate:"required"` + + // Advanced compute features, + // one of: hugepages, numa, cpupin, vfnic + // Required: false + ComputeFeatures []string `url:"computeFeatures,omitempty" json:"computeFeatures,omitempty" validate:"omitempty,computeFeatures"` +} + +// UpdateComputeFeatures updates advanced compute features +func (r RG) UpdateComputeFeatures(ctx context.Context, req UpdateComputeFeaturesRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/rg/updateComputeFeatures" + + 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/sep/add_pool.go b/pkg/cloudbroker/sep/add_pool.go new file mode 100644 index 0000000..9a67788 --- /dev/null +++ b/pkg/cloudbroker/sep/add_pool.go @@ -0,0 +1,47 @@ +package sep + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// AddPoolRequest struct to add pool to storage endpoint (SEP) +type AddPoolRequest struct { + // ID of SEP to add new pool + // Required: true + SEPID uint64 `url:"sep_id" json:"sep_id" validate:"required"` + + // method Async/Sync + // Default: true + // Required: false + Sync bool `url:"sync" json:"sync"` + + // Pool structure which contains fields such as "name", "types", "accessAccountIds", "accessResGroupIds" + // Required: true + Pool string `url:"pool" json:"pool" validate:"required"` +} + +// AddPool adds pool to SEP +func (s SEP) AddPool(ctx context.Context, req AddPoolRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/sep/addPool" + + res, err := s.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/sep/create.go b/pkg/cloudbroker/sep/create.go index 17e77a1..9101256 100644 --- a/pkg/cloudbroker/sep/create.go +++ b/pkg/cloudbroker/sep/create.go @@ -22,14 +22,14 @@ type CreateRequest struct { // Required: true SEPType string `url:"sep_type" json:"sep_type" validate:"required"` + // SEP config + // Required: true + Config string `url:"config" json:"config" validate:"required"` + // Description // Required: false Description string `url:"description,omitempty" json:"description,omitempty"` - // SEP config - // Required: false - Config string `url:"config,omitempty" json:"config,omitempty"` - // List of provider node IDs // Required: false ProviderNIDs []uint64 `url:"provider_nids,omitempty" json:"provider_nids,omitempty"` diff --git a/pkg/cloudbroker/sep/del_pool.go b/pkg/cloudbroker/sep/del_pool.go new file mode 100644 index 0000000..ce8744f --- /dev/null +++ b/pkg/cloudbroker/sep/del_pool.go @@ -0,0 +1,42 @@ +package sep + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DelPoolRequest struct to delete pool from storage endpoint (SEP) +type DelPoolRequest struct { + // ID of SEP to delete pool + // Required: true + SEPID uint64 `url:"sep_id" json:"sep_id" validate:"required"` + + // Name of pool to delete + // Required: true + PoolName string `url:"pool_name" json:"pool_name" validate:"required"` +} + +// DelPool deletes pool from SEP +func (s SEP) DelPool(ctx context.Context, req DelPoolRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/sep/delPool" + + res, err := s.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/sep/list.go b/pkg/cloudbroker/sep/list.go index 9b105a8..4b87c2b 100644 --- a/pkg/cloudbroker/sep/list.go +++ b/pkg/cloudbroker/sep/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of SEPs @@ -18,7 +20,7 @@ type ListRequest struct { // Find by gId // Required: false - GID uint64 `url:"gId,omitempty" json:"gId,omitempty"` + GID uint64 `url:"gid,omitempty" json:"gid,omitempty"` // Find by sep type // Required: false @@ -36,6 +38,10 @@ type ListRequest struct { // Required: false ConsumedBy uint64 `url:"consumedBy,omitempty" json:"consumedBy,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page size // Required: false Size uint64 `url:"size,omitempty" json:"size,omitempty"` @@ -47,6 +53,7 @@ type ListRequest struct { // List gets list of SEPs as a ListSEP struct func (s SEP) List(ctx context.Context, req ListRequest) (*ListSEP, error) { + res, err := s.ListRaw(ctx, req) if err != nil { return nil, err @@ -64,6 +71,12 @@ func (s SEP) List(ctx context.Context, req ListRequest) (*ListSEP, error) { // ListRaw gets list of SEPs as an array of bytes func (s SEP) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/sep/list" res, err := s.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/stack/get_logical_cores_count.go b/pkg/cloudbroker/stack/get_logical_cores_count.go new file mode 100644 index 0000000..c1a02ad --- /dev/null +++ b/pkg/cloudbroker/stack/get_logical_cores_count.go @@ -0,0 +1,38 @@ +package stack + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// GetLogicalCoresCountRequest struct to get logical cores count by stack +type GetLogicalCoresCountRequest struct { + // Stack ID + // Required: true + StackId uint64 `url:"stackId" json:"stackId" validate:"required"` +} + +// GetLogicalCoresCount get logical cores count by stack +func (i Stack) GetLogicalCoresCount(ctx context.Context, req GetLogicalCoresCountRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/stack/getLogicalCoresCount" + + res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, 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/stack/list.go b/pkg/cloudbroker/stack/list.go index 5842f2f..fd06a3c 100644 --- a/pkg/cloudbroker/stack/list.go +++ b/pkg/cloudbroker/stack/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of stacks @@ -24,6 +26,10 @@ type ListRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -35,6 +41,7 @@ type ListRequest struct { // List gets list of stacks as a ListStacks struct func (i Stack) List(ctx context.Context, req ListRequest) (*ListStacks, error) { + res, err := i.ListRaw(ctx, req) if err != nil { return nil, err @@ -52,6 +59,12 @@ func (i Stack) List(ctx context.Context, req ListRequest) (*ListStacks, error) { // ListRaw gets list of stacks as an array of bytes func (i Stack) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/stack/list" res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/stack/set_cpu_allocation_ratio.go b/pkg/cloudbroker/stack/set_cpu_allocation_ratio.go new file mode 100644 index 0000000..e23e494 --- /dev/null +++ b/pkg/cloudbroker/stack/set_cpu_allocation_ratio.go @@ -0,0 +1,44 @@ +package stack + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// SetCpuAllocationRatioRequest struct to set CPU allocation ratio +type SetCpuAllocationRatioRequest struct { + // Stack ID + // Required: true + StackId uint64 `url:"stackId" json:"stackId" validate:"required"` + + // Allocation ratio (zero or positive value) + // Required: true + Ratio float64 `url:"ratio" json:"ratio"` +} + +// SetCpuAllocationRatio set CPU allocation ratio +func (i Stack) SetCpuAllocationRatio(ctx context.Context, req SetCpuAllocationRatioRequest) (*InfoStack, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/stack/setCpuAllocationRatio" + + res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + info := InfoStack{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudbroker/stack/set_mem_allocation_ratio.go b/pkg/cloudbroker/stack/set_mem_allocation_ratio.go new file mode 100644 index 0000000..5e6eabf --- /dev/null +++ b/pkg/cloudbroker/stack/set_mem_allocation_ratio.go @@ -0,0 +1,44 @@ +package stack + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// SetMemAllocationRatioRequest struct to set memory allocation ratio +type SetMemAllocationRatioRequest struct { + // Stack ID + // Required: true + StackId uint64 `url:"stackId" json:"stackId" validate:"required"` + + // Allocation ratio (zero or positive value) + // Required: true + Ratio float64 `url:"ratio" json:"ratio"` +} + +// SetMemAllocationRatio set memory allocation ratio +func (i Stack) SetMemAllocationRatio(ctx context.Context, req SetMemAllocationRatioRequest) (*InfoStack, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/stack/setMemAllocationRatio" + + res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + info := InfoStack{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudbroker/tasks/list.go b/pkg/cloudbroker/tasks/list.go index f7f77b6..781c079 100644 --- a/pkg/cloudbroker/tasks/list.go +++ b/pkg/cloudbroker/tasks/list.go @@ -4,21 +4,51 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of audits type ListRequest struct { + // Find by guId + // Required: false + TaskID string `url:"taskId,omitempty" json:"taskId,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Find by completed True or False + // Default: false + // Required: false + Completed bool `url:"completed" json:"completed"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + + // Find all tasks after point in time (unixtime) + // Required: false + UpdateTimeAt uint64 `url:"page,updateTimeAt" json:"updateTimeAt,omitempty"` + + // Find all tasks before point in time (unixtime) + // Required: false + UpdateTimeTo uint64 `url:"page,updateTimeTo" json:"updateTimeTo,omitempty"` + // Page number + // Default: 0 // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` // Page size + // Default: 0 // Required: false Size uint64 `url:"size,omitempty" json:"size,omitempty"` } // List gets list of user API task with status PROCESSING as a ListTasks struct func (t Tasks) List(ctx context.Context, req ListRequest) (*ListTasks, error) { + res, err := t.ListRaw(ctx, req) if err != nil { return nil, err @@ -36,6 +66,12 @@ func (t Tasks) List(ctx context.Context, req ListRequest) (*ListTasks, error) { // ListRaw gets list of user API task with status PROCESSING as an array of bytes func (t Tasks) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/tasks/list" res, err := t.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/tasks/models.go b/pkg/cloudbroker/tasks/models.go index d4d0e84..f2cbd13 100644 --- a/pkg/cloudbroker/tasks/models.go +++ b/pkg/cloudbroker/tasks/models.go @@ -1,46 +1,13 @@ package tasks import ( - "encoding/json" + "errors" "fmt" - "strconv" ) -// Global variable for converting field to desired data type -type InfoResult int - -// Method for convert field -func (r *InfoResult) UnmarshalJSON(b []byte) error { - if b[0] == '"' { - b := b[1 : len(b)-1] - if len(b) == 0 { - *r = 0 - return nil - } - n, err := strconv.Atoi(string(b)) - if err != nil { - return err - } - *r = InfoResult(n) - } else if b[0] == '[' { - res := []interface{}{} - if err := json.Unmarshal(b, &res); err != nil { - return err - } - if n, ok := res[0].(float64); ok { - *r = InfoResult(n) - } else { - return fmt.Errorf("could not unmarshal %v into int", res[0]) - } - } else { - n, err := strconv.Atoi(string(b)) - if err != nil { - return err - } - *r = InfoResult(n) - } - - return nil +// Result structure of the task to provide methods +type Result struct { + Result interface{} `json:"result"` } // Detailed information about task @@ -61,11 +28,14 @@ type ItemTask struct { // Error Error string `json:"error"` + // GUID + GUID string `json:"guid"` + // List of logs Log []string `json:"log"` // Final result - Result InfoResult `json:"result"` + Result // Stage Stage string `json:"stage"` @@ -76,6 +46,9 @@ type ItemTask struct { // Update time UpdateTime uint64 `json:"updateTime"` + // Updated by + UpdatedBy string `json:"updatedBy"` + // Updated time UpdatedTime uint64 `json:"updatedTime"` } @@ -88,3 +61,90 @@ type ListTasks struct { // Entry count EntryCount uint64 `json:"entryCount"` } + +// ID returns ID of cluster or WG or any other resource successfully created as a Result of the task. +// It returns error if Result does not contain any resource ID. +func (r Result) ID() (int, error) { + // check id from cluster - it comes as slice, like [1234, "cluster-name"] + slice, ok := r.Result.([]interface{}) + if ok { + if len(slice) == 0 { + return 0, fmt.Errorf("could not get ID from empty slice") + } + + idFloat64, ok := slice[0].(float64) + if !ok { + return 0, fmt.Errorf("could not get ID from first slice element (%v)", slice[0]) + } + + return int(idFloat64), nil + } + + // check id from other resources - it comes as id + idFloat64, ok := r.Result.(float64) + if ok { + return int(idFloat64), nil + } + + return 0, errors.New("could not get ID because result is neither slice nor number (%v)") +} + +// Name returns name of cluster or wg successfully created as a result of the task. +// It returns error if Result does not contain k8s name. +func (r Result) Name() (string, error) { + slice, ok := r.Result.([]interface{}) + if !ok { + return "", fmt.Errorf("could not convert Result (%v) to slice", r.Result) + } + + if len(slice) < 2 { + return "", fmt.Errorf("could not get name from second slice element") + } + + var name string + name, ok = slice[1].(string) + if !ok { + return "", fmt.Errorf("could not get name from second slice element (%v)", slice[1]) + } + + return name, nil +} + +// ToMaps converts Result to a slice of maps containing back-up information as a result of the task. +// It returns error if Result does not contain back-up information. +func (r Result) ToMaps() ([]map[string]interface{}, error) { + slice, ok := r.Result.([]interface{}) + if !ok { + return nil, fmt.Errorf("could not convert Result (%v) to slice", r.Result) + } + + if len(slice) == 0 { + return nil, fmt.Errorf("could not get maps from empty slice") + } + + result := make([]map[string]interface{}, 0, len(slice)) + for _, s := range slice { + elem, ok := s.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("could not get map[string]interface{} from slice element (%v)", s) + } + result = append(result, elem) + } + + return result, nil +} + +// ToString converts Result to non-empty string. +// It returns error if Result is not a string or is an empty string. +func (r Result) ToString() (string, error) { + status, ok := r.Result.(string) + if !ok { + return "", fmt.Errorf("could not convert Result (%v) to string", r.Result) + } + + if status == "" { + return "", fmt.Errorf("info contains empty string") + } + + return status, nil +} diff --git a/pkg/cloudbroker/user/get_audit.go b/pkg/cloudbroker/user/get_audit.go index b30a931..d3f3bc9 100644 --- a/pkg/cloudbroker/user/get_audit.go +++ b/pkg/cloudbroker/user/get_audit.go @@ -12,6 +12,22 @@ type GetAuditRequest struct { // Required: false Username string `url:"username,omitempty" json:"username,omitempty"` + // Find by api call. + // Required: false + Call string `url:"call,omitempty" json:"call,omitempty"` + + // Find by HTTP status code + // Required: false + StatusCode uint64 `url:"statuscode,omitempty" json:"statuscode,omitempty"` + + // Find all audits after point in time (unixtime) + // Required: false + TimestampAt uint64 `url:"timestampAt,omitempty" json:"timestampAt,omitempty"` + + // Find all audits before point in time (unixtime) + // Required: false + TimestampTo uint64 `url:"timestampTo,omitempty" json:"timestampTo,omitempty"` + // Page number. // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -27,14 +43,14 @@ func (u User) GetAudit(ctx context.Context, req GetAuditRequest) (ListAudits, er res, err := u.client.DecortApiCall(ctx, http.MethodPost, url, req) if err != nil { - return nil, err + return ListAudits{}, err } list := ListAudits{} err = json.Unmarshal(res, &list) if err != nil { - return nil, err + return ListAudits{}, err } return list, nil diff --git a/pkg/cloudbroker/user/list.go b/pkg/cloudbroker/user/list.go index 2fc96b9..30ff0e2 100644 --- a/pkg/cloudbroker/user/list.go +++ b/pkg/cloudbroker/user/list.go @@ -4,13 +4,15 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get all non deleted user instances. type ListRequest struct { // Find by ID. // Required: false - ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + ByID string `url:"by_id,omitempty" json:"by_id,omitempty"` // Find by active. True or False. // Required: false @@ -20,6 +22,10 @@ type ListRequest struct { // Required: false ServiceAccount bool `url:"serviceaccount,omitempty" json:"serviceaccount,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number. // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -31,6 +37,7 @@ type ListRequest struct { // List gets all non deleted user instances as a ListUsers struct func (u User) List(ctx context.Context, req ListRequest) (*ListUsers, error) { + res, err := u.ListRaw(ctx, req) if err != nil { return nil, err @@ -48,6 +55,12 @@ func (u User) List(ctx context.Context, req ListRequest) (*ListUsers, error) { // ListRaw gets all non deleted user instances as an array of bytes func (u User) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/user/list" res, err := u.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/user/models.go b/pkg/cloudbroker/user/models.go index 34a0e42..940463a 100644 --- a/pkg/cloudbroker/user/models.go +++ b/pkg/cloudbroker/user/models.go @@ -13,7 +13,7 @@ type ItemUser struct { Active bool `json:"active"` // APIAccess - APIAccess []uint64 `json:"apiaccess"` + APIAccess map[string]string `json:"apiaccess"` // AuthKey AuthKey string `json:"authkey"` @@ -52,7 +52,7 @@ type ItemUser struct { Mobile []interface{} `json:"mobile"` // Password - Password string `json:"password"` + Password string `json:"passwd"` // Protected Protected bool `json:"protected"` @@ -110,7 +110,13 @@ type ItemAudit struct { Time float64 `json:"Time"` } -type ListAudits []ItemAudit +type ListAudits struct { + // Data + Data []ItemAudit `json:"data"` + + // Entry count + EntryCount uint64 `json:"entryCount"` +} type ResponseTime float64 diff --git a/pkg/cloudbroker/vfpool.go b/pkg/cloudbroker/vfpool.go new file mode 100644 index 0000000..be8d98a --- /dev/null +++ b/pkg/cloudbroker/vfpool.go @@ -0,0 +1,8 @@ +package cloudbroker + +import "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/vfpool" + +// Accessing the VFPool method group +func (cb *CloudBroker) VFPool() *vfpool.VFPool { + return vfpool.New(cb.client) +} diff --git a/pkg/cloudbroker/vfpool/create.go b/pkg/cloudbroker/vfpool/create.go new file mode 100644 index 0000000..a3be101 --- /dev/null +++ b/pkg/cloudbroker/vfpool/create.go @@ -0,0 +1,97 @@ +package vfpool + +import ( + "context" + "encoding/json" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// CreateRequest struct to create vfpool device +type CreateRequest struct { + // Name of device + // Required: true + Name string `url:"name" json:"name" validate:"required"` + + // Description + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` + + // Name of device + // Required: false + Config []Config `url:"-" json:"config,omitempty" validate:"omitempty,dive"` + + // List of Account IDs + // Required: false + AccountAccess []uint64 `url:"accountAccess,omitempty" json:"accountAccess,omitempty"` + + // List of RG IDs + // Required: false + RGAccess []uint64 `url:"rgAccess,omitempty" json:"rgAccess,omitempty"` +} + +// Config struct for CreateRequest +type Config struct { + // Node ID + // Required: true + NodeID uint64 `url:"nodeId" json:"nodeId" validation:"required"` + + // NicName + // Required: true + NicName string `url:"nicName" json:"nicName" validation:"required"` + + // VF IDs + // Required: true + VFIDs []uint64 `url:"vfIds" json:"vfIds" validation:"required"` +} + +type wrapperCreateRequest struct { + CreateRequest + Config []string `url:"config,omitempty"` +} + +// Create creates vfpool device +func (v VFPool) Create(ctx context.Context, req CreateRequest) (uint64, error) { + err := validators.ValidateRequest(req) + if err != nil { + return 0, validators.ValidationErrors(validators.GetErrors(err)) + } + + var config []string + + if len(req.Config) != 0 { + config = make([]string, 0, len(req.Config)) + + for c := range req.Config { + b, err := json.Marshal(req.Config[c]) + if err != nil { + return 0, err + } + + config = append(config, string(b)) + } + } else { + config = []string{} + } + + reqWrapped := wrapperCreateRequest{ + CreateRequest: req, + Config: config, + } + + url := "/cloudbroker/vfpool/create" + + res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) + 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/vfpool/delete.go b/pkg/cloudbroker/vfpool/delete.go new file mode 100644 index 0000000..8215593 --- /dev/null +++ b/pkg/cloudbroker/vfpool/delete.go @@ -0,0 +1,38 @@ +package vfpool + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DeleteRequest struct to delete vfpool device +type DeleteRequest struct { + // VFPool device ID + // Required: true + VFPoolID uint64 `url:"id" json:"id" validate:"required"` +} + +// Delete deletes vfpool device +func (v VFPool) Delete(ctx context.Context, req DeleteRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/vfpool/delete" + + 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/vfpool/disable.go b/pkg/cloudbroker/vfpool/disable.go new file mode 100644 index 0000000..13f40e8 --- /dev/null +++ b/pkg/cloudbroker/vfpool/disable.go @@ -0,0 +1,38 @@ +package vfpool + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DisableRequest struct to disable vfpool device +type DisableRequest struct { + // VFPool device ID + // Required: true + VFPoolID uint64 `url:"id" json:"id" validate:"required"` +} + +// Disable disables vfpool device +func (v VFPool) Disable(ctx context.Context, req DisableRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/vfpool/disable" + + 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/vfpool/enable.go b/pkg/cloudbroker/vfpool/enable.go new file mode 100644 index 0000000..9ee1ffb --- /dev/null +++ b/pkg/cloudbroker/vfpool/enable.go @@ -0,0 +1,38 @@ +package vfpool + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// EnableRequest struct to enable vfpool device +type EnableRequest struct { + // VFPool device ID + // Required: true + VFPoolID uint64 `url:"id" json:"id" validate:"required"` +} + +// Enable enables vfpool device +func (v VFPool) Enable(ctx context.Context, req EnableRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/vfpool/enable" + + 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/vfpool/filter.go b/pkg/cloudbroker/vfpool/filter.go new file mode 100644 index 0000000..78cbbf3 --- /dev/null +++ b/pkg/cloudbroker/vfpool/filter.go @@ -0,0 +1,99 @@ +package vfpool + +// FilterByID returns ListVFPool with specified ID. +func (lvfp ListVFPool) FilterByID(id uint64) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + return ivfp.ID == id + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByGID returns ListVFPool with specified GID. +func (lvfp ListVFPool) FilterByGID(gid uint64) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + return ivfp.GID == gid + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByName returns ListVFPool with specified Name. +func (lvfp ListVFPool) FilterByName(name string) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + return ivfp.Name == name + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByDescription returns ListVFPool with specified Description. +func (lvfp ListVFPool) FilterByDescription(description string) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + return ivfp.Description == description + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByStatus returns ListVFPool with specified Status. +func (lvfp ListVFPool) FilterByStatus(status string) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + return ivfp.Status == status + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByAccountAccess returns ListVFPool with specified AccountAccess. +func (lvfp ListVFPool) FilterByAccountAccess(accountAccess uint64) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + for _, i := range ivfp.AccountAccess { + if i == accountAccess { + return true + } + } + return false + } + + return lvfp.FilterFunc(predicate) +} + +// FilterByRGAccess returns ListVFPool with specified RGAccess. +func (lvfp ListVFPool) FilterByRGAccess(rgAccess uint64) ListVFPool { + predicate := func(ivfp ItemVFPool) bool { + for _, i := range ivfp.RGAccess { + if i == rgAccess { + return true + } + } + return false + } + + return lvfp.FilterFunc(predicate) +} + +// FilterFunc allows filtering ListVFPool based on a user-specified predicate. +func (lvfp ListVFPool) FilterFunc(predicate func(ItemVFPool) bool) ListVFPool { + var result ListVFPool + + for _, item := range lvfp.Data { + if predicate(item) { + result.Data = append(result.Data, item) + } + } + + result.EntryCount = uint64(len(result.Data)) + + return result +} + +// FindOne returns first found ItemVFPool +// If none was found, returns an empty struct. +func (lvfp ListVFPool) FindOne() ItemVFPool { + if lvfp.EntryCount == 0 { + return ItemVFPool{} + } + + return lvfp.Data[0] +} diff --git a/pkg/cloudbroker/vfpool/filter_test.go b/pkg/cloudbroker/vfpool/filter_test.go new file mode 100644 index 0000000..66d78a3 --- /dev/null +++ b/pkg/cloudbroker/vfpool/filter_test.go @@ -0,0 +1,138 @@ +package vfpool + +import "testing" + +var vfpools = ListVFPool{ + Data: []ItemVFPool{ + { + AccountAccess: []uint64{1, 2}, + Description: "descr", + GID: 1, + ID: 1, + Name: "name", + RGAccess: []uint64{3, 4}, + Status: "ENABLED", + }, + { + AccountAccess: []uint64{}, + Description: "", + GID: 2, + ID: 2, + Name: "name2", + RGAccess: []uint64{}, + Status: "DISABLED", + }, + { + AccountAccess: []uint64{7, 8}, + Description: "", + GID: 215, + ID: 3, + Name: "name3", + RGAccess: []uint64{5, 6}, + Status: "DISABLED", + }, + }, +} + +func TestFilterByID(t *testing.T) { + actual := vfpools.FilterByID(1).FindOne() + + if actual.ID != 1 { + t.Fatal("expected ID 1, found: ", actual.ID) + } +} + +func TestFilterByGID(t *testing.T) { + var gid uint64 = 1 + actual := vfpools.FilterByGID(gid).FindOne() + + if actual.GID != gid { + t.Fatal("expected ", gid, " found: ", actual.GID) + } +} + +func TestFilterByName(t *testing.T) { + name := "name" + actual := vfpools.FilterByName(name).FindOne() + + if actual.Name != name { + t.Fatal("expected ", name, " found: ", actual.Name) + } +} + +func TestFilterByDescription(t *testing.T) { + description := "descr" + actual := vfpools.FilterByDescription(description).FindOne() + + if actual.Description != description { + t.Fatal("expected ", description, " found: ", actual.Description) + } +} + +func TestFilterByStatus(t *testing.T) { + actual := vfpools.FilterByStatus("ENABLED") + + if len(actual.Data) != 1 { + t.Fatal("expected 1 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if item.Status != "ENABLED" { + t.Fatal("expected Status 'ENABLED', found: ", item.Status) + } + } +} + +func TestFilterByAccountAccess(t *testing.T) { + var account uint64 = 1 + actual := vfpools.FilterByAccountAccess(account) + + if len(actual.Data) != 1 { + t.Fatal("expected 1 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + var found bool + for _, a := range item.AccountAccess { + if a == account { + found = true + } + } + + if !found { + t.Fatalf("expected account access %d, found: %v", account, item.AccountAccess) + } + } +} + +func TestFilterByRGAccess(t *testing.T) { + var rg uint64 = 3 + actual := vfpools.FilterByRGAccess(rg) + + if len(actual.Data) != 1 { + t.Fatal("expected 1 found, actual: ", len(actual.Data)) + } + + for _, item := range actual.Data { + var found bool + for _, r := range item.RGAccess { + if r == rg { + found = true + } + } + + if !found { + t.Fatalf("expected account access %d, found: %v", rg, item.RGAccess) + } + } +} + +func TestFilterFunc(t *testing.T) { + actual := vfpools.FilterFunc(func(ivfpool ItemVFPool) bool { + return ivfpool.GID == ivfpool.ID + }) + + if len(actual.Data) != 2 { + t.Fatal("expected 2 elements, found: ", len(actual.Data)) + } +} diff --git a/pkg/cloudbroker/vfpool/get.go b/pkg/cloudbroker/vfpool/get.go new file mode 100644 index 0000000..5fa9036 --- /dev/null +++ b/pkg/cloudbroker/vfpool/get.go @@ -0,0 +1,46 @@ +package vfpool + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// GetRequest struct to get detailed information about vfpool device +type GetRequest struct { + // ID of vfpool device + // Required: true + VFPoolID uint64 `url:"id" json:"id" validate:"required"` +} + +// Get gets detailed information about vfpool device as a RecordVFPool struct +func (v VFPool) Get(ctx context.Context, req GetRequest) (*RecordVFPool, error) { + res, err := v.GetRaw(ctx, req) + if err != nil { + return nil, err + } + + info := RecordVFPool{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} + +// GetRaw gets detailed information about vfpool device as an array of bytes +func (v VFPool) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) { + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/vfpool/get" + + res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudbroker/vfpool/ids.go b/pkg/cloudbroker/vfpool/ids.go new file mode 100644 index 0000000..1a58061 --- /dev/null +++ b/pkg/cloudbroker/vfpool/ids.go @@ -0,0 +1,19 @@ +package vfpool + +// IDs gets array of VFPool IDs from ListVFPool struct +func (lv ListVFPool) IDs() []uint64 { + res := make([]uint64, 0, len(lv.Data)) + for _, e := range lv.Data { + res = append(res, e.ID) + } + return res +} + +// IDs gets array of VF IDs from VFSInfoList struct +func (lv VFSInfoList) IDs() []uint64 { + res := make([]uint64, 0, len(lv)) + for _, e := range lv { + res = append(res, e.ID) + } + return res +} diff --git a/pkg/cloudbroker/vfpool/list.go b/pkg/cloudbroker/vfpool/list.go new file mode 100644 index 0000000..676b691 --- /dev/null +++ b/pkg/cloudbroker/vfpool/list.go @@ -0,0 +1,83 @@ +package vfpool + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// ListRequest struct to get list of vfpool devices +type ListRequest struct { + // Find by ID + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Find by Grid ID + // Required: false + GID uint64 `url:"gid,omitempty" json:"gid,omitempty"` + + // Find by name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Find by description + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Find by account Access + // Required: false + AccountAccess uint64 `url:"accountAccess,omitempty" json:"accountAccess,omitempty"` + + // Find by resource group Access + // Required: false + RGAccess uint64 `url:"rgAccess,omitempty" json:"rgAccess,omitempty"` + + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + + // 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 all available vfpool devices as a ListVFPool struct +func (v VFPool) List(ctx context.Context, req ListRequest) (*ListVFPool, error) { + + res, err := v.ListRaw(ctx, req) + if err != nil { + return nil, err + } + + list := ListVFPool{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} + +// ListRaw gets list of all available vfpool devices as an array of bytes +func (v VFPool) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + if err := validators.ValidateRequest(req); err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/vfpool/list" + + res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) + return res, err +} diff --git a/pkg/cloudbroker/vfpool/models.go b/pkg/cloudbroker/vfpool/models.go new file mode 100644 index 0000000..3ecd53b --- /dev/null +++ b/pkg/cloudbroker/vfpool/models.go @@ -0,0 +1,116 @@ +package vfpool + +// Main information about vfpool device +type ItemVFPool struct { + // AccountAccess + AccountAccess []uint64 `json:"accountAccess"` + + // CreatedTime + CreatedTime uint64 `json:"createdTime"` + + // Description + Description string `json:"description"` + + // GID + GID uint64 `json:"gid"` + + // GUID + GUID uint64 `json:"guid"` + + // ID + ID uint64 `json:"id"` + + // Name + Name string `json:"name"` + + // RGAccess + RGAccess []uint64 `json:"rgAccess"` + + // Status + Status string `json:"status"` + + // UpdatedTime + UpdatedTime uint64 `json:"updatedTime"` + + // VFS + VFS []VFS `json:"vfs"` +} + +// List of information about vfpool devices +type ListVFPool struct { + Data []ItemVFPool `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} + +// Detailed information about vfpool device +type RecordVFPool struct { + // AccountAccess + AccountAccess []uint64 `json:"accountAccess"` + + // CreatedTime + CreatedTime uint64 `json:"createdTime"` + + // Description + Description string `json:"description"` + + // GID + GID uint64 `json:"gid"` + + // GUID + GUID uint64 `json:"guid"` + + // ID + ID uint64 `json:"id"` + + // Name + Name string `json:"name"` + + // RGAccess + RGAccess []uint64 `json:"rgAccess"` + + // Status + Status string `json:"status"` + + // UpdatedTime + UpdatedTime uint64 `json:"updatedTime"` + + // VFS + VFS []VFS `json:"vfs"` +} + +// VFS struct +type VFS struct { + // NodeID + NodeID uint64 `json:"nodeId"` + + // UpdatedTime + VFList VFList `json:"vfList"` +} + +// VFList struct +type VFList []VFItem + +// VFItem struct +type VFItem struct { + // NicName + NicName string `json:"nicName"` + + // VFSInfo list + VFSInfo VFSInfoList `json:"vfsInfo"` +} + +// VFSInfoList struct +type VFSInfoList []VFSInfoItem + +// VFSInfoItem struct +type VFSInfoItem struct { + // ID + ID uint64 `json:"id"` + + // Claimed + Claimed bool `json:"claimed"` + + // VM ID + VMID uint64 `json:"vmId"` +} diff --git a/pkg/cloudbroker/vfpool/serialize.go b/pkg/cloudbroker/vfpool/serialize.go new file mode 100644 index 0000000..143d8cb --- /dev/null +++ b/pkg/cloudbroker/vfpool/serialize.go @@ -0,0 +1,59 @@ +package vfpool + +import ( + "encoding/json" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/serialization" +) + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (lvfpool ListVFPool) Serialize(params ...string) (serialization.Serialized, error) { + if lvfpool.EntryCount == 0 { + return []byte{}, nil + } + + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(lvfpool, prefix, indent) + } + + return json.Marshal(lvfpool) +} + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (rvfpool RecordVFPool) Serialize(params ...string) (serialization.Serialized, error) { + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(rvfpool, prefix, indent) + } + + return json.Marshal(rvfpool) +} + +// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions. +// +// In order to serialize with indent make sure to follow these guidelines: +// - First argument -> prefix +// - Second argument -> indent +func (ivfpool ItemVFPool) Serialize(params ...string) (serialization.Serialized, error) { + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(ivfpool, prefix, indent) + } + + return json.Marshal(ivfpool) +} diff --git a/pkg/cloudbroker/vfpool/update.go b/pkg/cloudbroker/vfpool/update.go new file mode 100644 index 0000000..43129cb --- /dev/null +++ b/pkg/cloudbroker/vfpool/update.go @@ -0,0 +1,86 @@ +package vfpool + +import ( + "context" + "encoding/json" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// UpdateRequest struct to update vfpool device +type UpdateRequest struct { + // VFPool device ID + // Required: true + VFPoolID uint64 `url:"id" json:"id" validate:"required"` + + // Name of vfpool device + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Description + // Required: false + Description string `url:"description,omitempty" json:"description,omitempty"` + + // Name of device + // Required: false + Config []Config `url:"-" json:"config,omitempty" validation:"omitempty,dive"` + + // List of Account IDs + // Required: false + AccountAccess []uint64 `url:"accountAccess,omitempty" json:"accountAccess,omitempty"` + + // List of RG IDs + // Required: false + RGAccess []uint64 `url:"rgAccess,omitempty" json:"rgAccess,omitempty"` +} + +type wrapperUpdateRequest struct { + UpdateRequest + Config []string `url:"config,omitempty"` +} + +// Update updates vfpool device +func (v VFPool) Update(ctx context.Context, req UpdateRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + var config []string + + if len(req.Config) != 0 { + config = make([]string, 0, len(req.Config)) + + for c := range req.Config { + b, err := json.Marshal(req.Config[c]) + if err != nil { + return false, err + } + + config = append(config, string(b)) + } + } else { + config = []string{} + } + + reqWrapped := wrapperUpdateRequest{ + UpdateRequest: req, + Config: config, + } + + url := "/cloudbroker/vfpool/update" + + res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped) + 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/vfpool/vfpool.go b/pkg/cloudbroker/vfpool/vfpool.go new file mode 100644 index 0000000..1541349 --- /dev/null +++ b/pkg/cloudbroker/vfpool/vfpool.go @@ -0,0 +1,18 @@ +// API Actor for managing vfpool device +package vfpool + +import ( + "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" +) + +// Structure for creating request to vfpool +type VFPool struct { + client interfaces.Caller +} + +// Builder for vfpool endpoints +func New(client interfaces.Caller) *VFPool { + return &VFPool{ + client, + } +} diff --git a/pkg/cloudbroker/vgpu/list.go b/pkg/cloudbroker/vgpu/list.go index 05a1457..0ffa116 100644 --- a/pkg/cloudbroker/vgpu/list.go +++ b/pkg/cloudbroker/vgpu/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of VGPU @@ -40,6 +42,10 @@ type ListRequest struct { // Required: false PGPUID uint64 `url:"pgpuId,omitempty" json:"pgpuId,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -51,6 +57,7 @@ type ListRequest struct { // List gets list of all VGPU as a ListVGPU struct func (v VGPU) List(ctx context.Context, req ListRequest) (*ListVGPU, error) { + res, err := v.ListRaw(ctx, req) if err != nil { return nil, err @@ -68,6 +75,12 @@ func (v VGPU) List(ctx context.Context, req ListRequest) (*ListVGPU, error) { // ListRaw gets list of all VGPU as an array of bytes func (v VGPU) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/vgpu/list" res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/vins/create_in_account.go b/pkg/cloudbroker/vins/create_in_account.go index 2257098..212c1e2 100644 --- a/pkg/cloudbroker/vins/create_in_account.go +++ b/pkg/cloudbroker/vins/create_in_account.go @@ -46,6 +46,10 @@ type CreateInAccountRequest struct { // Required: false PreReservationsNum uint64 `url:"preReservationsNum,omitempty" json:"preReservationsNum,omitempty"` + // List of DNS ip address + // Required: false + DNSList []string `url:"dnsList" json:"dnsList,omitempty"` + // List of static routes, each item must have destination, netmask, and gateway fields // Required: false Routes []Route `url:"-" json:"routes,omitempty" validate:"omitempty,dive"` diff --git a/pkg/cloudbroker/vins/create_in_rg.go b/pkg/cloudbroker/vins/create_in_rg.go index 90084e3..29f3e7f 100644 --- a/pkg/cloudbroker/vins/create_in_rg.go +++ b/pkg/cloudbroker/vins/create_in_rg.go @@ -40,6 +40,10 @@ type CreateInRGRequest struct { // Required: false PreReservationsNum uint64 `url:"preReservationsNum,omitempty" json:"preReservationsNum,omitempty"` + // List of DNS ip address + // Required: false + DNSList []string `url:"dnsList" json:"dnsList,omitempty"` + // List of static routes, each item must have destination, netmask, and gateway fields // Required: false Routes []Route `url:"-" json:"routes,omitempty" validate:"omitempty,dive"` diff --git a/pkg/cloudbroker/vins/default_qos_update.go b/pkg/cloudbroker/vins/default_qos_update.go index 6d78ae3..9dc124a 100644 --- a/pkg/cloudbroker/vins/default_qos_update.go +++ b/pkg/cloudbroker/vins/default_qos_update.go @@ -20,7 +20,7 @@ type DefaultQOSUpdateRequest struct { // Internal traffic burst, kbit // Required: false - IngressBirst uint64 `url:"ingress_birst,omitempty" json:"ingress_birst,omitempty"` + IngressBirst uint64 `url:"ingress_burst,omitempty" json:"ingress_burst,omitempty"` // External traffic rate, kbit // Required: false diff --git a/pkg/cloudbroker/vins/dns_apply.go b/pkg/cloudbroker/vins/dns_apply.go new file mode 100644 index 0000000..33dbf50 --- /dev/null +++ b/pkg/cloudbroker/vins/dns_apply.go @@ -0,0 +1,43 @@ +package vins + +import ( + "context" + "net/http" + "strconv" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// DNSApplyRequest struct to apply new DNS list in VINS +type DNSApplyRequest struct { + // VINS ID + // Required: true + VINSID uint64 `url:"vinsId" json:"vinsId" validate:"required"` + + // List of DNS ip address + // Required: true + DNSList []string `url:"dnsList" json:"dnsList" validate:"required"` +} + +// DNSApply applies new DNS list in VINS +func (v VINS) DNSApply(ctx context.Context, req DNSApplyRequest) (bool, error) { + err := validators.ValidateRequest(req) + if err != nil { + return false, validators.ValidationErrors(validators.GetErrors(err)) + } + + url := "/cloudbroker/vins/dnsApply" + + 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/vins/ids.go b/pkg/cloudbroker/vins/ids.go index 77893bc..8e516b4 100644 --- a/pkg/cloudbroker/vins/ids.go +++ b/pkg/cloudbroker/vins/ids.go @@ -45,8 +45,8 @@ func (lr ListRoutes) IDs() []uint64 { return res } -// IDs gets array of NATRuleConfigIDs from ListNatRule struct -func (lnrc ListNatRule) IDs() []uint64 { +// IDs gets array of NATRuleConfigIDs from ListNATRule struct +func (lnrc ListNATRule) IDs() []uint64 { res := make([]uint64, 0, len(lnrc)) for _, nrc := range lnrc { res = append(res, nrc.ID) diff --git a/pkg/cloudbroker/vins/ip_reserve.go b/pkg/cloudbroker/vins/ip_reserve.go index 3abd913..b828984 100644 --- a/pkg/cloudbroker/vins/ip_reserve.go +++ b/pkg/cloudbroker/vins/ip_reserve.go @@ -45,6 +45,7 @@ type IPReserveRequest struct { // IPReserve creates reservation on ViNS DHCP func (v VINS) IPReserve(ctx context.Context, req IPReserveRequest) (string, error) { + err := validators.ValidateRequest(req) if err != nil { return "", validators.ValidationErrors(validators.GetErrors(err)) diff --git a/pkg/cloudbroker/vins/list.go b/pkg/cloudbroker/vins/list.go index 195cba2..80c1dee 100644 --- a/pkg/cloudbroker/vins/list.go +++ b/pkg/cloudbroker/vins/list.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListRequest struct to get list of VINSes @@ -32,6 +34,10 @@ type ListRequest struct { // Required: false IncludeDeleted bool `url:"includeDeleted,omitempty" json:"includeDeleted,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -43,6 +49,7 @@ type ListRequest struct { // List gets list of VINSes as a ListVINS struct func (v VINS) List(ctx context.Context, req ListRequest) (*ListVINS, error) { + res, err := v.ListRaw(ctx, req) if err != nil { return nil, err @@ -60,6 +67,12 @@ func (v VINS) List(ctx context.Context, req ListRequest) (*ListVINS, error) { // ListRaw gets list of VINSes as an array of bytes func (v VINS) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/vins/list" res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/vins/list_deleted.go b/pkg/cloudbroker/vins/list_deleted.go index 6a0335c..0bd28a5 100644 --- a/pkg/cloudbroker/vins/list_deleted.go +++ b/pkg/cloudbroker/vins/list_deleted.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) // ListDeletedRequest struct to get list of deleted VINSes @@ -28,6 +30,10 @@ type ListDeletedRequest struct { // Required: false ExtIP string `url:"extIp,omitempty" json:"extIp,omitempty"` + // Sort by one of supported fields, format +|-(field) + // Required: false + SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -39,6 +45,12 @@ type ListDeletedRequest struct { // ListDeleted gets list of deleted VINSes func (v VINS) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListVINS, error) { + + err := validators.ValidateRequest(req) + if err != nil { + return nil, validators.ValidationErrors(validators.GetErrors(err)) + } + url := "/cloudbroker/vins/listDeleted" res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) diff --git a/pkg/cloudbroker/vins/models.go b/pkg/cloudbroker/vins/models.go index 9a99ab1..10aabfc 100644 --- a/pkg/cloudbroker/vins/models.go +++ b/pkg/cloudbroker/vins/models.go @@ -146,6 +146,9 @@ type ItemInterface struct { // Network type NetType string `json:"netType"` + // NodeID + NodeID int64 `json:"nodeId"` + // PCI slot PCISlot int64 `json:"pciSlot"` @@ -337,7 +340,7 @@ type RecordGW struct { } // List NATRules -type ListNatRule []ItemNATRule +type ListNATRule []ItemNATRule // NAT config type NATConfig struct { @@ -348,7 +351,7 @@ type NATConfig struct { Network string `json:"network"` // Rules - Rules ListNatRule `json:"rules"` + Rules ListNATRule `json:"rules"` } // Main information about NAT @@ -677,6 +680,12 @@ type ItemVINS struct { // External IP ExternalIP string `json:"externalIP"` + // Extnet ID + ExtnetId uint64 `json:"extnetId"` + + // Free IPs + FreeIPs uint64 `json:"freeIPs"` + // Grid ID GID uint64 `json:"gid"` diff --git a/pkg/cloudbroker/vins/nat_rule_add.go b/pkg/cloudbroker/vins/nat_rule_add.go index a949a9e..8badc62 100644 --- a/pkg/cloudbroker/vins/nat_rule_add.go +++ b/pkg/cloudbroker/vins/nat_rule_add.go @@ -16,16 +16,16 @@ type NATRuleAddRequest struct { // Internal IP address to apply this rule to // Required: true - IntIP string `url:"intIp " json:"intIp " validate:"required"` - - // Internal IP port number to use for this rule - // Required: true - IntPort uint64 `url:"intPort" json:"intPort" validate:"required"` + IntIP string `url:"intIp" json:"intIp" validate:"required"` // External IP start port to use for this rule // Required: true ExtPortStart uint64 `url:"extPortStart" json:"extPortStart" validate:"required"` + // Internal IP port number to use for this rule + // Required: false + IntPort uint64 `url:"intPort,omitempty" json:"intPort,omitempty"` + // External IP end port to use for this rule // Required: false ExtPortEnd uint64 `url:"extPortEnd,omitempty" json:"extPortEnd,omitempty"` diff --git a/pkg/cloudbroker/vins/net_qos.go b/pkg/cloudbroker/vins/net_qos.go index c315c40..c642931 100644 --- a/pkg/cloudbroker/vins/net_qos.go +++ b/pkg/cloudbroker/vins/net_qos.go @@ -20,7 +20,7 @@ type NetQOSRequest struct { // Internal traffic burst, kbit // Required: false - IngressBirst uint64 `url:"ingress_birst,omitempty" json:"ingress_birst,omitempty"` + IngressBirst uint64 `url:"ingress_burst,omitempty" json:"ingress_burst,omitempty"` // External traffic rate, kbit // Required: false diff --git a/tests/platform_upgrade/.env.template b/tests/platform_upgrade/.env.template new file mode 100644 index 0000000..fd17149 --- /dev/null +++ b/tests/platform_upgrade/.env.template @@ -0,0 +1,5 @@ +# delta +AppID="app_id" +AppSecret="app_secret" +SSOURL="https://sso-delta.qa.loc:8443" +DecortURL="https://delta.qa.loc/" \ No newline at end of file diff --git a/tests/platform_upgrade/README.md b/tests/platform_upgrade/README.md new file mode 100644 index 0000000..7f8b4a9 --- /dev/null +++ b/tests/platform_upgrade/README.md @@ -0,0 +1,133 @@ +# Авто тесты при переходе на новую версию платформы + +## Содержание + +- [Авто тесты при переходе на новую версию платформы](#авто-тесты-при-переходе-на-новую-версию-платформы) + - [Содержание](#содержание) + - [Подготовка к тестам](#подготовка-к-тестам) + - [Тесты Raw методов (Get, List)](#тесты-raw-методов-get-list) + - [Cloudapi](#cloudapi) + - [Cloudbroker](#cloudbroker) + - [Тесты запросов](#тесты-запросов) + - [Cloudapi](#cloudapi-1) + - [Cloudbroker](#cloudbroker-1) + - [Тесты API методов](#тесты-api-методов) + +## Подготовка к тестам + +1. Тесты находятся по директории `decort-sdk/tests/platform_upgrade` +2. Внутри директории нужно создать и заполнить файл `.env` по аналогии с `.env.template` для доступа к платформе +3. Внутри директории нужно создать и заполнить файл `input.json`, содержащий json с раздела [POST /system/docgenerator/prepareCatalog](https://delta.qa.loc/system/ActorApi?group=system#!/system__docgenerator/post_system_docgenerator_prepareCatalog) (для получения json нажать кнопку Try it Out!) - требуется только для тестов запросов + +## Тесты Raw методов (Get, List) + +### Cloudapi + +Запустить тест `TestGetListCloudAPI` в `decort-sdk/tests/platform_upgrade/cloud_test.go` +При наличии подсвеченных полей, проверить, что они содержатся на платформе и не содержатся в go структурах, завести и исправить ошибку. + +Пример вывода: +```go + utils_get_list.go:71: Sizes list: OK + utils_get_list.go:71: Tasks list: + Platform has these fields that golang struct doesn't: [updatedBy guid] + utils_get_list.go:71: VINS list: + Platform has these fields that golang struct doesn't: [freeIPs extnetId] + utils_get_list.go:71: VINS get: OK +--- FAIL: TestGetListCloudAPI (66.13s) +``` + +### Cloudbroker + +**ВНИМАНИЕ: из-за особенностей архитектуры моделей (вложенные структуры без json-тегов) в cloudbroker этот тест часто выдает некорректные результаты - ложноположительные на предмет багов.** + +Запустить тест `TestGetListCloudbroker` в `decort-sdk/tests/platform_upgrade/cloud_test.go` +При наличии подсвеченных полей, проверить, что они содержатся на платформе и не содержатся в go структурах, завести и исправить ошибку. + +## Тесты запросов + +### Cloudapi + +Запустить тест `TestRequestsCloudAPI` в `decort-sdk/tests/platform_upgrade/cloud_test.go` +При наличии подсвеченных ошибок, проверить, что они являются ошибками (возможны ситуации, когда расхождение платформы и sdk задумано специально), завести и исправить ошибку. + +Пример вывода: +```go +=== RUN TestRequestsCloudAPI + utils_requests.go:125: Path /cloudapi/compute/affinityRuleRemove has following errors: [Field value has different required parameters on the platform and in golang structure] + utils_requests.go:125: Path /cloudapi/lb/listDeleted has following errors: [Platform has field accountId that golang structure doesn't] + utils_requests.go:125: Path /cloudapi/compute/pfwAdd has following errors: [Field localBasePort has different required parameters on the platform and in golang structure] + utils_requests.go:125: Path /cloudapi/kvmppc/create has following errors: [Field interfaces has different type parameters on the platform and in golang structure] + utils_requests.go:125: Path /cloudapi/image/create has following errors: [Platform (14) and golang structure (15) have different amount of fields. Field accountId has different required parameters on the platform and in golang structure] + <...> + utils_requests.go:125: Path /cloudapi/compute/affinityRuleAdd has following errors: [Field value has different required parameters on the platform and in golang structure] + utils_requests.go:125: Path /cloudapi/compute/antiAffinityRuleAdd has following errors: [Field value has different required parameters on the platform and in golang structure] + utils_requests.go:125: Path /cloudapi/lb/create has following errors: [Platform (7) and golang structure (8) have different amount of fields. Field extnetId has different required parameters on the platform and in golang structure Field vinsId has different required parameters on the platform and in golang structure] +--- FAIL: TestRequestsCloudAPI (0.02s) +FAIL +``` + +### Cloudbroker + +Запустить тест `TestRequestsCloudbroker` в `decort-sdk/tests/platform_upgrade/cloud_test.go` +При наличии подсвеченных ошибок, проверить, что они являются ошибками (возможны ситуации, когда расхождение платформы и sdk задумано специально), завести и исправить ошибку. + +Пример вывода: +```go +=== RUN TestRequestsCloudbroker + utils_requests.go:125: Path /cloudbroker/image/updateNodes has following errors: [Field enabledStacks has different type parameters on the platform and in golang structure] + utils_requests.go:125: Path /cloudbroker/lb/listDeleted has following errors: [Platform has field accountId that golang structure doesn't] + utils_requests.go:125: Path /cloudbroker/k8ci/listDeleted has following errors: [Platform has field k8cId that golang structure doesn't] +<...> + utils_requests.go:125: Path /cloudbroker/account/setCpuAllocationRatio has following errors: [Platform has field accountId that golang structure doesn't Field ratio has different required parameters on the platform and in golang structure] + utils_requests.go:125: Path /cloudbroker/image/list has following errors: [Field size has different type parameters on the platform and in golang structure] + utils_requests.go:125: Path /cloudbroker/rg/create has following errors: [Platform has field uniqPools that golang structure doesn't] + utils_requests.go:125: Path /cloudbroker/sep/create has following errors: [Field config has different required parameters on the platform and in golang structure] +--- FAIL: TestRequestsCloudbroker (0.02s) +FAIL +``` + +## Тесты API методов + +Запустить тест `TestGetAllPaths` в `decort-sdk/tests/platform_upgrade/cloud_test.go` +При наличии подсвеченных ошибок, проверить, что указанные методы API не являются устаревшими (deprecated). В противном случе добавить устаревшие методы в переменную `DEPRECATED_GROUPS` по адресу `decort-sdk/tests/platform_upgrade/utils_url.go`. + +Пример вывода: +```go +=== RUN TestGetAllPaths + cloud_test.go:692: Below API handlers (30 in total) need to be added to decort-sdk: + /cloudbroker/grid/addCustomBackupPath + /cloudapi/user/getResourceConsumption + /cloudapi/user/authenticate + /cloudbroker/compute/getCustomFields + /cloudapi/user/isValidInviteUserToken + /cloudapi/pcidevice/list + /cloudbroker/compute/createTemplateFromBlank + /cloudbroker/account/listVMs + /cloudapi/user/brief + /cloudapi/user/search + /cloudbroker/stack/setMemAllocationRatio + /cloudbroker/image/computeciUnset + /cloudbroker/image/uploadImageFile + /cloudapi/account/getStats + /cloudapi/disks/fromPlatformDisk + /cloudbroker/stack/getLogicalCoresCount + /cloudapi/lb/stop + /cloudapi/account/listVMs + /cloudapi/user/setData + /cloudapi/compute/createTemplateFromBlank + /cloudbroker/grid/removeCustomBackupPath + /cloudapi/user/getAudit + /cloudbroker/account/listCS + /cloudapi/account/listCS + /cloudbroker/stack/setCpuAllocationRatio + /cloudbroker/grid/setPasswordPolicy + /cloudapi/user/apiList + /cloudbroker/disks/fromPlatformDisk + /cloudapi/user/get + /cloudapi/vgpu/list +--- FAIL: TestGetAllPaths (0.03s) +FAIL +exit status 1 +FAIL repository.basistech.ru/BASIS/decort-golang-sdk/tests/platform_upgrade 0.031s +``` \ No newline at end of file diff --git a/tests/platform_upgrade/cloud_test.go b/tests/platform_upgrade/cloud_test.go new file mode 100644 index 0000000..8da9932 --- /dev/null +++ b/tests/platform_upgrade/cloud_test.go @@ -0,0 +1,696 @@ +package test + +import ( + "context" + "fmt" + "testing" + + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/account" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/extnet" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/flipgroup" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/image" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8ci" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8s" + "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" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/sizes" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/stack" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/tasks" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/vins" + + account_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/account" + audit_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/audit" + compute_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/compute" + disks_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/disks" + extnet_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/extnet" + flipgroup_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/flipgroup" + grid_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/grid" + image_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/image" + k8ci_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8ci" + k8s_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8s" + lb_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/lb" + pcidevice_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/pcidevice" + rg_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/rg" + sep_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/sep" + stack_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/stack" + tasks_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/tasks" + vins_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/vins" +) + +// TestGetListCloudAPI tests platforms responses vs. json tags of golang structures in cloudapi get/list methods +func TestGetListCloudAPI(t *testing.T) { + var bytes []byte + var err error + client, err := getClient() + if err != nil { + t.Fatalf("Cannot get client: %v", err) + } + + // Account + // List + bytes, err = client.CloudAPI().Account().ListRaw(context.Background(), account.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Account list", bytes, account.ListAccounts{}, t) + // Get + listAcc, _ := client.CloudAPI().Account().List(context.Background(), account.ListRequest{}) + if len(listAcc.Data) > 0 { + id := listAcc.Data[0].ID + bytes, err = client.CloudAPI().Account().GetRaw(context.Background(), account.GetRequest{AccountID: id}) + if err != nil { + t.Error(err) + } + getResult("Account get", bytes, account.RecordAccount{}, t) + } else { + t.Errorf("Can not test Account get because account list is empty") + } + + // Bservice + // List + bytes, err = client.CloudAPI().BService().ListRaw(context.Background(), bservice.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Bservice list", bytes, bservice.ListBasicServices{}, t) + // Get + listBServ, _ := client.CloudAPI().BService().List(context.Background(), bservice.ListRequest{}) + if len(listBServ.Data) > 0 { + id := listBServ.Data[0].ID + bytes, err = client.CloudAPI().BService().GetRaw(context.Background(), bservice.GetRequest{ServiceID: id}) + if err != nil { + t.Error(err) + } + getResult("Bservice get", bytes, bservice.RecordBasicService{}, t) + } else { + t.Errorf("Can not test Bservice get because bservice list is empty") + } + + // Compute + // List + bytes, err = client.CloudAPI().Compute().ListRaw(context.Background(), compute.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Compute list", bytes, compute.ListComputes{}, t) + // Get + listComp, _ := client.CloudAPI().Compute().List(context.Background(), compute.ListRequest{}) + if len(listComp.Data) > 0 { + id := listComp.Data[0].ID + bytes, err = client.CloudAPI().Compute().GetRaw(context.Background(), compute.GetRequest{ComputeID: id}) + if err != nil { + t.Error(err) + } + getResult("Compute get", bytes, compute.RecordCompute{}, t) + } else { + t.Errorf("Can not test Compute get because compute list is empty") + } + + // Disk + // List + bytes, err = client.CloudAPI().Disks().ListRaw(context.Background(), disks.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Disk list", bytes, disks.ListDisks{}, t) + // Get + listDisk, _ := client.CloudAPI().Disks().List(context.Background(), disks.ListRequest{}) + if len(listDisk.Data) > 0 { + id := listDisk.Data[0].ID + bytes, err = client.CloudAPI().Disks().GetRaw(context.Background(), disks.GetRequest{DiskID: id}) + if err != nil { + t.Error(err) + } + getResult("Disk get", bytes, disks.RecordDisk{}, t) + } else { + t.Errorf("Can not test Disk get because disk list is empty") + } + + // ExtNet + // List + bytes, err = client.CloudAPI().ExtNet().ListRaw(context.Background(), extnet.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("ExtNet list", bytes, extnet.ListExtNets{}, t) + // Get + listExtNet, _ := client.CloudAPI().ExtNet().List(context.Background(), extnet.ListRequest{}) + if len(listExtNet.Data) > 0 { + id := listExtNet.Data[0].ID + bytes, err = client.CloudAPI().ExtNet().GetRaw(context.Background(), extnet.GetRequest{NetID: id}) + if err != nil { + t.Error(err) + } + getResult("ExtNet get", bytes, extnet.RecordExtNet{}, t) + } else { + t.Errorf("Can not test ExtNet get because listExtNet list is empty") + } + + // FLIPGroup + // List + bytes, err = client.CloudAPI().FLIPGroup().ListRaw(context.Background(), flipgroup.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("FLIPGroup list", bytes, flipgroup.ListFLIPGroups{}, t) + // Get + listFG, _ := client.CloudAPI().FLIPGroup().List(context.Background(), flipgroup.ListRequest{}) + if len(listFG.Data) > 0 { + id := listFG.Data[0].ID + bytes, err = client.CloudAPI().FLIPGroup().GetRaw(context.Background(), flipgroup.GetRequest{FLIPGroupID: id}) + if err != nil { + t.Error(err) + } + getResult("FLIPGroup get", bytes, flipgroup.RecordFLIPGroup{}, t) + } else { + t.Errorf("Can not test FLIPGroup get because flipgroup list is empty") + } + + // Image + // List + bytes, err = client.CloudAPI().Image().ListRaw(context.Background(), image.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Image list", bytes, image.ListImages{}, t) + // Get + listImg, _ := client.CloudAPI().Image().List(context.Background(), image.ListRequest{}) + if len(listImg.Data) > 0 { + id := listImg.Data[0].ID + bytes, err = client.CloudAPI().Image().GetRaw(context.Background(), image.GetRequest{ImageID: id}) + if err != nil { + t.Error(err) + } + getResult("Image get", bytes, image.RecordImage{}, t) + } else { + t.Errorf("Can not test Image get because Image list is empty") + } + + // K8CI + // List + bytes, err = client.CloudAPI().K8CI().ListRaw(context.Background(), k8ci.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("K8CI list", bytes, k8ci.ListK8CI{}, t) + // Get + listk8ci, _ := client.CloudAPI().K8CI().List(context.Background(), k8ci.ListRequest{}) + if len(listk8ci.Data) > 0 { + id := listk8ci.Data[0].ID + bytes, err = client.CloudAPI().K8CI().GetRaw(context.Background(), k8ci.GetRequest{K8CIID: id}) + if err != nil { + t.Error(err) + } + getResult("K8CI get", bytes, k8ci.RecordK8CI{}, t) + } else { + t.Errorf("Can not test K8CI get because K8CI list is empty") + } + + // K8S + // List + bytes, err = client.CloudAPI().K8S().ListRaw(context.Background(), k8s.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("K8S list", bytes, k8s.ListK8SClusters{}, t) + // Get + listk8s, _ := client.CloudAPI().K8S().List(context.Background(), k8s.ListRequest{}) + if len(listk8s.Data) > 0 { + id := listk8s.Data[0].ID + bytes, err = client.CloudAPI().K8S().GetRaw(context.Background(), k8s.GetRequest{K8SID: id}) + if err != nil { + t.Error(err) + } + getResult("K8S get", bytes, k8s.RecordK8S{}, t) + } else { + t.Errorf("Can not test K8S get because K8S list is empty") + } + + // LB + // List + bytes, err = client.CloudAPI().LB().ListRaw(context.Background(), lb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("LB list", bytes, lb.ListLB{}, t) + // Get + listLB, _ := client.CloudAPI().LB().List(context.Background(), lb.ListRequest{}) + if len(listLB.Data) > 0 { + id := listLB.Data[0].ID + bytes, err = client.CloudAPI().LB().GetRaw(context.Background(), lb.GetRequest{LBID: id}) + if err != nil { + t.Error(err) + } + getResult("LB get", bytes, lb.RecordLB{}, t) + } else { + t.Errorf("Can not test LB get because LB list is empty") + } + + // Locations + // List + bytes, err = client.CloudAPI().Locations().ListRaw(context.Background(), locations.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Locations list", bytes, locations.ListLocations{}, t) + + // RG + // List + bytes, err = client.CloudAPI().RG().ListRaw(context.Background(), rg.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("RG list", bytes, rg.ListResourceGroups{}, t) + // Get + listRG, _ := client.CloudAPI().RG().List(context.Background(), rg.ListRequest{}) + if len(listRG.Data) > 0 { + id := listRG.Data[0].ID + bytes, err = client.CloudAPI().RG().GetRaw(context.Background(), rg.GetRequest{RGID: id}) + if err != nil { + t.Error(err) + } + getResult("RG get", bytes, rg.RecordResourceGroup{}, t) + } else { + t.Errorf("Can not test RG get because RG list is empty") + } + + // Sizes + // List + bytes, err = client.CloudAPI().Sizes().ListRaw(context.Background(), sizes.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Sizes list", bytes, sizes.ListSizes{}, t) + + // Stack + // List + bytes, err = client.CloudAPI().Stack().ListRaw(context.Background(), stack.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Stack list", bytes, stack.ListStacks{}, t) + + // Tasks + // List + bytes, err = client.CloudAPI().Tasks().ListRaw(context.Background(), tasks.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Tasks list", bytes, tasks.ListTasks{}, t) + // Get + listTasks, _ := client.CloudAPI().Tasks().List(context.Background(), tasks.ListRequest{}) + if len(listTasks.Data) > 0 { + id := listTasks.Data[0].AuditID + bytes, err = client.CloudAPI().Tasks().GetRaw(context.Background(), tasks.GetRequest{AuditID: id}) + if err != nil { + t.Error(err) + } + getResult("Tasks get", bytes, tasks.RecordAsyncTask{}, t) + } else { + t.Errorf("Can not test Tasks get because Tasks list is empty") + } + + // VINS + // List + bytes, err = client.CloudAPI().VINS().ListRaw(context.Background(), vins.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("VINS list", bytes, vins.ListVINS{}, t) + // Get + listVINS, _ := client.CloudAPI().VINS().List(context.Background(), vins.ListRequest{}) + if len(listVINS.Data) > 0 { + id := listVINS.Data[0].ID + bytes, err = client.CloudAPI().VINS().GetRaw(context.Background(), vins.GetRequest{VINSID: id}) + if err != nil { + t.Error(err) + } + getResult("VINS get", bytes, vins.RecordVINS{}, t) + } else { + t.Errorf("Can not test VINS get because VINS list is empty") + } +} + +// WARNING: not working correctly due to inclusions of tagless structures in cloudbroker +// TestGetListCloudbroker tests platforms responses vs. json tags of golang structures in cloudbroker get/list methods +func TestGetListCloudbroker(t *testing.T) { + var bytes []byte + var err error + client, err := getClient() + if err != nil { + t.Fatalf("Cannot get client: %v", err) + } + + // Account + // List + bytes, err = client.CloudBroker().Account().ListRaw(context.Background(), account_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Account list", bytes, account_cb.ListAccounts{}, t) + // Get + listAcc, _ := client.CloudBroker().Account().List(context.Background(), account_cb.ListRequest{}) + if len(listAcc.Data) > 0 { + id := listAcc.Data[0].ID + bytes, err = client.CloudBroker().Account().GetRaw(context.Background(), account_cb.GetRequest{AccountID: id}) + if err != nil { + t.Error(err) + } + getResult("Account get", bytes, account_cb.RecordAccount{}, t) + } else { + t.Errorf("Can not test Account get because account list is empty") + } + + // Audit + // List + bytes, err = client.CloudBroker().Audit().ListRaw(context.Background(), audit_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Audit list", bytes, audit_cb.ListAudits{}, t) + // Get + listAudits, _ := client.CloudBroker().Audit().List(context.Background(), audit_cb.ListRequest{}) + if len(listAudits.Data) > 0 { + id := listAudits.Data[0].GUID + bytes, err = client.CloudBroker().Audit().GetRaw(context.Background(), audit_cb.GetRequest{AuditGuid: id}) + if err != nil { + t.Error(err) + } + getResult("Audit get", bytes, audit_cb.RecordAudit{}, t) + } else { + t.Errorf("Can not test Audit get because Audit list is empty") + } + + // Compute + // List + bytes, err = client.CloudBroker().Compute().ListRaw(context.Background(), compute_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Compute list", bytes, compute_cb.ListComputes{}, t) + // Get + listComp, _ := client.CloudBroker().Compute().List(context.Background(), compute_cb.ListRequest{}) + if len(listComp.Data) > 0 { + id := listComp.Data[0].ID + bytes, err = client.CloudBroker().Compute().GetRaw(context.Background(), compute_cb.GetRequest{ComputeID: id}) + if err != nil { + t.Error(err) + } + getResult("Compute get", bytes, compute_cb.RecordCompute{}, t) + } else { + t.Errorf("Can not test Compute get because compute list is empty") + } + + // Disk + // List + bytes, err = client.CloudBroker().Disks().ListRaw(context.Background(), disks_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Disk list", bytes, disks_cb.ListDisks{}, t) + // Get + listDisk, _ := client.CloudBroker().Disks().List(context.Background(), disks_cb.ListRequest{}) + if len(listDisk.Data) > 0 { + id := listDisk.Data[0].ID + bytes, err = client.CloudBroker().Disks().GetRaw(context.Background(), disks_cb.GetRequest{DiskID: id}) + if err != nil { + t.Error(err) + } + getResult("Disk get", bytes, disks_cb.RecordDisk{}, t) + } else { + t.Errorf("Can not test Disk get because disk list is empty") + } + + // ExtNet + // List + bytes, err = client.CloudBroker().ExtNet().ListRaw(context.Background(), extnet_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("ExtNet list", bytes, extnet_cb.ListExtNet{}, t) + // Get + listExtNet, _ := client.CloudBroker().ExtNet().List(context.Background(), extnet_cb.ListRequest{}) + if len(listExtNet.Data) > 0 { + id := listExtNet.Data[0].ID + bytes, err = client.CloudBroker().ExtNet().GetRaw(context.Background(), extnet_cb.GetRequest{NetID: id}) + if err != nil { + t.Error(err) + } + getResult("ExtNet get", bytes, extnet_cb.RecordExtNet{}, t) + } else { + t.Errorf("Can not test ExtNet get because listExtNet list is empty") + } + + // FLIPGroup + // List + bytes, err = client.CloudBroker().FLIPGroup().ListRaw(context.Background(), flipgroup_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("FLIPGroup list", bytes, flipgroup_cb.ListFLIPGroups{}, t) + // Get + listFG, _ := client.CloudBroker().FLIPGroup().List(context.Background(), flipgroup_cb.ListRequest{}) + if len(listFG.Data) > 0 { + id := listFG.Data[0].ID + bytes, err = client.CloudBroker().FLIPGroup().GetRaw(context.Background(), flipgroup_cb.GetRequest{FLIPGroupID: id}) + if err != nil { + t.Error(err) + } + getResult("FLIPGroup get", bytes, flipgroup_cb.RecordFLIPGroup{}, t) + } else { + t.Errorf("Can not test FLIPGroup get because flipgroup list is empty") + } + + // Grid + // List + bytes, err = client.CloudBroker().Grid().ListRaw(context.Background(), grid_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Grid list", bytes, grid_cb.ListGrids{}, t) + // Get + listGrid, _ := client.CloudBroker().Grid().List(context.Background(), grid_cb.ListRequest{}) + if len(listGrid.Data) > 0 { + id := listGrid.Data[0].ID + bytes, err = client.CloudBroker().Grid().GetRaw(context.Background(), grid_cb.GetRequest{GID: id}) + if err != nil { + t.Error(err) + } + getResult("Grid get", bytes, grid_cb.RecordGrid{}, t) + } else { + t.Errorf("Can not test Grid get because Grid list is empty") + } + + // Image + // List + bytes, err = client.CloudBroker().Image().ListRaw(context.Background(), image_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Image list", bytes, image_cb.ListImages{}, t) + // Get + listImg, _ := client.CloudBroker().Image().List(context.Background(), image_cb.ListRequest{}) + if len(listImg.Data) > 0 { + id := listImg.Data[0].ID + bytes, err = client.CloudBroker().Image().GetRaw(context.Background(), image_cb.GetRequest{ImageID: id}) + if err != nil { + t.Error(err) + } + getResult("Image get", bytes, image_cb.RecordImage{}, t) + } else { + t.Errorf("Can not test Image get because Image list is empty") + } + + // K8CI + // List + bytes, err = client.CloudBroker().K8CI().ListRaw(context.Background(), k8ci_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("K8CI list", bytes, k8ci_cb.ListK8CI{}, t) + // Get + listk8ci, _ := client.CloudBroker().K8CI().List(context.Background(), k8ci_cb.ListRequest{}) + if len(listk8ci.Data) > 0 { + id := listk8ci.Data[0].ID + bytes, err = client.CloudBroker().K8CI().GetRaw(context.Background(), k8ci_cb.GetRequest{K8CIID: id}) + if err != nil { + t.Error(err) + } + getResult("K8CI get", bytes, k8ci_cb.RecordK8CI{}, t) + } else { + t.Errorf("Can not test K8CI get because K8CI list is empty") + } + + // K8S + // List + bytes, err = client.CloudBroker().K8S().ListRaw(context.Background(), k8s_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("K8S list", bytes, k8s_cb.ListK8S{}, t) + // Get + listk8s, _ := client.CloudBroker().K8S().List(context.Background(), k8s_cb.ListRequest{}) + if len(listk8s.Data) > 0 { + id := listk8s.Data[0].ID + bytes, err = client.CloudBroker().K8S().GetRaw(context.Background(), k8s_cb.GetRequest{K8SID: id}) + if err != nil { + t.Error(err) + } + getResult("K8S get", bytes, k8s_cb.RecordK8S{}, t) + } else { + t.Errorf("Can not test K8S get because K8S list is empty") + } + + // LB + // List + bytes, err = client.CloudBroker().LB().ListRaw(context.Background(), lb_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("LB list", bytes, lb_cb.ListLB{}, t) + // Get + listLB, _ := client.CloudBroker().LB().List(context.Background(), lb_cb.ListRequest{}) + if len(listLB.Data) > 0 { + id := listLB.Data[0].ID + bytes, err = client.CloudBroker().LB().GetRaw(context.Background(), lb_cb.GetRequest{LBID: id}) + if err != nil { + t.Error(err) + } + getResult("LB get", bytes, lb_cb.RecordLB{}, t) + } else { + t.Errorf("Can not test LB get because LB list is empty") + } + + // Pcidevice + // List + bytes, err = client.CloudBroker().PCIDevice().ListRaw(context.Background(), pcidevice_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Pcidevice list", bytes, pcidevice_cb.ListPCIDevices{}, t) + + // RG + // List + bytes, err = client.CloudBroker().RG().ListRaw(context.Background(), rg_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("RG list", bytes, rg_cb.ListRG{}, t) + // Get + listRG, _ := client.CloudBroker().RG().List(context.Background(), rg_cb.ListRequest{}) + if len(listRG.Data) > 0 { + id := listRG.Data[0].ID + bytes, err = client.CloudBroker().RG().GetRaw(context.Background(), rg_cb.GetRequest{RGID: id}) + if err != nil { + t.Error(err) + } + getResult("RG get", bytes, rg_cb.RecordRG{}, t) + } else { + t.Errorf("Can not test RG get because RG list is empty") + } + + // SEP + // List + bytes, err = client.CloudBroker().SEP().ListRaw(context.Background(), sep_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("SEP list", bytes, sep_cb.ListSEP{}, t) + // Get + listSEP, _ := client.CloudBroker().SEP().List(context.Background(), sep_cb.ListRequest{}) + if len(listSEP.Data) > 0 { + id := listSEP.Data[0].ID + bytes, err = client.CloudBroker().SEP().GetRaw(context.Background(), sep_cb.GetRequest{SEPID: id}) + if err != nil { + t.Error(err) + } + getResult("SEP get", bytes, sep_cb.RecordSEP{}, t) + } else { + t.Errorf("Can not test SEP get because SEP list is empty") + } + + // Stack + // List + bytes, err = client.CloudBroker().Stack().ListRaw(context.Background(), stack_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Stack list", bytes, stack_cb.ListStacks{}, t) + // Get + listStack, _ := client.CloudBroker().Stack().List(context.Background(), stack_cb.ListRequest{}) + if len(listStack.Data) > 0 { + id := listStack.Data[0].ID + bytes, err = client.CloudBroker().Stack().GetRaw(context.Background(), stack_cb.GetRequest{StackId: id}) + if err != nil { + t.Error(err) + } + getResult("Stack get", bytes, stack_cb.InfoStack{}, t) + } else { + t.Errorf("Can not test Stack get because Stack list is empty") + } + + // Tasks + // List + bytes, err = client.CloudBroker().Tasks().ListRaw(context.Background(), tasks_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("Tasks list", bytes, tasks_cb.ListTasks{}, t) + + // VINS + // List + bytes, err = client.CloudBroker().VINS().ListRaw(context.Background(), vins_cb.ListRequest{}) + if err != nil { + t.Error(err) + } + getResult("VINS list", bytes, vins_cb.ListVINS{}, t) + // Get + listVINS, _ := client.CloudBroker().VINS().List(context.Background(), vins_cb.ListRequest{}) + if len(listVINS.Data) > 0 { + id := listVINS.Data[0].ID + bytes, err = client.CloudBroker().VINS().GetRaw(context.Background(), vins_cb.GetRequest{VINSID: id}) + if err != nil { + t.Error(err) + } + getResult("VINS get", bytes, vins_cb.RecordVINS{}, t) + } else { + t.Errorf("Can not test VINS get because VINS 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) + getErrorsFromJSON(bytes, t, "cloudapi") +} + +// TestRequestsCloudbroker tests platform requests vs. golang request structures in sdk for cloudbroker requests +func TestRequestsCloudbroker(t *testing.T) { + bytes := getBytesFromJSON("input.json", t) + getErrorsFromJSON(bytes, t, "cloudbroker") +} + +// 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) { + bytes := getBytesFromJSON("input.json", t) + jsonUrls, err := getUrlsFromBytes(bytes) + if err != nil { + t.Error(err) + } + + decortUrls := readUrlFromDir("../../pkg", len(jsonUrls)) + + result := getMissingDecortUrls(jsonUrls, decortUrls) + if len(result) > 0 { + errorText := fmt.Sprintf("Below API handlers (%d in total) need to be added to decort-sdk:\n", len(result)) + for _, r := range result { + errorText += fmt.Sprintln(r) + } + t.Errorf(errorText) + } +} diff --git a/tests/platform_upgrade/request_map.go b/tests/platform_upgrade/request_map.go new file mode 100644 index 0000000..5a2817d --- /dev/null +++ b/tests/platform_upgrade/request_map.go @@ -0,0 +1,912 @@ +package test + +import ( + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/account" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/extnet" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/flipgroup" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/image" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8ci" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8s" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmppc" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmx86" + "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/pcidevice" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/rg" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/sizes" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/stack" + "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/tasks" + "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" + + account_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/account" + apiaccess_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/apiaccess" + audit_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/audit" + backup_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/backup" + compute_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/compute" + disks_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/disks" + extnet_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/extnet" + flipgroup_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/flipgroup" + grid_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/grid" + group_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/group" + image_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/image" + k8ci_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8ci" + k8s_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8s" + kvmppc_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/kvmppc" + kvmx86_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/kvmx86" + lb_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/lb" + 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" + sep_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/sep" + stack_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/stack" + tasks_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/tasks" + user_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/user" + vfpool_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/vfpool" + vgpu_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/vgpu" + vins_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/vins" +) + +type EmptyStruct struct{} + +// getRequestsMapCloudAPI maps request path with request golang sdk structures for cloudapi most used requests +func getRequestsMapCloudAPI() map[string]interface{} { + return map[string]interface{}{ + // account + "/cloudapi/account/addUser": account.AddUserRequest{}, + "/cloudapi/account/audits": account.AuditsRequest{}, + "/cloudapi/account/delete": account.DeleteRequest{}, + "/cloudapi/account/deleteUser": account.DeleteUserRequest{}, + "/cloudapi/account/disable": account.DisableEnableRequest{}, + "/cloudapi/account/enable": account.DisableEnableRequest{}, + "/cloudapi/account/get": account.GetRequest{}, + "/cloudapi/account/getConsumedAccountUnits": account.GetConsumedAccountUnitsRequest{}, + "/cloudapi/account/getConsumedCloudUnitsByType": account.GetConsumedCloudUnitsByTypeRequest{}, + "/cloudapi/account/getConsumption": account.GetConsumptionRequest{}, + "/cloudapi/account/getReservedAccountUnits": account.GetReservedAccountUnitsRequest{}, + "/cloudapi/account/getResourceConsumption": account.GetResourceConsumptionRequest{}, + "/cloudapi/account/list": account.ListRequest{}, + "/cloudapi/account/listComputes": account.ListComputesRequest{}, + "/cloudapi/account/listDeleted": account.ListDeletedRequest{}, + "/cloudapi/account/listDisks": account.ListDisksRequest{}, + "/cloudapi/account/listFlipGroups": account.ListFLIPGroupsRequest{}, + "/cloudapi/account/listRG": account.ListRGRequest{}, + "/cloudapi/account/listResourceConsumption": EmptyStruct{}, + "/cloudapi/account/listTemplates": account.ListTemplatesRequest{}, + "/cloudapi/account/listVins": account.ListVINSRequest{}, + "/cloudapi/account/restore": account.RestoreRequest{}, + "/cloudapi/account/update": account.UpdateRequest{}, + "/cloudapi/account/updateUser": account.UpdateUserRequest{}, + + //bservice + "/cloudapi/bservice/create": bservice.CreateRequest{}, + "/cloudapi/bservice/delete": bservice.DeleteRequest{}, + "/cloudapi/bservice/disable": bservice.DisableRequest{}, + "/cloudapi/bservice/enable": bservice.EnableRequest{}, + "/cloudapi/bservice/get": bservice.GetRequest{}, + "/cloudapi/bservice/groupAdd": bservice.GroupAddRequest{}, + "/cloudapi/bservice/groupComputeRemove": bservice.GroupComputeRemoveRequest{}, + "/cloudapi/bservice/groupGet": bservice.GroupGetRequest{}, + "/cloudapi/bservice/groupParentAdd": bservice.GroupParentAddRequest{}, + "/cloudapi/bservice/groupParentRemove": bservice.GroupParentRemoveRequest{}, + "/cloudapi/bservice/groupRemove": bservice.GroupRemoveRequest{}, + "/cloudapi/bservice/groupResize": bservice.GroupResizeRequest{}, + "/cloudapi/bservice/groupStart": bservice.GroupStartRequest{}, + "/cloudapi/bservice/groupStop": bservice.GroupStopRequest{}, + "/cloudapi/bservice/groupUpdate": bservice.GroupUpdateRequest{}, + "/cloudapi/bservice/groupUpdateExtnet": bservice.GroupUpdateExtNetRequest{}, + "/cloudapi/bservice/groupUpdateVins": bservice.GroupUpdateVINSRequest{}, + "/cloudapi/bservice/list": bservice.ListRequest{}, + "/cloudapi/bservice/listDeleted": bservice.ListDeletedRequest{}, + "/cloudapi/bservice/restore": bservice.RestoreRequest{}, + "/cloudapi/bservice/snapshotCreate": bservice.SnapshotCreateRequest{}, + "/cloudapi/bservice/snapshotDelete": bservice.SnapshotDeleteRequest{}, + "/cloudapi/bservice/snapshotList": bservice.SnapshotListRequest{}, + "/cloudapi/bservice/snapshotRollback": bservice.SnapshotRollbackRequest{}, + "/cloudapi/bservice/start": bservice.StartRequest{}, + "/cloudapi/bservice/stop": bservice.StopRequest{}, + + // compute + "/cloudapi/compute/affinityGroupCheckStart": compute.AffinityGroupCheckStartRequest{}, + "/cloudapi/compute/affinityLabelRemove": compute.AffinityLabelRemoveRequest{}, + "/cloudapi/compute/affinityLabelSet": compute.AffinityLabelSetRequest{}, + "/cloudapi/compute/affinityRelations": compute.AffinityRelationsRequest{}, + "/cloudapi/compute/affinityRuleAdd": compute.AffinityRuleAddRequest{}, + "/cloudapi/compute/affinityRuleRemove": compute.AffinityRuleRemoveRequest{}, + "/cloudapi/compute/affinityRulesClear": compute.AffinityRulesClearRequest{}, + "/cloudapi/compute/antiAffinityRuleAdd": compute.AntiAffinityRuleAddRequest{}, + "/cloudapi/compute/antiAffinityRuleRemove": compute.AntiAffinityRuleRemoveRequest{}, + "/cloudapi/compute/antiAffinityRulesClear": compute.AffinityRulesClearRequest{}, + "/cloudapi/compute/attachGpu": compute.AttachGPURequest{}, + "/cloudapi/compute/attachPciDevice": compute.AttachPCIDeviceRequest{}, + "/cloudapi/compute/audits": compute.AuditsRequest{}, + "/cloudapi/compute/bootDiskSet": compute.BootDiskSetRequest{}, + "/cloudapi/compute/bootOrderGet": compute.BootOrderGetRequest{}, + "/cloudapi/compute/bootOrderSet": compute.BootOrderSetRequest{}, + "/cloudapi/compute/cdEject": compute.CDEjectRequest{}, + "/cloudapi/compute/cdInsert": compute.CDInsertRequest{}, + "/cloudapi/compute/changeLinkState": compute.ChangeLinkStateRequest{}, + "/cloudapi/compute/clone": compute.CloneRequest{}, + "/cloudapi/compute/createTemplate": compute.CreateTemplateRequest{}, + "/cloudapi/compute/createTemplateFromBlank": compute.CreateTemplateFromBlankRequest{}, + "/cloudapi/compute/delete": compute.DeleteRequest{}, + "/cloudapi/compute/deleteCustomFields": compute.DeleteCustomFieldsRequest{}, + "/cloudapi/compute/detachGpu": compute.DetachGPURequest{}, + "/cloudapi/compute/detachPciDevice": compute.DetachPCIDeviceRequest{}, + "/cloudapi/compute/disable": compute.DisableRequest{}, + "/cloudapi/compute/diskAdd": compute.DiskAddRequest{}, + "/cloudapi/compute/diskAttach": compute.DiskAttachRequest{}, + "/cloudapi/compute/diskDel": compute.DiskDelRequest{}, + "/cloudapi/compute/diskDetach": compute.DiskDetachRequest{}, + "/cloudapi/compute/diskMigrate": compute.DiskMigrateRequest{}, + "/cloudapi/compute/diskQos": compute.DiskQOSRequest{}, + "/cloudapi/compute/diskSwitchToReplication": compute.DiskSwitchToReplicationRequest{}, + "/cloudapi/compute/diskResize": compute.DiskResizeRequest{}, + "/cloudapi/compute/enable": compute.EnableRequest{}, + "/cloudapi/compute/get": compute.GetRequest{}, + "/cloudapi/compute/getAudits": compute.GetAuditsRequest{}, + "/cloudapi/compute/getConsoleUrl": compute.GetConsoleURLRequest{}, + "/cloudapi/compute/getCustomFields": compute.GetCustomFieldsRequest{}, + "/cloudapi/compute/getLog": compute.GetLogRequest{}, + "/cloudapi/compute/list": compute.ListRequest{}, + "/cloudapi/compute/listDeleted": compute.ListDeletedRequest{}, + "/cloudapi/compute/listPciDevice": compute.ListPCIDeviceRequest{}, + "/cloudapi/compute/listVGpu": compute.ListVGPURequest{}, + "/cloudapi/compute/moveToRg": compute.MoveToRGRequest{}, + "/cloudapi/compute/netAttach": compute.NetAttachRequest{}, + "/cloudapi/compute/netDetach": compute.NetDetachRequest{}, + "/cloudapi/compute/pfwAdd": compute.PFWAddRequest{}, + "/cloudapi/compute/pfwDel": compute.PFWDelRequest{}, + "/cloudapi/compute/pfwList": compute.PFWListRequest{}, + "/cloudapi/compute/pause": compute.PauseRequest{}, + "/cloudapi/compute/pinToStack": compute.PinToStackRequest{}, + "/cloudapi/compute/powerCycle": compute.PowerCycleRequest{}, + "/cloudapi/compute/reboot": compute.RebootRequest{}, + "/cloudapi/compute/redeploy": compute.RedeployRequest{}, + "/cloudapi/compute/reset": compute.ResetRequest{}, + "/cloudapi/compute/resize": compute.ResizeRequest{}, + "/cloudapi/compute/restore": compute.RestoreRequest{}, + "/cloudapi/compute/resume": compute.ResumeRequest{}, + "/cloudapi/compute/setCustomFields": compute.SetCustomFieldsRequest{}, + "/cloudapi/compute/snapshotCreate": compute.SnapshotCreateRequest{}, + "/cloudapi/compute/snapshotDelete": compute.SnapshotDeleteRequest{}, + "/cloudapi/compute/snapshotList": compute.SnapshotListRequest{}, + "/cloudapi/compute/snapshotRollback": compute.SnapshotRollbackRequest{}, + "/cloudapi/compute/snapshotUsage": compute.SnapshotUsageRequest{}, + "/cloudapi/compute/start": compute.StartRequest{}, + "/cloudapi/compute/stop": compute.StopRequest{}, + "/cloudapi/compute/tagAdd": compute.TagAddRequest{}, + "/cloudapi/compute/tagRemove": compute.TagRemoveRequest{}, + "/cloudapi/compute/unpinFromStack": compute.UnpinFromStackRequest{}, + "/cloudapi/compute/update": compute.UpdateRequest{}, + "/cloudapi/compute/userGrant": compute.UserGrantRequest{}, + "/cloudapi/compute/userList": compute.UserListRequest{}, + "/cloudapi/compute/userRevoke": compute.UserRevokeRequest{}, + "/cloudapi/compute/userUpdate": compute.UserUpdateRequest{}, + + // disks + "/cloudapi/disks/create": disks.CreateRequest{}, + "/cloudapi/disks/delete": disks.DeleteRequest{}, + "/cloudapi/disks/deleteDisks": disks.DisksDeleteRequest{}, + "/cloudapi/disks/fromPlatformDisk": disks.FromPlatformDiskRequest{}, + "/cloudapi/disks/get": disks.GetRequest{}, + "/cloudapi/disks/limitIO": disks.LimitIORequest{}, + "/cloudapi/disks/list": disks.ListRequest{}, + "/cloudapi/disks/listDeleted": disks.ListDeletedRequest{}, + "/cloudapi/disks/listTypes": disks.ListTypesRequest{}, + "/cloudapi/disks/listUnattached": disks.ListUnattachedRequest{}, + "/cloudapi/disks/rename": disks.RenameRequest{}, + "/cloudapi/disks/replicate": disks.ReplicateRequest{}, + "/cloudapi/disks/replicationResume": disks.ReplicationResumeRequest{}, + "/cloudapi/disks/replicationReverse": disks.ReplicationReverseRequest{}, + "/cloudapi/disks/replicationStart": disks.ReplicationStartRequest{}, + "/cloudapi/disks/replicationStatus": disks.ReplicationStatusRequest{}, + "/cloudapi/disks/replicationStop": disks.ReplicationStopRequest{}, + "/cloudapi/disks/replicationSuspend": disks.ReplicationSuspendRequest{}, + "/cloudapi/disks/resize": disks.ResizeRequest{}, + "/cloudapi/disks/resize2": disks.ResizeRequest{}, + "/cloudapi/disks/restore": disks.RestoreRequest{}, + "/cloudapi/disks/search": disks.SearchRequest{}, + "/cloudapi/disks/share": disks.ShareRequest{}, + "/cloudapi/disks/snapshotDelete": disks.SnapshotDeleteRequest{}, + "/cloudapi/disks/snapshotRollback": disks.SnapshotRollbackRequest{}, + "/cloudapi/disks/unshare": disks.UnshareRequest{}, + + // extnet + "/cloudapi/extnet/get": extnet.GetRequest{}, + "/cloudapi/extnet/getDefault": EmptyStruct{}, + "/cloudapi/extnet/list": extnet.ListRequest{}, + "/cloudapi/extnet/listComputes": extnet.ListComputesRequest{}, + + // flipgroup + "/cloudapi/flipgroup/computeAdd": flipgroup.ComputeAddRequest{}, + "/cloudapi/flipgroup/computeRemove": flipgroup.ComputeRemoveRequest{}, + "/cloudapi/flipgroup/create": flipgroup.CreateRequest{}, + "/cloudapi/flipgroup/delete": flipgroup.DeleteRequest{}, + "/cloudapi/flipgroup/edit": flipgroup.EditRequest{}, + "/cloudapi/flipgroup/get": flipgroup.GetRequest{}, + "/cloudapi/flipgroup/list": flipgroup.ListRequest{}, + + // image + "/cloudapi/image/create": image.CreateRequest{}, + "/cloudapi/image/createVirtual": image.CreateVirtualRequest{}, + "/cloudapi/image/delete": image.DeleteRequest{}, + "/cloudapi/image/get": image.GetRequest{}, + "/cloudapi/image/link": image.LinkRequest{}, + "/cloudapi/image/list": image.ListRequest{}, + "/cloudapi/image/rename": image.RenameRequest{}, + + // k8ci, k8s + "/cloudapi/k8ci/get": k8ci.GetRequest{}, + "/cloudapi/k8ci/list": k8ci.ListRequest{}, + "/cloudapi/k8ci/listDeleted": k8ci.ListDeletedRequest{}, + "/cloudapi/k8s/create": k8s.CreateRequest{}, + "/cloudapi/k8s/delete": k8s.DeleteRequest{}, + "/cloudapi/k8s/deleteMasterFromGroup": k8s.DeleteMasterFromGroupRequest{}, + "/cloudapi/k8s/deleteWorkerFromGroup": k8s.DeleteWorkerFromGroupRequest{}, + "/cloudapi/k8s/disable": k8s.DisableEnableRequest{}, + "/cloudapi/k8s/enable": k8s.DisableEnableRequest{}, + "/cloudapi/k8s/findGroupByLabel": k8s.FindGroupByLabelRequest{}, + "/cloudapi/k8s/get": k8s.GetRequest{}, + "/cloudapi/k8s/getConfig": k8s.GetConfigRequest{}, + "/cloudapi/k8s/getNodeAnnotations": k8s.GetNodeAnnotationsRequest{}, + "/cloudapi/k8s/getNodeLabels": k8s.GetNodeLabelsRequest{}, + "/cloudapi/k8s/getNodeTaints": k8s.GetNodeTaintsRequest{}, + "/cloudapi/k8s/getWorkerNodesMetaData": k8s.GetWorkerNodesMetaDataRequest{}, + "/cloudapi/k8s/list": k8s.ListRequest{}, + "/cloudapi/k8s/listDeleted": k8s.ListDeletedRequest{}, + "/cloudapi/k8s/restore": k8s.RestoreRequest{}, + "/cloudapi/k8s/start": k8s.StartRequest{}, + "/cloudapi/k8s/stop": k8s.StopRequest{}, + "/cloudapi/k8s/update": k8s.UpdateRequest{}, + "/cloudapi/k8s/updateWorkerNodesMetaData": k8s.UpdateWorkerNodesMetaDataRequest{}, + "/cloudapi/k8s/workerAdd": k8s.WorkerAddRequest{}, + "/cloudapi/k8s/workersGroupAdd": k8s.WorkersGroupAddRequest{}, + "/cloudapi/k8s/workersGroupDelete": k8s.WorkersGroupDeleteRequest{}, + "/cloudapi/k8s/workersGroupGetByName": k8s.WorkersGroupGetByNameRequest{}, + "/cloudapi/k8s/workerReset": k8s.WorkerResetRequest{}, + "/cloudapi/k8s/workerRestart": k8s.WorkerRestartRequest{}, + + // kvmppc + "/cloudapi/kvmppc/create": kvmppc.CreateRequest{}, + "/cloudapi/kvmppc/createBlank": kvmppc.CreateBlankRequest{}, + "/cloudapi/kvmx86/create": kvmx86.CreateRequest{}, + "/cloudapi/kvmx86/createBlank": kvmx86.CreateBlankRequest{}, + + // lb + "/cloudapi/lb/backendCreate": lb.BackendCreateRequest{}, + "/cloudapi/lb/backendDelete": lb.BackendDeleteRequest{}, + "/cloudapi/lb/backendServerAdd": lb.BackendServerAddRequest{}, + "/cloudapi/lb/backendServerDelete": lb.BackendServerDeleteRequest{}, + "/cloudapi/lb/backendServerUpdate": lb.BackendServerUpdateRequest{}, + "/cloudapi/lb/backendUpdate": lb.BackendUpdateRequest{}, + "/cloudapi/lb/configReset": lb.ConfigResetRequest{}, + "/cloudapi/lb/create": lb.CreateRequest{}, + "/cloudapi/lb/delete": lb.DeleteRequest{}, + "/cloudapi/lb/disable": lb.DisableEnableRequest{}, + "/cloudapi/lb/enable": lb.DisableEnableRequest{}, + "/cloudapi/lb/frontendBind": lb.FrontendBindRequest{}, + "/cloudapi/lb/frontendBindDelete": lb.FrontendBindDeleteRequest{}, + "/cloudapi/lb/frontendBindingUpdate": lb.FrontendBindUpdateRequest{}, + "/cloudapi/lb/frontendCreate": lb.FrontendCreateRequest{}, + "/cloudapi/lb/frontendDelete": lb.FrontendDeleteRequest{}, + "/cloudapi/lb/get": lb.GetRequest{}, + "/cloudapi/lb/makeHighlyAvailable": lb.HighlyAvailableRequest{}, + "/cloudapi/lb/list": lb.ListRequest{}, + "/cloudapi/lb/listDeleted": lb.ListDeletedRequest{}, + "/cloudapi/lb/restart": lb.RestartRequest{}, + "/cloudapi/lb/restore": lb.RestoreRequest{}, + "/cloudapi/lb/start": lb.StartRequest{}, + "/cloudapi/lb/stop": lb.StopRequest{}, + "/cloudapi/lb/update": lb.UpdateRequest{}, + "/cloudapi/lb/updateSysctlParams": lb.UpdateSysctParamsRequest{}, + + // locations + "/cloudapi/locations/getUrl": EmptyStruct{}, + "/cloudapi/locations/list": locations.ListRequest{}, + + // pcidevice + "/cloudapi/pcidevice/list": pcidevice.ListRequest{}, + + // rg + "/cloudapi/rg/accessGrant": rg.AccessGrantRequest{}, + "/cloudapi/rg/accessRevoke": rg.AccessRevokeRequest{}, + "/cloudapi/rg/affinityGroupComputes": rg.AffinityGroupComputesRequest{}, + "/cloudapi/rg/affinityGroupsGet": rg.AffinityGroupsGetRequest{}, + "/cloudapi/rg/affinityGroupsList": rg.AffinityGroupsListRequest{}, + "/cloudapi/rg/audits": rg.AuditsRequest{}, + "/cloudapi/rg/create": rg.CreateRequest{}, + "/cloudapi/rg/delete": rg.DeleteRequest{}, + "/cloudapi/rg/disable": rg.DisableRequest{}, + "/cloudapi/rg/enable": rg.EnableRequest{}, + "/cloudapi/rg/get": rg.GetRequest{}, + "/cloudapi/rg/getResourceConsumption": rg.GetResourceConsumptionRequest{}, + "/cloudapi/rg/list": rg.ListRequest{}, + "/cloudapi/rg/listComputes": rg.ListComputesRequest{}, + "/cloudapi/rg/listDeleted": rg.ListDeletedRequest{}, + "/cloudapi/rg/listLb": rg.ListLBRequest{}, + "/cloudapi/rg/listPFW": rg.ListPFWRequest{}, + "/cloudapi/rg/listResourceConsumption": EmptyStruct{}, + "/cloudapi/rg/listVins": rg.ListVINSRequest{}, + "/cloudapi/rg/restore": rg.RestoreRequest{}, + "/cloudapi/rg/setDefNet": rg.SetDefNetRequest{}, + "/cloudapi/rg/update": rg.UpdateRequest{}, + "/cloudapi/rg/usage": rg.UsageRequest{}, + + // stack, tasks, sizes + "/cloudapi/sizes/list": sizes.ListRequest{}, + "/cloudapi/stack/get": stack.GetRequest{}, + "/cloudapi/stack/list": stack.ListRequest{}, + "/cloudapi/tasks/get": tasks.GetRequest{}, + "/cloudapi/tasks/list": tasks.ListRequest{}, + + // user + "/cloudapi/user/apiList": user.APIListRequest{}, + "/cloudapi/user/authenticate": user.AuthenticateRequest{}, + "/cloudapi/user/brief": EmptyStruct{}, + "/cloudapi/user/get": user.GetRequest{}, + "/cloudapi/user/getAudit": user.GetAuditRequest{}, + "/cloudapi/user/getResourceConsumption": EmptyStruct{}, + "/cloudapi/user/isValidInviteUserToken": user.IsValidInviteUserTokenRequest{}, + "/cloudapi/user/search": user.SearchRequest{}, + "/cloudapi/user/setData": user.SetDataRequest{}, + + // vfpool + "/cloudapi/vfpool/get": vfpool.GetRequest{}, + "/cloudapi/vfpool/list": vfpool.ListRequest{}, + + // vins + "/cloudapi/vins/audits": vins.AuditsRequest{}, + "/cloudapi/vins/createInAccount": vins.CreateInAccountRequest{}, + "/cloudapi/vins/createInRG": vins.CreateInRGRequest{}, + "/cloudapi/vins/delete": vins.DeleteRequest{}, + "/cloudapi/vins/disable": vins.DisableEnableRequest{}, + "/cloudapi/vins/dnsApply": vins.DNSApplyRequest{}, + "/cloudapi/vins/enable": vins.DisableEnableRequest{}, + "/cloudapi/vins/extNetConnect": vins.ExtNetConnectRequest{}, + "/cloudapi/vins/extNetDisconnect": vins.ExtNetDisconnectRequest{}, + "/cloudapi/vins/extNetList": vins.ExtNetListRequest{}, + "/cloudapi/vins/get": vins.GetRequest{}, + "/cloudapi/vins/ipList": vins.IPListRequest{}, + "/cloudapi/vins/ipRelease": vins.IPReleaseRequest{}, + "/cloudapi/vins/ipReserve": vins.IPReserveRequest{}, + "/cloudapi/vins/list": vins.ListRequest{}, + "/cloudapi/vins/listDeleted": vins.ListDeletedRequest{}, + "/cloudapi/vins/natRuleAdd": vins.NATRuleAddRequest{}, + "/cloudapi/vins/natRuleDel": vins.NATRuleDelRequest{}, + "/cloudapi/vins/natRuleList": vins.NATRuleListRequest{}, + "/cloudapi/vins/restore": vins.RestoreRequest{}, + "/cloudapi/vins/search": vins.SearchRequest{}, + "/cloudapi/vins/staticRouteAccessGrant": vins.StaticRouteAccessGrantRequest{}, + "/cloudapi/vins/staticRouteAccessRevoke": vins.StaticRouteAccessRevokeRequest{}, + "/cloudapi/vins/staticRouteAdd": vins.StaticRouteAddRequest{}, + "/cloudapi/vins/staticRouteDel": vins.StaticRouteDelRequest{}, + "/cloudapi/vins/staticRouteList": vins.StaticRouteListRequest{}, + "/cloudapi/vins/vnfdevRedeploy": vins.VNFDevRedeployRequest{}, + "/cloudapi/vins/vnfdevRestart": vins.VNFDevRestartRequest{}, + } +} + +// getRequestsMapCloudbroker maps request path with request golang sdk structures for cloudbroker most used requests +func getRequestsMapCloudbroker() map[string]interface{} { + return map[string]interface{}{ + // account_cb + "/cloudbroker/account/addUser": account_cb.AddUserRequest{}, + "/cloudbroker/account/audits": account_cb.AuditsRequest{}, + "/cloudbroker/account/create": account_cb.CreateRequest{}, + "/cloudbroker/account/delete": account_cb.DeleteRequest{}, + "/cloudbroker/account/deleteAccounts": account_cb.DeleteAccountsRequest{}, + "/cloudbroker/account/deleteUser": account_cb.DeleteUserRequest{}, + "/cloudbroker/account/disable": account_cb.DisableRequest{}, + "/cloudbroker/account/disableAccounts": account_cb.DisableAccountsRequest{}, + "/cloudbroker/account/enable": account_cb.EnableRequest{}, + "/cloudbroker/account/enableAccounts": account_cb.EnableAccountsRequest{}, + "/cloudbroker/account/get": account_cb.GetRequest{}, + "/cloudbroker/account/getResourceConsumption": account_cb.GetResourceConsumptionRequest{}, + "/cloudbroker/account/grantAccessTemplates": account_cb.GrantAccessTemplatesRequest{}, + "/cloudbroker/account/list": account_cb.ListRequest{}, + "/cloudbroker/account/listAvailableTemplates": account_cb.ListAvailableTemplatesRequest{}, + "/cloudbroker/account/listComputes": account_cb.ListComputesRequest{}, + "/cloudbroker/account/listDeleted": account_cb.ListDeletedRequest{}, + "/cloudbroker/account/listDisks": account_cb.ListDisksRequest{}, + "/cloudbroker/account/listFlipGroups": account_cb.ListFLIPGroupsRequest{}, + "/cloudbroker/account/listRG": account_cb.ListRGRequest{}, + "/cloudbroker/account/listResourceConsumption": EmptyStruct{}, + "/cloudbroker/account/listVins": account_cb.ListVINSRequest{}, + "/cloudbroker/account/restore": account_cb.RestoreRequest{}, + "/cloudbroker/account/revokeAccessTemplates": account_cb.RevokeAccessTemplatesRequest{}, + "/cloudbroker/account/setCpuAllocationParameter": account_cb.SetCPUAllocationParameterRequest{}, + "/cloudbroker/account/setCpuAllocationRatio": account_cb.SetCPUAllocationRatioRequest{}, + "/cloudbroker/account/update": account_cb.UpdateRequest{}, + "/cloudbroker/account/updateComputeFeatures": account_cb.UpdateComputeFeaturesRequest{}, + "/cloudbroker/account/updateResourceTypes": account_cb.UpdateResourceTypesRequest{}, + "/cloudbroker/account/updateUser": account_cb.UpdateUserRequest{}, + + // apiaccess_cb + "/cloudbroker/apiaccess/apisExclude": apiaccess_cb.APIsExcludeRequest{}, + "/cloudbroker/apiaccess/apiFind": apiaccess_cb.APIFindRequest{}, + "/cloudbroker/apiaccess/apisInclude": apiaccess_cb.APIsIncludeRequest{}, + "/cloudbroker/apiaccess/copy": apiaccess_cb.CopyRequest{}, + "/cloudbroker/apiaccess/create": apiaccess_cb.CreateRequest{}, + "/cloudbroker/apiaccess/delete": apiaccess_cb.DeleteRequest{}, + "/cloudbroker/apiaccess/descUpdate": apiaccess_cb.DescUpdateRequest{}, + "/cloudbroker/apiaccess/get": apiaccess_cb.GetRequest{}, + "/cloudbroker/apiaccess/getFull": EmptyStruct{}, + "/cloudbroker/apiaccess/getPreGroups": EmptyStruct{}, + "/cloudbroker/apiaccess/list": apiaccess_cb.ListRequest{}, + "/cloudbroker/apiaccess/listDeleted": apiaccess_cb.ListDeletedRequest{}, + "/cloudbroker/apiaccess/setDefault": apiaccess_cb.SetDefaultRequest{}, + "/cloudbroker/apiaccess/subtract": apiaccess_cb.SubtractRequest{}, + "/cloudbroker/apiaccess/union": apiaccess_cb.UnionRequest{}, + "/cloudbroker/apiaccess/update": apiaccess_cb.UpdateRequest{}, + "/cloudbroker/apiaccess/userList": apiaccess_cb.UserListRequest{}, + + // audit_cb + "/cloudbroker/audit/get": audit_cb.GetRequest{}, + "/cloudbroker/audit/linkedJobs": audit_cb.LinkedJobsRequest{}, + "/cloudbroker/audit/list": audit_cb.ListRequest{}, + + // backup_cb + "/cloudbroker/backup/createDiskBackup": backup_cb.CreateDiskBackupRequest{}, + "/cloudbroker/backup/createDisksBackup": backup_cb.CreateDisksBackupRequest{}, + "/cloudbroker/backup/deleteDiskBackup": backup_cb.DeleteDiskBackupRequest{}, + "/cloudbroker/backup/listBackupPaths": backup_cb.ListBackupPathsRequest{}, + "/cloudbroker/backup/restoreDiskFromBackup": backup_cb.RestoreDiskFromBackupRequest{}, + "/cloudbroker/backup/restoreDisksFromBackup": backup_cb.RestoreDisksFromBackupRequest{}, + + // compute_cb + "/cloudbroker/compute/affinityGroupCheckStart": compute_cb.AffinityGroupCheckStartRequest{}, + "/cloudbroker/compute/affinityLabelRemove": compute_cb.AffinityLabelRemoveRequest{}, + "/cloudbroker/compute/affinityLabelSet": compute_cb.AffinityLabelSetRequest{}, + "/cloudbroker/compute/affinityRelations": compute_cb.AffinityRelationsRequest{}, + "/cloudbroker/compute/affinityRuleAdd": compute_cb.AffinityRuleAddRequest{}, + "/cloudbroker/compute/affinityRuleRemove": compute_cb.AffinityRuleRemoveRequest{}, + "/cloudbroker/compute/affinityRulesClear": compute_cb.AffinityRulesClearRequest{}, + "/cloudbroker/compute/antiAffinityRuleAdd": compute_cb.AntiAffinityRuleAddRequest{}, + "/cloudbroker/compute/antiAffinityRuleRemove": compute_cb.AntiAffinityRuleRemoveRequest{}, + "/cloudbroker/compute/antiAffinityRulesClear": compute_cb.AffinityRulesClearRequest{}, + "/cloudbroker/compute/attachGpu": compute_cb.AttachGPURequest{}, + "/cloudbroker/compute/attachPciDevice": compute_cb.AttachPCIDeviceRequest{}, + "/cloudbroker/compute/audits": compute_cb.AuditsRequest{}, + "/cloudbroker/compute/bootDiskSet": compute_cb.BootDiskSetRequest{}, + "/cloudbroker/compute/bootOrderGet": compute_cb.BootOrderGetRequest{}, + "/cloudbroker/compute/bootOrderSet": compute_cb.BootOrderSetRequest{}, + "/cloudbroker/compute/cdEject": compute_cb.CDEjectRequest{}, + "/cloudbroker/compute/cdInsert": compute_cb.CDInsertRequest{}, + "/cloudbroker/compute/changeLinkState": compute_cb.ChangeLinkStateRequest{}, + "/cloudbroker/compute/clone": compute_cb.CloneRequest{}, + "/cloudbroker/compute/computeciSet": compute_cb.ComputeCISetRequest{}, + "/cloudbroker/compute/computeciUnset": compute_cb.ComputeCIUnsetRequest{}, + "/cloudbroker/compute/createTemplate": compute_cb.CreateTemplateRequest{}, + "/cloudbroker/compute/createTemplateFromBlank": compute_cb.CreateTemplateFromBlankRequest{}, + "/cloudbroker/compute/delete": compute_cb.DeleteRequest{}, + "/cloudbroker/compute/deleteCustomFields": compute_cb.DeleteCustomFieldsRequest{}, + "/cloudbroker/compute/detachGpu": compute_cb.DetachGPURequest{}, + "/cloudbroker/compute/detachPciDevice": compute_cb.DetachPCIDeviceRequest{}, + "/cloudbroker/compute/disable": compute_cb.DisableRequest{}, + "/cloudbroker/compute/diskAdd": compute_cb.DiskAddRequest{}, + "/cloudbroker/compute/diskAttach": compute_cb.DiskAttachRequest{}, + "/cloudbroker/compute/diskDel": compute_cb.DiskDelRequest{}, + "/cloudbroker/compute/diskDetach": compute_cb.DiskDetachRequest{}, + "/cloudbroker/compute/diskMigrate": compute_cb.DiskMigrateRequest{}, + "/cloudbroker/compute/diskResize": compute_cb.DiskResizeRequest{}, + "/cloudbroker/compute/diskSwitchToReplication": compute_cb.DiskSwitchToReplicationRequest{}, + "/cloudbroker/compute/diskQos": compute_cb.DiskQOSRequest{}, + "/cloudbroker/compute/enable": compute_cb.EnableRequest{}, + "/cloudbroker/compute/get": compute_cb.GetRequest{}, + "/cloudbroker/compute/getAudits": compute_cb.GetAuditsRequest{}, + "/cloudbroker/compute/getConsoleUrl": compute_cb.GetConsoleURLRequest{}, + "/cloudbroker/compute/getCustomFields": compute_cb.GetCustomFieldsRequest{}, + "/cloudbroker/compute/getLog": compute_cb.GetLogRequest{}, + "/cloudbroker/compute/list": compute_cb.ListRequest{}, + "/cloudbroker/compute/listDeleted": compute_cb.ListDeletedRequest{}, + "/cloudbroker/compute/listPciDevice": compute_cb.ListPCIDeviceRequest{}, + "/cloudbroker/compute/listVGpu": compute_cb.ListVGPURequest{}, + "/cloudbroker/compute/massDelete": compute_cb.MassDeleteRequest{}, + "/cloudbroker/compute/massStart": compute_cb.MassStartRequest{}, + "/cloudbroker/compute/massStop": compute_cb.MassStopRequest{}, + "/cloudbroker/compute/massReboot": compute_cb.MassRebootRequest{}, + "/cloudbroker/compute/massRepairBootFs": compute_cb.MassRepairBootFSRequest{}, + "/cloudbroker/compute/migrate": compute_cb.MigrateRequest{}, + "/cloudbroker/compute/migrateStorage": compute_cb.MigrateStorageRequest{}, + "/cloudbroker/compute/migrateStorageAbort": compute_cb.MigrateStorageAbortRequest{}, + "/cloudbroker/compute/migrateStorageCleanup": compute_cb.MigrateStorageCleanUpRequest{}, + "/cloudbroker/compute/migrateStorageInfo": compute_cb.MigrateStorageInfoRequest{}, + "/cloudbroker/compute/moveToRg": compute_cb.MoveToRGRequest{}, + "/cloudbroker/compute/netAttach": compute_cb.NetAttachRequest{}, + "/cloudbroker/compute/netDetach": compute_cb.NetDetachRequest{}, + "/cloudbroker/compute/netQos": compute_cb.NetQOSRequest{}, + "/cloudbroker/compute/pfwAdd": compute_cb.PFWAddRequest{}, + "/cloudbroker/compute/pfwDel": compute_cb.PFWDelRequest{}, + "/cloudbroker/compute/pfwList": compute_cb.PFWListRequest{}, + "/cloudbroker/compute/pause": compute_cb.PauseRequest{}, + "/cloudbroker/compute/pinToStack": compute_cb.PinToStackRequest{}, + "/cloudbroker/compute/powerCycle": compute_cb.PowerCycleRequest{}, + "/cloudbroker/compute/raiseDown": EmptyStruct{}, + "/cloudbroker/compute/reboot": compute_cb.RebootRequest{}, + "/cloudbroker/compute/redeploy": compute_cb.RedeployRequest{}, + "/cloudbroker/compute/registration": compute_cb.RegistrationRequest{}, + "/cloudbroker/compute/repairBootFs": compute_cb.RepairBootFSRequest{}, + "/cloudbroker/compute/reset": compute_cb.ResetRequest{}, + "/cloudbroker/compute/resize": compute_cb.ResizeRequest{}, + "/cloudbroker/compute/restore": compute_cb.RestoreRequest{}, + "/cloudbroker/compute/resume": compute_cb.ResumeRequest{}, + "/cloudbroker/compute/setCustomFields": compute_cb.SetCustomFieldsRequest{}, + "/cloudbroker/compute/snapshotCreate": compute_cb.SnapshotCreateRequest{}, + "/cloudbroker/compute/snapshotDelete": compute_cb.SnapshotDeleteRequest{}, + "/cloudbroker/compute/snapshotEvictDisk": compute_cb.SnapshotEvictDiskRequest{}, + "/cloudbroker/compute/snapshotList": compute_cb.SnapshotListRequest{}, + "/cloudbroker/compute/snapshotRollback": compute_cb.SnapshotRollbackRequest{}, + "/cloudbroker/compute/snapshotUsage": compute_cb.SnapshotUsageRequest{}, + "/cloudbroker/compute/start": compute_cb.StartRequest{}, + "/cloudbroker/compute/stop": compute_cb.StopRequest{}, + "/cloudbroker/compute/tagAdd": compute_cb.TagAddRequest{}, + "/cloudbroker/compute/tagRemove": compute_cb.TagRemoveRequest{}, + "/cloudbroker/compute/unpinFromStack": compute_cb.UnpinFromStackRequest{}, + "/cloudbroker/compute/update": compute_cb.UpdateRequest{}, + "/cloudbroker/compute/userGrant": compute_cb.UserGrantRequest{}, + "/cloudbroker/compute/userList": compute_cb.UserListRequest{}, + "/cloudbroker/compute/userRevoke": compute_cb.UserRevokeRequest{}, + "/cloudbroker/compute/userUpdate": compute_cb.UserUpdateRequest{}, + + // disks + "/cloudbroker/disks/create": disks_cb.CreateRequest{}, + "/cloudbroker/disks/delete": disks_cb.DeleteRequest{}, + "/cloudbroker/disks/deleteDisks": disks_cb.DeleteDisksRequest{}, + "/cloudbroker/disks/fromPlatformDisk": disks_cb.FromPlatformDiskRequest{}, + "/cloudbroker/disks/get": disks_cb.GetRequest{}, + "/cloudbroker/disks/limitIO": disks_cb.LimitIORequest{}, + "/cloudbroker/disks/list": disks_cb.ListRequest{}, + "/cloudbroker/disks/listDeleted": disks_cb.ListDeletedRequest{}, + "/cloudbroker/disks/listTypes": disks_cb.ListTypesRequest{}, + "/cloudbroker/disks/listUnattached": disks_cb.ListUnattachedRequest{}, + "/cloudbroker/disks/rename": disks_cb.RenameRequest{}, + "/cloudbroker/disks/replicate": disks_cb.ReplicateRequest{}, + "/cloudbroker/disks/replicationResume": disks_cb.ReplicationResumeRequest{}, + "/cloudbroker/disks/replicationReverse": disks_cb.ReplicationReverseRequest{}, + "/cloudbroker/disks/replicationStart": disks_cb.ReplicationStartRequest{}, + "/cloudbroker/disks/replicationStatus": disks_cb.ReplicationStatusRequest{}, + "/cloudbroker/disks/replicationStop": disks_cb.ReplicationStopRequest{}, + "/cloudbroker/disks/replicationSuspend": disks_cb.ReplicationSuspendRequest{}, + "/cloudbroker/disks/resize": disks_cb.ResizeRequest{}, + "/cloudbroker/disks/resize2": disks_cb.ResizeRequest{}, + "/cloudbroker/disks/restore": disks_cb.RestoreRequest{}, + "/cloudbroker/disks/search": disks_cb.SearchRequest{}, + "/cloudbroker/disks/share": disks_cb.ShareRequest{}, + "/cloudbroker/disks/snapshotDelete": disks_cb.SnapshotDeleteRequest{}, + "/cloudbroker/disks/snapshotRollback": disks_cb.SnapshotRollbackRequest{}, + "/cloudbroker/disks/unshare": disks_cb.UnshareRequest{}, + + // extnet + "/cloudbroker/extnet/accessAdd": extnet_cb.AccessAddRequest{}, + "/cloudbroker/extnet/accessRemove": extnet_cb.AccessRemoveRequest{}, + "/cloudbroker/extnet/create": extnet_cb.CreateRequest{}, + "/cloudbroker/extnet/dnsApply": extnet_cb.DNSApplyRequest{}, + "/cloudbroker/extnet/defaultQosUpdate": extnet_cb.DefaultQOSUpdateRequest{}, + "/cloudbroker/extnet/destroy": extnet_cb.DestroyRequest{}, + "/cloudbroker/extnet/deviceDeploy": extnet_cb.DeviceDeployRequest{}, + "/cloudbroker/extnet/deviceMigrate": extnet_cb.DeviceMigrateRequest{}, + "/cloudbroker/extnet/deviceRemove": extnet_cb.DeviceRemoveRequest{}, + "/cloudbroker/extnet/deviceRestart": extnet_cb.DeviceRestartRequest{}, + "/cloudbroker/extnet/disable": extnet_cb.DisableRequest{}, + "/cloudbroker/extnet/enable": extnet_cb.EnableRequest{}, + "/cloudbroker/extnet/get": extnet_cb.GetRequest{}, + "/cloudbroker/extnet/getDefault": EmptyStruct{}, + "/cloudbroker/extnet/ipsExclude": extnet_cb.IPsExcludeRequest{}, + "/cloudbroker/extnet/ipsExcludeRange": extnet_cb.IPsExcludeRangeRequest{}, + "/cloudbroker/extnet/ipsInclude": extnet_cb.IPsExcludeRequest{}, + "/cloudbroker/extnet/ipsIncludeRange": extnet_cb.IPsExcludeRangeRequest{}, + "/cloudbroker/extnet/list": extnet_cb.ListRequest{}, + "/cloudbroker/extnet/ntpApply": extnet_cb.NTPApplyRequest{}, + "/cloudbroker/extnet/raiseDown": EmptyStruct{}, + "/cloudbroker/extnet/setDefault": extnet_cb.SetDefaultRequest{}, + "/cloudbroker/extnet/staticRouteAccessGrant": extnet_cb.StaticRouteAccessGrantRequest{}, + "/cloudbroker/extnet/staticRouteAccessRevoke": extnet_cb.StaticRouteAccessRevokeRequest{}, + "/cloudbroker/extnet/staticRouteAdd": extnet_cb.StaticRouteAddRequest{}, + "/cloudbroker/extnet/staticRouteDel": extnet_cb.StaticRouteDelRequest{}, + "/cloudbroker/extnet/staticRouteList": extnet_cb.StaticRouteListRequest{}, + "/cloudbroker/extnet/update": extnet_cb.UpdateRequest{}, + + // flipgroup + "/cloudbroker/flipgroup/computeAdd": flipgroup_cb.ComputeAddRequest{}, + "/cloudbroker/flipgroup/computeRemove": flipgroup_cb.ComputeRemoveRequest{}, + "/cloudbroker/flipgroup/create": flipgroup_cb.CreateRequest{}, + "/cloudbroker/flipgroup/delete": flipgroup_cb.DeleteRequest{}, + "/cloudbroker/flipgroup/edit": flipgroup_cb.EditRequest{}, + "/cloudbroker/flipgroup/get": flipgroup_cb.GetRequest{}, + "/cloudbroker/flipgroup/list": flipgroup_cb.ListRequest{}, + + // grid + "/cloudbroker/grid/add": grid_cb.AddRequest{}, + "/cloudbroker/grid/addCustomBackupPath": grid_cb.AddCustomBackupPathRequest{}, + "/cloudbroker/grid/changeSettings": grid_cb.ChangeSettingsRequest{}, + "/cloudbroker/grid/checkVMs": grid_cb.CheckVMsRequest{}, + "/cloudbroker/grid/createSystemSpace": grid_cb.CreateSystemSpaceRequest{}, + "/cloudbroker/grid/executeMaintenanceScript": grid_cb.ExecuteMaintenanceScriptRequest{}, + "/cloudbroker/grid/get": grid_cb.GetRequest{}, + "/cloudbroker/grid/getBackup": grid_cb.GetBackupRequest{}, + "/cloudbroker/grid/getDiagnosis": grid_cb.GetDiagnosisRequest{}, + "/cloudbroker/grid/getResourceConsumption": grid_cb.GetResourceConsumptionRequest{}, + "/cloudbroker/grid/list": grid_cb.ListRequest{}, + "/cloudbroker/grid/listEmails": grid_cb.ListEmailsRequest{}, + "/cloudbroker/grid/listResourceConsumption": EmptyStruct{}, + "/cloudbroker/grid/purgeLogs": grid_cb.PurgeLogsRequest{}, + "/cloudbroker/grid/removeCustomBackupPath": grid_cb.RemoveCustomBackupPathRequest{}, + "/cloudbroker/grid/rename": grid_cb.RenameRequest{}, + "/cloudbroker/grid/servicesRestart": grid_cb.ServicesRestartRequest{}, + "/cloudbroker/grid/setCpuAllocationParameter": grid_cb.SetCPUAllocationParameterRequest{}, + "/cloudbroker/grid/setCpuAllocationRatio": grid_cb.SetCPUAllocationRatioRequest{}, + "/cloudbroker/grid/setCpuAllocationRatioForVM": grid_cb.SetCPUAllocationRatioForVMRequest{}, + "/cloudbroker/grid/setMemAllocationRatio": grid_cb.SetMemAllocationRatioRequest{}, + "/cloudbroker/grid/setPasswordPolicy": grid_cb.SetPasswordPolicyRequest{}, + "/cloudbroker/grid/status": EmptyStruct{}, + + // group + "/cloudbroker/group/get": group_cb.GetRequest{}, + "/cloudbroker/group/list": group_cb.ListRequest{}, + + // image + "/cloudbroker/image/computeciSet": image_cb.ComputeCISetRequest{}, + "/cloudbroker/image/computeciUnset": image_cb.ComputeCIUnsetRequest{}, + "/cloudbroker/image/createCDROMImage": image_cb.CreateCDROMImageRequest{}, + "/cloudbroker/image/createImage": image_cb.CreateRequest{}, + "/cloudbroker/image/createVirtual": image_cb.CreateVirtualRequest{}, + "/cloudbroker/image/delete": image_cb.DeleteRequest{}, + "/cloudbroker/image/deleteCDROMImage": image_cb.DeleteCDROMImageRequest{}, + "/cloudbroker/image/deleteImages": image_cb.DeleteImagesRequest{}, + "/cloudbroker/image/disable": image_cb.DisableRequest{}, + "/cloudbroker/image/edit": image_cb.EditRequest{}, + "/cloudbroker/image/enable": image_cb.EnableRequest{}, + "/cloudbroker/image/get": image_cb.GetRequest{}, + "/cloudbroker/image/grantAccess": image_cb.GrantAccessRequest{}, + "/cloudbroker/image/link": image_cb.LinkRequest{}, + "/cloudbroker/image/list": image_cb.ListRequest{}, + "/cloudbroker/image/listStacks": image_cb.ListStacksRequest{}, + "/cloudbroker/image/rename": image_cb.RenameRequest{}, + "/cloudbroker/image/revokeAccess": image_cb.RevokeAccessRequest{}, + "/cloudbroker/image/share": image_cb.ShareRequest{}, + "/cloudbroker/image/syncCreateImage": image_cb.SyncCreateRequest{}, + "/cloudbroker/image/updateNodes": image_cb.UpdateNodesRequest{}, + + // k8ci + "/cloudbroker/k8ci/accessAdd": k8ci_cb.AccessAddRequest{}, + "/cloudbroker/k8ci/accessRemove": k8ci_cb.AccessRemoveRequest{}, + "/cloudbroker/k8ci/create": k8ci_cb.CreateRequest{}, + "/cloudbroker/k8ci/delete": k8ci_cb.DeleteRequest{}, + "/cloudbroker/k8ci/disable": k8ci_cb.DisableRequest{}, + "/cloudbroker/k8ci/enable": k8ci_cb.EnableRequest{}, + "/cloudbroker/k8ci/get": k8ci_cb.GetRequest{}, + "/cloudbroker/k8ci/list": k8ci_cb.ListRequest{}, + "/cloudbroker/k8ci/listDeleted": k8ci_cb.ListDeletedRequest{}, + "/cloudbroker/k8ci/restore": k8ci_cb.RestoreRequest{}, + + // k8s + "/cloudbroker/k8s/create": k8s_cb.CreateRequest{}, + "/cloudbroker/k8s/delete": k8s_cb.DeleteRequest{}, + "/cloudbroker/k8s/deleteMasterFromGroup": k8s_cb.DeleteMasterFromGroupRequest{}, + "/cloudbroker/k8s/deleteWorkerFromGroup": k8s_cb.DeleteWorkerFromGroupRequest{}, + "/cloudbroker/k8s/disable": k8s_cb.DisableRequest{}, + "/cloudbroker/k8s/enable": k8s_cb.EnableRequest{}, + "/cloudbroker/k8s/findGroupByLabel": k8s_cb.FindGroupByLabelRequest{}, + "/cloudbroker/k8s/get": k8s_cb.GetRequest{}, + "/cloudbroker/k8s/getConfig": k8s_cb.GetConfigRequest{}, + "/cloudbroker/k8s/getNodeAnnotations": k8s_cb.GetNodeAnnotationsRequest{}, + "/cloudbroker/k8s/getNodeLabels": k8s_cb.GetNodeLabelsRequest{}, + "/cloudbroker/k8s/getNodeTaints": k8s_cb.GetNodeTaintsRequest{}, + "/cloudbroker/k8s/getWorkerNodesMetaData": k8s_cb.GetWorkerNodesMetaDataRequest{}, + "/cloudbroker/k8s/list": k8s_cb.ListRequest{}, + "/cloudbroker/k8s/listDeleted": k8s_cb.ListDeletedRequest{}, + "/cloudbroker/k8s/restore": k8s_cb.RestoreRequest{}, + "/cloudbroker/k8s/start": k8s_cb.StartRequest{}, + "/cloudbroker/k8s/stop": k8s_cb.StopRequest{}, + "/cloudbroker/k8s/update": k8s_cb.UpdateRequest{}, + "/cloudbroker/k8s/updateWorkerNodesMetaData": k8s_cb.UpdateWorkerNodesMetaDataRequest{}, + "/cloudbroker/k8s/workerAdd": k8s_cb.WorkerAddRequest{}, + "/cloudbroker/k8s/workersGroupAdd": k8s_cb.WorkersGroupAddRequest{}, + "/cloudbroker/k8s/workersGroupDelete": k8s_cb.WorkersGroupDeleteRequest{}, + "/cloudbroker/k8s/workersGroupGetByName": k8s_cb.WorkersGroupGetByNameRequest{}, + "/cloudbroker/k8s/workerReset": k8s_cb.WorkerResetRequest{}, + "/cloudbroker/k8s/workerRestart": k8s_cb.WorkerRestartRequest{}, + + // kvmppc, kvmx86 + "/cloudbroker/kvmppc/create": kvmppc_cb.CreateRequest{}, + "/cloudbroker/kvmppc/createBlank": kvmppc_cb.CreateBlankRequest{}, + "/cloudbroker/kvmppc/massCreate": kvmppc_cb.MassCreateRequest{}, + "/cloudbroker/kvmx86/create": kvmx86_cb.CreateRequest{}, + "/cloudbroker/kvmx86/createBlank": kvmx86_cb.CreateBlankRequest{}, + "/cloudbroker/kvmx86/massCreate": kvmx86_cb.MassCreateRequest{}, + + // lb + "/cloudbroker/lb/backendCreate": lb_cb.BackendCreateRequest{}, + "/cloudbroker/lb/backendDelete": lb_cb.BackendDeleteRequest{}, + "/cloudbroker/lb/backendServerAdd": lb_cb.BackendServerAddRequest{}, + "/cloudbroker/lb/backendServerDelete": lb_cb.BackendServerDeleteRequest{}, + "/cloudbroker/lb/backendServerUpdate": lb_cb.BackendServerUpdateRequest{}, + "/cloudbroker/lb/backendUpdate": lb_cb.BackendUpdateRequest{}, + "/cloudbroker/lb/configReset": lb_cb.ConfigResetRequest{}, + "/cloudbroker/lb/create": lb_cb.CreateRequest{}, + "/cloudbroker/lb/delete": lb_cb.DeleteRequest{}, + "/cloudbroker/lb/disable": lb_cb.DisableRequest{}, + "/cloudbroker/lb/enable": lb_cb.EnableRequest{}, + "/cloudbroker/lb/frontendBind": lb_cb.FrontendBindRequest{}, + "/cloudbroker/lb/frontendBindDelete": lb_cb.FrontendBindDeleteRequest{}, + "/cloudbroker/lb/frontendBindingUpdate": lb_cb.FrontendBindUpdateRequest{}, + "/cloudbroker/lb/frontendCreate": lb_cb.FrontendCreateRequest{}, + "/cloudbroker/lb/frontendDelete": lb_cb.FrontendDeleteRequest{}, + "/cloudbroker/lb/get": lb_cb.GetRequest{}, + "/cloudbroker/lb/makeHighlyAvailable": lb_cb.HighlyAvailableRequest{}, + "/cloudbroker/lb/list": lb_cb.ListRequest{}, + "/cloudbroker/lb/listDeleted": lb_cb.ListDeletedRequest{}, + "/cloudbroker/lb/restart": lb_cb.RestartRequest{}, + "/cloudbroker/lb/restore": lb_cb.RestoreRequest{}, + "/cloudbroker/lb/start": lb_cb.StartRequest{}, + "/cloudbroker/lb/stop": lb_cb.StopRequest{}, + "/cloudbroker/lb/update": lb_cb.UpdateRequest{}, + "/cloudbroker/lb/updateSysctlParams": lb_cb.UpdateSysctParamsRequest{}, + + // node + "/cloudbroker/node/applyIpmiAction": node_cb.ApplyIpmiActionRequest{}, + "/cloudbroker/node/consumption": node_cb.ConsumptionRequest{}, + "/cloudbroker/node/decommission": node_cb.DecommissionRequest{}, + "/cloudbroker/node/enable": node_cb.EnableRequest{}, + "/cloudbroker/node/enableNodes": node_cb.EnableNodesRequest{}, + "/cloudbroker/node/get": node_cb.GetRequest{}, + "/cloudbroker/node/list": node_cb.ListRequest{}, + "/cloudbroker/node/maintenance": node_cb.MaintenanceRequest{}, + "/cloudbroker/node/restrict": node_cb.RestrictRequest{}, + "/cloudbroker/node/setCoreIsolation": node_cb.SetCoreIsolationRequest{}, + "/cloudbroker/node/setHugePages": node_cb.SetHugePagesRequest{}, + "/cloudbroker/node/setsriovstatus": node_cb.SetSRIOVStatusRequest{}, + "/cloudbroker/node/setVFsNumber": node_cb.SetVFsNumberRequest{}, + "/cloudbroker/node/update": node_cb.UpdateRequest{}, + + // pcidevice + "/cloudbroker/pcidevice/create": pcidevice_cb.CreateRequest{}, + "/cloudbroker/pcidevice/delete": pcidevice_cb.DeleteRequest{}, + "/cloudbroker/pcidevice/disable": pcidevice_cb.DisableRequest{}, + "/cloudbroker/pcidevice/enable": pcidevice_cb.EnableRequest{}, + "/cloudbroker/pcidevice/list": pcidevice_cb.ListRequest{}, + + // rg + "/cloudbroker/rg/accessGrant": rg_cb.AccessGrantRequest{}, + "/cloudbroker/rg/accessRevoke": rg_cb.AccessRevokeRequest{}, + "/cloudbroker/rg/affinityGroupComputes": rg_cb.AffinityGroupComputesRequest{}, + "/cloudbroker/rg/affinityGroupsGet": rg_cb.AffinityGroupsGetRequest{}, + "/cloudbroker/rg/affinityGroupsList": rg_cb.AffinityGroupsListRequest{}, + "/cloudbroker/rg/audits": rg_cb.AuditsRequest{}, + "/cloudbroker/rg/create": rg_cb.CreateRequest{}, + "/cloudbroker/rg/delete": rg_cb.DeleteRequest{}, + "/cloudbroker/rg/disable": rg_cb.DisableRequest{}, + "/cloudbroker/rg/enable": rg_cb.EnableRequest{}, + "/cloudbroker/rg/get": rg_cb.GetRequest{}, + "/cloudbroker/rg/getResourceConsumption": rg_cb.GetResourceConsumptionRequest{}, + "/cloudbroker/rg/list": rg_cb.ListRequest{}, + "/cloudbroker/rg/listComputes": rg_cb.ListComputesRequest{}, + "/cloudbroker/rg/listDeleted": rg_cb.ListDeletedRequest{}, + "/cloudbroker/rg/listLb": rg_cb.ListLBRequest{}, + "/cloudbroker/rg/listPFW": rg_cb.ListPFWRequest{}, + "/cloudbroker/rg/listResourceConsumption": EmptyStruct{}, + "/cloudbroker/rg/listVins": rg_cb.ListVINSRequest{}, + "/cloudbroker/rg/massDelete": rg_cb.MassDeleteRequest{}, + "/cloudbroker/rg/massDisable": rg_cb.MassDisableRequest{}, + "/cloudbroker/rg/massEnable": rg_cb.MassEnableRequest{}, + "/cloudbroker/rg/restore": rg_cb.RestoreRequest{}, + "/cloudbroker/rg/setCpuAllocationParameter": rg_cb.SetCPUAllocationParameterRequest{}, + "/cloudbroker/rg/setCpuAllocationRatio": rg_cb.SetCPUAllocationRatioRequest{}, + "/cloudbroker/rg/setDefNet": rg_cb.SetDefNetRequest{}, + "/cloudbroker/rg/update": rg_cb.UpdateRequest{}, + "/cloudbroker/rg/updateComputeFeatures": rg_cb.UpdateComputeFeaturesRequest{}, + "/cloudbroker/rg/updateResourceTypes": rg_cb.UpdateResourceTypesRequest{}, + "/cloudbroker/rg/usage": rg_cb.UsageRequest{}, + + // sep + "/cloudbroker/sep/accessGrant": sep_cb.AccessGrantRequest{}, + "/cloudbroker/sep/accessGrantToPool": sep_cb.AccessGrantToPoolRequest{}, + "/cloudbroker/sep/accessRevoke": sep_cb.AccessRevokeRequest{}, + "/cloudbroker/sep/accessRevokeToPool": sep_cb.AccessRevokeToPoolRequest{}, + "/cloudbroker/sep/addConsumerNodes": sep_cb.AddConsumerNodesRequest{}, + "/cloudbroker/sep/addPool": sep_cb.AddPoolRequest{}, + "/cloudbroker/sep/addProviderNodes": sep_cb.AddProviderNodesRequest{}, + "/cloudbroker/sep/configFieldEdit": sep_cb.ConfigFieldEditRequest{}, + "/cloudbroker/sep/configInsert": sep_cb.ConfigInsertRequest{}, + "/cloudbroker/sep/configValidate": sep_cb.ConfigValidateRequest{}, + "/cloudbroker/sep/consumption": sep_cb.ConsumptionRequest{}, + "/cloudbroker/sep/create": sep_cb.CreateRequest{}, + "/cloudbroker/sep/decommission": sep_cb.DecommissionRequest{}, + "/cloudbroker/sep/delConsumerNodes": sep_cb.DelConsumerNodesRequest{}, + "/cloudbroker/sep/delete": sep_cb.DeleteRequest{}, + "/cloudbroker/sep/delPool": sep_cb.DelPoolRequest{}, + "/cloudbroker/sep/disable": sep_cb.DisableRequest{}, + "/cloudbroker/sep/diskList": sep_cb.DiskListRequest{}, + "/cloudbroker/sep/enable": sep_cb.EnableRequest{}, + "/cloudbroker/sep/get": sep_cb.GetRequest{}, + "/cloudbroker/sep/getConfig": sep_cb.GetConfigRequest{}, + "/cloudbroker/sep/getPool": sep_cb.GetPoolRequest{}, + "/cloudbroker/sep/list": sep_cb.ListRequest{}, + "/cloudbroker/sep/updateCapacityLimit": sep_cb.UpdateCapacityLimitRequest{}, + + // stack + "/cloudbroker/stack/get": stack_cb.GetRequest{}, + "/cloudbroker/stack/getLogicalCoresCount": stack_cb.GetLogicalCoresCountRequest{}, + "/cloudbroker/stack/list": stack_cb.ListRequest{}, + "/cloudbroker/stack/setCpuAllocationRatio": stack_cb.SetCpuAllocationRatioRequest{}, + "/cloudbroker/stack/setMemAllocationRatio": stack_cb.SetMemAllocationRatioRequest{}, + + // tasks + "/cloudbroker/tasks/get": tasks_cb.GetRequest{}, + "/cloudbroker/tasks/list": tasks_cb.ListRequest{}, + + // user + "/cloudbroker/user/apiaccessJoin": user_cb.APIAccessJoinRequest{}, + "/cloudbroker/user/apiaccessLeave": user_cb.APIAccessLeaveRequest{}, + "/cloudbroker/user/apiaccessList": user_cb.APIAccessListRequest{}, + "/cloudbroker/user/apiList": user_cb.APIListRequest{}, + "/cloudbroker/user/create": user_cb.CreateRequest{}, + "/cloudbroker/user/delete": user_cb.DeleteRequest{}, + "/cloudbroker/user/deleteByGuid": user_cb.DeleteByGUIDRequest{}, + "/cloudbroker/user/deleteUsers": user_cb.DeleteUsersRequest{}, + "/cloudbroker/user/get": user_cb.GetRequest{}, + "/cloudbroker/user/getAudit": user_cb.GetAuditRequest{}, + "/cloudbroker/user/getMatchingUsernames": user_cb.GetMatchingUsernamesRequest{}, + "/cloudbroker/user/list": user_cb.ListRequest{}, + + // vfpool + "/cloudbroker/vfpool/create": vfpool_cb.CreateRequest{}, + "/cloudbroker/vfpool/delete": vfpool_cb.DeleteRequest{}, + "/cloudbroker/vfpool/disable": vfpool_cb.DisableRequest{}, + "/cloudbroker/vfpool/enable": vfpool_cb.EnableRequest{}, + "/cloudbroker/vfpool/get": vfpool_cb.GetRequest{}, + "/cloudbroker/vfpool/list": vfpool_cb.ListRequest{}, + "/cloudbroker/vfpool/update": vfpool_cb.UpdateRequest{}, + + // vgpu + "/cloudbroker/vgpu/allocate": vgpu_cb.AllocateRequest{}, + "/cloudbroker/vgpu/create": vgpu_cb.CreateRequest{}, + "/cloudbroker/vgpu/deallocate": vgpu_cb.DeallocateRequest{}, + "/cloudbroker/vgpu/destroy": vgpu_cb.DestroyRequest{}, + "/cloudbroker/vgpu/list": vgpu_cb.ListRequest{}, + + // vins + "/cloudbroker/vins/audits": vins_cb.AuditsRequest{}, + "/cloudbroker/vins/createInAccount": vins_cb.CreateInAccountRequest{}, + "/cloudbroker/vins/createInRG": vins_cb.CreateInRGRequest{}, + "/cloudbroker/vins/defaultQosUpdate": vins_cb.DefaultQOSUpdateRequest{}, + "/cloudbroker/vins/delete": vins_cb.DeleteRequest{}, + "/cloudbroker/vins/disable": vins_cb.DisableRequest{}, + "/cloudbroker/vins/dnsApply": vins_cb.DNSApplyRequest{}, + "/cloudbroker/vins/enable": vins_cb.EnableRequest{}, + "/cloudbroker/vins/extNetConnect": vins_cb.ExtNetConnectRequest{}, + "/cloudbroker/vins/extNetDisconnect": vins_cb.ExtNetDisconnectRequest{}, + "/cloudbroker/vins/extNetList": vins_cb.ExtNetListRequest{}, + "/cloudbroker/vins/get": vins_cb.GetRequest{}, + "/cloudbroker/vins/ipList": vins_cb.IPListRequest{}, + "/cloudbroker/vins/ipRelease": vins_cb.IPReleaseRequest{}, + "/cloudbroker/vins/ipReserve": vins_cb.IPReserveRequest{}, + "/cloudbroker/vins/list": vins_cb.ListRequest{}, + "/cloudbroker/vins/listDeleted": vins_cb.ListDeletedRequest{}, + "/cloudbroker/vins/massDelete": vins_cb.MassDeleteRequest{}, + "/cloudbroker/vins/massDisable": vins_cb.MassDisableRequest{}, + "/cloudbroker/vins/massEnable": vins_cb.MassEnableRequest{}, + "/cloudbroker/vins/natRuleAdd": vins_cb.NATRuleAddRequest{}, + "/cloudbroker/vins/natRuleDel": vins_cb.NATRuleDelRequest{}, + "/cloudbroker/vins/natRuleList": vins_cb.NATRuleListRequest{}, + "/cloudbroker/vins/netQos": vins_cb.NetQOSRequest{}, + "/cloudbroker/vins/raiseDown": EmptyStruct{}, + "/cloudbroker/vins/restore": vins_cb.RestoreRequest{}, + "/cloudbroker/vins/search": vins_cb.SearchRequest{}, + "/cloudbroker/vins/staticRouteAccessGrant": vins_cb.StaticRouteAccessGrantRequest{}, + "/cloudbroker/vins/staticRouteAccessRevoke": vins_cb.StaticRouteAccessRevokeRequest{}, + "/cloudbroker/vins/staticRouteAdd": vins_cb.StaticRouteAddRequest{}, + "/cloudbroker/vins/staticRouteDel": vins_cb.StaticRouteDelRequest{}, + "/cloudbroker/vins/staticRouteList": vins_cb.StaticRouteListRequest{}, + "/cloudbroker/vins/vnfdevRedeploy": vins_cb.VNFDevRedeployRequest{}, + "/cloudbroker/vins/vnfdevRestart": vins_cb.VNFDevRestartRequest{}, + "/cloudbroker/vins/vnfdevReset": vins_cb.VNFDevResetRequest{}, + "/cloudbroker/vins/vnfdevStart": vins_cb.VNFDevStartRequest{}, + "/cloudbroker/vins/vnfdevStop": vins_cb.VNFDevStopRequest{}, + } +} diff --git a/tests/platform_upgrade/utils_get_list.go b/tests/platform_upgrade/utils_get_list.go new file mode 100644 index 0000000..01ca31b --- /dev/null +++ b/tests/platform_upgrade/utils_get_list.go @@ -0,0 +1,261 @@ +package test + +import ( + "encoding/json" + "fmt" + "log" + "os" + "reflect" + "strconv" + "testing" + "time" + + "github.com/joho/godotenv" + decort "repository.basistech.ru/BASIS/decort-golang-sdk" + "repository.basistech.ru/BASIS/decort-golang-sdk/config" +) + +func getClient() (*decort.DecortClient, error) { + cfg := config.Config{ + Retries: 5, + SSLSkipVerify: true, + } + + err := godotenv.Load(".env") + if err != nil { + log.Fatal("Error loading .env file") + } + + appID, ok := os.LookupEnv("AppID") + if !ok { + return &decort.DecortClient{}, fmt.Errorf("AppID is not set") + } + cfg.AppID = appID + + AppSecret, ok := os.LookupEnv("AppSecret") + if !ok { + return &decort.DecortClient{}, fmt.Errorf("AppSecret is not set") + } + cfg.AppSecret = AppSecret + + SSOURL, ok := os.LookupEnv("SSOURL") + if !ok { + return &decort.DecortClient{}, fmt.Errorf("SSOURL is not set") + } + cfg.SSOURL = SSOURL + + DecortURL, ok := os.LookupEnv("DecortURL") + if !ok { + return &decort.DecortClient{}, fmt.Errorf("DecortURL is not set") + } + cfg.DecortURL = DecortURL + + cfg.SetTimeout(5 * time.Minute) + c := decort.New(cfg) + return c, nil +} + +// getResult checks how json-structure of bytes is different from golang structure and return t.Error if there are any differences. +func getResult(testName string, bytes []byte, structure any, t *testing.T) { + // convert bytes to map[string]interface{} + bytesMap, err := GetMapFromBytes(bytes) + if err != nil { + t.Errorf("%s: can not unmarshal json", testName) + } + + // convert structure to map[string]interface{} + structMap := GetMapFromStructure(structure) + + // assert if they are equal + if !reflect.DeepEqual(bytesMap, structMap) { + t.Errorf(getDifference(testName, bytesMap, structMap)) + } +} + +// 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) + 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(bytesFields) == 0 { + result += "OK" + } + + return result +} + +func evaluate(m1, m2 map[string]interface{}) ([]string, []string) { + var s1, s2 []string + + for k1, v1 := range m1 { + v2, ok := m2[k1] + if !ok { + s1 = append(s1, k1) + continue + } + + v1Map := v1.(map[string]interface{}) + v2Map := v2.(map[string]interface{}) + + len1 := len(v1Map) + len2 := len(v2Map) + + if len1 == 0 && len2 == 0 { + continue + } else { + toAdd1, toAdd2 := evaluate(v1Map, v2Map) + s1 = append(s1, toAdd1...) + s2 = append(s2, toAdd2...) + } + } + + for k2, v2 := range m2 { + v1, ok := m1[k2] + if !ok { + if !contains(s2, k2) { + s2 = append(s2, k2) + } + continue + } + + v1Map := v1.(map[string]interface{}) + v2Map := v2.(map[string]interface{}) + + len1 := len(v1Map) + len2 := len(v2Map) + + if len1 == 0 && len2 == 0 { + continue + } else { + toAdd1, toAdd2 := evaluate(v1Map, v2Map) + s1 = appendSelectedElements(s1, toAdd1) + s2 = appendSelectedElements(s2, toAdd2) + } + } + + return s1, s2 +} + +func contains(slice []string, element string) bool { + for _, elem := range slice { + if elem == element { + return true + } + } + return false +} + +func appendSelectedElements(slice []string, elements []string) []string { + result := make([]string, 0, len(slice)) + result = append(result, slice...) + + for _, el := range elements { + if !contains(slice, el) { + result = append(result, el) + } + } + + return result +} + +// 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) + if err != nil { + return nil, err + } + + return getMapBytes(x), nil +} + +func getMapBytes(value map[string]interface{}) map[string]interface{} { + temporary := make(map[string]interface{}) + for k, v := range value { + list, ok := v.([]interface{}) + if ok && len(list) > 0 { + elem, ok := list[0].(map[string]interface{}) + if ok { + temporary[k] = getMapBytes(elem) + continue + } + temporary[k] = map[string]interface{}{} + continue + } + + m, ok := v.(map[string]interface{}) + if ok { + temporary[k] = getMapBytes(m) + continue + } + + if _, err := strconv.Atoi(k); err != nil { + temporary[k] = map[string]interface{}{} + } + } + + return temporary +} + +// GetMapFromStructure converts golang structure to map[string]interface{} +func GetMapFromStructure(structure any) map[string]interface{} { + typ := reflect.TypeOf(structure) + + return getMapStruct(typ) +} + +func getMapStruct(t reflect.Type) map[string]interface{} { + temporary := make(map[string]interface{}) + for i := 0; i < t.NumField(); i++ { + tag := t.Field(i).Tag.Get("json") + kind := t.Field(i).Type.Kind() + + //nolint + switch kind { + case reflect.Array, reflect.Slice: + elem := t.Field(i).Type.Elem() + switch elem.Kind() { + case reflect.Struct: + temporary[tag] = getMapStruct(elem) + default: + temporary[tag] = map[string]interface{}{} + } + + case reflect.Struct: + if tag == "" { + return getMapStruct(t.Field(i).Type) + } else { + temporary[tag] = getMapStruct(t.Field(i).Type) + } + // в этом месте работает некорректно для вложенных структур без json тегов (scope - все в cloudbroker) + + case reflect.Map, reflect.Interface, reflect.String, reflect.Bool, reflect.Int64, reflect.Int, reflect.Uint, + reflect.Int32, reflect.Uint64, reflect.Float32, reflect.Float64: + temporary[tag] = map[string]interface{}{} + } + } + + return temporary +} + +// getMapFromFile converts json to map[string]interface{} +func getMapFromFile(bytes []byte) (map[string]interface{}, error) { + var x map[string]interface{} + err := json.Unmarshal(bytes, &x) + if err != nil { + return nil, err + } + + paths := x["paths"].(map[string]interface{}) + + return paths, nil +} diff --git a/tests/platform_upgrade/utils_requests.go b/tests/platform_upgrade/utils_requests.go new file mode 100644 index 0000000..c25d795 --- /dev/null +++ b/tests/platform_upgrade/utils_requests.go @@ -0,0 +1,218 @@ +package test + +import ( + "fmt" + "io" + "os" + "reflect" + "strings" + "testing" +) + +func getParameters(input map[string]interface{}) []interface{} { + var emptySlice []interface{} + post, ok := input["post"] + if !ok { + return emptySlice + } + + parameters, ok := post.(map[string]interface{}) + if !ok { + return emptySlice + } + + params, ok := parameters["parameters"] + if !ok { + return emptySlice + } + + res, ok := params.([]interface{}) + if !ok { + return emptySlice + } + + return res +} + +func getBytesFromJSON(fileName string, t *testing.T) []byte { + jsonFile, err := os.Open(fileName) + if err != nil { + t.Error(err) + } + defer jsonFile.Close() + + bytes, err := io.ReadAll(jsonFile) + if err != nil { + t.Error(err) + } + + return bytes +} + +func getErrorsFromJSON(bytes []byte, t *testing.T, cloud string) { + var requests map[string]interface{} + + switch cloud { + case "cloudapi": + requests = getRequestsMapCloudAPI() + case "cloudbroker": + requests = getRequestsMapCloudbroker() + default: + t.Fatalf("Wrong cloud provided, expected `cloudapi` or `cloudbroker`, got %s", cloud) + } + + paths, err := getMapFromFile(bytes) + if err != nil { + t.Error(err) + } + i := 0 + for k, v := range paths { + // exclude deprecated urls from analysis + if !validateUrlFromJson(k) { + continue + } + + params := getParameters(v.(map[string]interface{})) + structure, ok := requests[k] + if !ok { + continue + } + i++ + typStruct := reflect.TypeOf(structure) + + var errs []string + // empty request case + if len(params) == 0 && structure == nil { + continue + } + if len(params) != typStruct.NumField() { + errs = append(errs, fmt.Sprintf("Platform (%d) and golang structure (%d) have different amount of fields.", len(params), typStruct.NumField())) + } + for _, p := range params { + param, ok := p.(map[string]interface{}) + if !ok { + continue + } + + name := param["name"].(string) + required := param["required"].(bool) + typ := p.(map[string]interface{})["type"].(string) + + var items string + if p.(map[string]interface{})["items"] != nil { + itemsTemp := p.(map[string]interface{})["items"] + if itemsTemp != nil { + itemsType := itemsTemp.(map[string]interface{})["type"] + if itemsType != nil { + items = itemsType.(string) + } + } + } + + var found bool + for i := 0; i < typStruct.NumField(); i++ { + jsonTag := typStruct.Field(i).Tag.Get("json") + validation, _ := typStruct.Field(i).Tag.Lookup("validate") + + if checkName(name, jsonTag) { + if !checkRequired(required, validation, typ) { + errs = append(errs, fmt.Sprintf("Field %s has different required parameters on the platform and in golang structure", name)) + } + if !checkKind(typ, items, typStruct.Field(i).Type) { + errs = append(errs, fmt.Sprintf("Field %s has different type parameters on the platform and in golang structure", name)) + } + found = true + break + } + } + + if !found { + errs = append(errs, fmt.Sprintf("Platform has field %s that golang structure doesn't", name)) + } + } + if len(errs) > 0 { + t.Errorf("Path %s has following errors: %v", k, errs) + } + } + + if len(requests) != i { + t.Errorf("Amount of structure checked (%d) is not the same as amount of platform requests available (%d), please check getRequestsMapCloudAPI func in code.", + i, len(requests)) + } +} + +// checkName checks if name field from platform has the same value as json tag in golang structure (maybe including omitempty) +func checkName(name, tag string) bool { + return strings.Contains(tag, name) +} + +// checkRequired checks if required field from platform has the same value as validate tag in golang structure +func checkRequired(required bool, validation, fieldType string) bool { + if required && strings.Contains(validation, "required") { + return true + } + if required && (!strings.Contains(validation, "omitempty") && validation != "") { + return true + } + if !required && (validation == "" || strings.Contains(validation, "omitempty")) { + return true + } + + if fieldType == "boolean" { + return true // otherwise we have issues with setting false/true + } + + return false +} + +// checkKind checks if type field from platform has the same value as field type in golang structure +func checkKind(platformType, items string, typ reflect.Type) bool { + //nolint + switch typ.Kind() { + case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int8, reflect.Int16, reflect.Uint, reflect.Uint64, reflect.Uint16, reflect.Uint32, reflect.Uint8: + if platformType == "integer" { + return true + } + return false + + case reflect.String: + if platformType == "string" { + return true + } + return false + + case reflect.Bool: + if platformType == "boolean" { + return true + } + return false + + case reflect.Float32, reflect.Float64: + if platformType == "number" { + return true + } + return false + + case reflect.Array, reflect.Slice: + if platformType != "array" { + return false + } + + elem := typ.Elem() + switch elem.Kind() { + case reflect.String: + if items == "string" { + return true + } + return false + + case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int8, reflect.Int16, reflect.Uint, reflect.Uint64, reflect.Uint16, reflect.Uint32, reflect.Uint8: + if items == "integer" { + return true + } + return false + } + } + + return false +} diff --git a/tests/platform_upgrade/utils_urls.go b/tests/platform_upgrade/utils_urls.go new file mode 100644 index 0000000..4c5739c --- /dev/null +++ b/tests/platform_upgrade/utils_urls.go @@ -0,0 +1,171 @@ +package test + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +// DEPRECATED_GROUPS stores API groups that are deprecated and therefore are not supported in further developement +var DEPRECATED_GROUPS = []string{ + "/cloudapi/machine/", + "/cloudapi/cloudspace/", + "/cloudapi/prometheus/", + "//cloudbroker/pgpu/", + "/cloudapi/gpu/", + "/cloudapi/portforwarding/", + "/cloudapi/account/listVMs", + "/cloudapi/account/listCS", + "/cloudapi/account/getStats", + "/cloudapi/vgpu/list", + + "/cloudbroker/account/listVMs", + "/cloudbroker/account/listCS", + "/cloudbroker/machine/", + "/cloudbroker/bservice/", + "/cloudbroker/prometheus/", + "/cloudbroker/auditcollector/", + "/cloudbroker/health/", + "/cloudbroker/metering/", + "/cloudbroker/cloudspace/", + "/cloudbroker/vnfdev/", + "/cloudbroker/auditbeat/", + "/cloudbroker/zeroaccess/", + "/cloudbroker/qos/", + "/cloudbroker/backupcreator/", + "/cloudbroker/resmon/", + "/cloudbroker/pgpu/", + "/cloudbroker/job/", + "/cloudbroker/tlock/", + "/cloudbroker/eco/", + "/cloudbroker/iaas/", + "/cloudbroker/diagnostics/", + "/cloudbroker/milestones/", +} + +// getUrlsFromBytes converts bytes to array of urls strings +func getUrlsFromBytes(bytes []byte) ([]string, error) { + paths, err := getMapFromFile(bytes) + if err != nil { + return nil, err + } + + urls := make([]string, 0, len(paths)) + for p := range paths { + if validateUrlFromJson(p) { + urls = append(urls, p) + } + } + + return urls, nil +} + +func validateUrlFromJson(url string) bool { + if !strings.HasPrefix(url, "/cloudapi/") && !strings.HasPrefix(url, "/cloudbroker/") { + return false + } + + for _, deprecated := range DEPRECATED_GROUPS { + if strings.Contains(url, deprecated) { + return false + } + } + + return true +} + +// getMissingDecortUrls returns array of url strings that are present in json swagger docs and absent in decort-sdk handlers. +func getMissingDecortUrls(jsonUrls, decortUrls []string) []string { + result := make([]string, 0, len(jsonUrls)) + for _, jsonUrl := range jsonUrls { + var found bool + for _, decortUrl := range decortUrls { + if jsonUrl == decortUrl { + found = true + break + } + } + + if !found { + result = append(result, jsonUrl) + } + } + + return result +} + +// readUrlFromDir reads all url addresses from given directory and its subdirectories and subfiles and returns array of urls found. Capacity will +func readUrlFromDir(dirName string, capacity int) []string { + result := make([]string, 0, capacity) + + items, _ := os.ReadDir(dirName) + + for _, item := range items { + itemName := dirName + "/" + item.Name() + if item.IsDir() { + subitems, _ := os.ReadDir(itemName) + + for _, subitem := range subitems { + subName := itemName + "/" + subitem.Name() + files, _ := os.ReadDir(subName) + if item.IsDir() { + for _, file := range files { + fileName := dirName + "/" + item.Name() + "/" + subitem.Name() + "/" + file.Name() + if !file.IsDir() { + url, err := readUrlFromFile(fileName) + if err != nil { + continue + } + result = append(result, url...) + } + } + } + + if !subitem.IsDir() { + url, err := readUrlFromFile(subName) + if err != nil { + continue + } + result = append(result, url...) + } + } + + } else { + url, err := readUrlFromFile(itemName) + if err != nil { + continue + } + result = append(result, url...) + + } + } + return result +} + +// readUrlFromFile reads url address of format url := "/cloudapi/vins/audits" or url := "/cloudbroker/vins/audits" from file with name fileName. +func readUrlFromFile(fileName string) ([]string, error) { + var result []string + file, err := os.Open(fileName) + if err != nil { + return nil, err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + if strings.Contains(scanner.Text(), `"/cloudapi/`) { + indexStart := strings.Index(scanner.Text(), "/cloudapi/") + result = append(result, strings.TrimRight(scanner.Text()[indexStart:], `"`)) + } + if strings.Contains(scanner.Text(), `"/cloudbroker/`) { + indexStart := strings.Index(scanner.Text(), "/cloudbroker/") + result = append(result, strings.TrimRight(scanner.Text()[indexStart:], `"`)) + } + } + + if len(result) == 0 { + return nil, fmt.Errorf("file %s doesn't contain any url", fileName) + } + return result, nil +}