Compare commits

...

28 Commits

Author SHA1 Message Date
7de095302b v1.5.5 2023-08-25 13:53:43 +03:00
a3711057ba v1.5.4 2023-08-22 15:28:39 +03:00
1c59ca338a v1.5.3 2023-08-15 11:42:30 +03:00
f1529c9aac v1.5.2 2023-08-09 19:33:50 +03:00
040235f92f v1.5.1 2023-07-24 18:13:52 +03:00
4a152cb44c v1.5.0 2023-07-24 16:43:10 +03:00
c78b1348e3 v1.5.0 2023-07-24 15:13:04 +03:00
8f152a2f63 v1.5.0 2023-07-21 15:14:10 +03:00
0be4d8fb0c v1.5.0-epsilon 2023-07-13 18:32:21 +03:00
Никита Сорокин
5025a17ea4 v1.5.0-delta 2023-07-13 15:28:07 +03:00
7c787f6fce v1.5.0-gamma2 2023-07-07 12:40:03 +03:00
20fd7ab50c v1.5.0-gamma-qf 2023-06-30 11:24:26 +03:00
f50f71ab0d v1.5.0-gamma 2023-06-30 11:21:47 +03:00
29c7f143fe v1.4.7 2023-06-29 15:52:49 +03:00
264538f492 v1.4.6 2023-06-23 15:13:22 +03:00
c06a3198f6 v1.4.5 2023-06-19 15:06:31 +03:00
c9e4ae6afe v1.4.4 2023-06-01 16:50:10 +03:00
2a1593f45f v1.5.0-beta 2023-05-18 13:55:28 +03:00
190f24dac1 v1.4.3 2023-05-18 13:37:48 +03:00
256dba5134 v1.5.0-alfa 2023-05-15 19:27:02 +03:00
b7137683ab v1.4.2 2023-05-15 10:55:36 +03:00
10e3e19892 v1.4.1 2023-05-04 16:15:35 +03:00
aaf0857ff0 v1.4.0 2023-04-28 11:46:58 +03:00
7d6cda7119 v1.3.1 2023-04-20 11:17:35 +03:00
84b64b7d80 v1.3.0 2023-03-24 17:09:30 +03:00
437841c8dd update go.mod and imports 2023-03-17 12:54:34 +03:00
f3a1a4c83f v1.2.1 2023-03-14 14:45:51 +03:00
stSolo
42800ac4fe v1.2.0 2023-03-01 19:05:53 +03:00
891 changed files with 24617 additions and 10068 deletions

4
.gitignore vendored
View File

@@ -1 +1,3 @@
cmd/ cmd/
.idea/
.vscode/

View File

@@ -1,54 +1,5 @@
## Version 1.1.2 ## Version 1.5.5
### Feature ### Bugfix
- Added missing field cloudbroker/sep/RecordPool/UsageLimit
#### Cloudbroker - Fixed the field cloudbroker/sep/RecordConsumption/ByPool
- Disks
- Add share method
- Add unshare method
### Bug fixes
#### CloudAPI
- Account/Create
- Change the MaxMemoryCapacity field type to int64
- Change the MaxVDiskCapacity field type to int64
- Change the MaxCPUCapacity field type to int64
- Change the MaxNetworkPeerTransfer field type to int64
- Change the MaxNumPublicIP field type to int64
- Change the GPUUnits field type to int64
- Change url to cloudapi
- Account/Models
- Change the DiskSize field type to float64
- Change the DiskSizeMax field type to uint64
- RG/Create
- Change the MaxMemoryCapacity field type to int64
- Change the MaxVDiskCapacity field type to int64
- Change the MaxCPUCapacity field type to int64
- Change the MaxNumPublicIP field type to int64
- RG/Models
- Change the DiskSize field type to float64
- Change the DiskSizeMax field type to uint64
#### Cloudbroker
- Account/Create
- Change the MaxMemoryCapacity field type to int64
- Change the MaxVDiskCapacity field type to int64
- Change the MaxCPUCapacity field type to int64
- Change the MaxNetworkPeerTransfer field type to int64
- Change the MaxNumPublicIP field type to int64
- Change the GPUUnits field type to int64
- Account/Models
- Change the DiskSize field type to float64
- Change the DiskSizeMax field type to uint64
- RG/Create
- Change the MaxMemoryCapacity field type to int64
- Change the MaxVDiskCapacity field type to int64
- Change the MaxCPUCapacity field type to int64
- Change the MaxNumPublicIP field type to int64
- RG/Models
- Change the DiskSize field type to float64
- Change the DiskSizeMax field type to uint64

View File

@@ -1,5 +1,10 @@
.PHONY: lint all: lint test
lint: .PHONY: all
golangci-lint run --timeout 600s
lint:
.DEFAULT_GOAL := lint golangci-lint run --timeout 600s
test:
go test -v -failfast -timeout 600s ./...
.DEFAULT_GOAL := lint

480
README.md
View File

@@ -3,8 +3,13 @@
Decort SDK - это библиотека, написанная на языке GO, позволяющая взаимодействовать с API облачной платформы **DECORT**. Библиотека содеражит в себе структуры и методы, необходимые для отправки запросов. Decort SDK имеет встроенный http-клиент и поддерживает разные способы авторизации на платформе. Библиотека так же содержит в себе модели ответов от платформы. Decort SDK - это библиотека, написанная на языке GO, позволяющая взаимодействовать с API облачной платформы **DECORT**. Библиотека содеражит в себе структуры и методы, необходимые для отправки запросов. Decort SDK имеет встроенный http-клиент и поддерживает разные способы авторизации на платформе. Библиотека так же содержит в себе модели ответов от платформы.
## Версии ## Версии
- Версия 1.0.0 Decort-SDK соответствует 3.8.4 версии платформы
- Версия 1.1.0 Decort-SDK соответствует 3.8.5 версии платформы - Версия 1.0.x Decort-SDK соответствует 3.8.4 версии платформы
- Версия 1.1.x Decort-SDK соответствует 3.8.5 версии платформы
- Версия 1.2.x Decort-SDK соответствует 3.8.5 версии платформы
- Версия 1.3.x Decort-SDK соответствует 3.8.5 версии платформы
- Версия 1.4.x Decort-SDK соответствует 3.8.6 версии платформы
- Версия 1.5.x Decort-SDK соответствует 3.8.7 версии платформы
## Оглавление ## Оглавление
@@ -14,16 +19,32 @@ Decort SDK - это библиотека, написанная на языке G
- [Cloudbroker](#cloudbroker) - [Cloudbroker](#cloudbroker)
- [Работа с библиотекой](#работа-с-библиотекой) - [Работа с библиотекой](#работа-с-библиотекой)
- [Настройка конфигурации клиента](#настройка-конфигурации-клиента) - [Настройка конфигурации клиента](#настройка-конфигурации-клиента)
- [Пример конфигурации клиента](#пример-конфигурации-клиента)
- [Парсинг конфигурации из файла](#парсинг-конфигурации-из-файла)
- [Пример JSON конфигурации](#пример-json-конфигурации)
- [Пример YAML конфигурации](#пример-yaml-конфигурации)
- [Создание клиента](#создание-клиента) - [Создание клиента](#создание-клиента)
- [Создание структуры запроса](#cоздание-структуры-запроса) - [Создание структуры запроса](#cоздание-структуры-запроса)
- [Выполнение запроса](#выполнение-запроса) - [Выполнение запроса](#выполнение-запроса)
- [Фильтрация](#фильтрация)
- [Сортировка](#сортировка)
- [Сериализация](#сериализация)
- [Работа с legacy клиентом](#работа-с-legacy-клиентом)
- [Настройка конфигурации legacy клиента](#настройка-конфигурации-legacy-клиента)
- [Пример конфигурации legacy клиента](#пример-конфигурации-legacy-клиента)
- [Парсинг legacy конфигурации из файла](#парсинг-legacy-конфигурации-из-файла)
- [Пример legacy JSON конфигурации](#пример-legacy-json-конфигурации)
- [Пример legacy YAML конфигурации](#пример-legacy-yaml-конфигурации)
- [Создание legacy клиента](#создание-legacy-клиента)
- [Создание структуры запроса](#cоздание-структуры-запроса)
- [Выполнение запроса](#выполнение-запроса)
## Установка ## Установка
Выполните команду в терминале: Выполните команду в терминале:
```bash ```bash
go get -u github.com/rudecs/decort-sdk go get -u repository.basistech.ru/BASIS/decort-golang-sdk
``` ```
## Список API ## Список API
@@ -83,9 +104,10 @@ go get -u github.com/rudecs/decort-sdk
Алгоритм работы с библиотекой выглядит следующим образом: Алгоритм работы с библиотекой выглядит следующим образом:
1. Настройка конфигурации клиента. 1. Настройка конфигурации клиента.
2. Создание клиента. 2. Парсинг конфигурации из файла.
3. Создание структуры запроса. 3. Создание клиента.
4. Выполнение запроса. 4. Создание структуры запроса.
5. Выполнение запроса.
### Настройка конфигурации клиента ### Настройка конфигурации клиента
@@ -97,15 +119,17 @@ go get -u github.com/rudecs/decort-sdk
| SSOURL | string | Да | URL адрес сервиса аутентификации и авторизации | | SSOURL | string | Да | URL адрес сервиса аутентификации и авторизации |
| DecortURL | string | Да | URL адрес платформы, с которой будет осуществляться взаимодействие | | DecortURL | string | Да | URL адрес платформы, с которой будет осуществляться взаимодействие |
| Retries | uint | Нет | Кол-во неудачных попыток выполнения запроса, по умолчанию - 5 | | Retries | uint | Нет | Кол-во неудачных попыток выполнения запроса, по умолчанию - 5 |
| Timeout | config.Duration | Нет | Таймаут HTTP клиента, по умолчанию - без ограничений |
| SSLSkipVerify | bool | Нет | Пропуск проверки подлинности сертификата, по умолчанию - true | | SSLSkipVerify | bool | Нет | Пропуск проверки подлинности сертификата, по умолчанию - true |
| Token | string | Нет | JWT токен | | Token | string | Нет | JWT токен |
Пример кода: #### Пример конфигурации клиента
```go ```go
import ( import (
"github.com/rudecs/decort-sdk/config" "repository.basistech.ru/BASIS/decort-golang-sdk/config"
) )
func main(){ func main(){
// Настройка конфигурации // Настройка конфигурации
cfg := config.Config{ cfg := config.Config{
@@ -115,9 +139,54 @@ func main(){
DecortURL: "https://mr4.digitalenergy.online", DecortURL: "https://mr4.digitalenergy.online",
Retries: 5, Retries: 5,
} }
cfg.SetTimeout(5 * time.Minute)
} }
``` ```
#### Парсинг конфигурации из файла
Также возможно создать переменную конфигурации из JSON или YAML файла, используя функцию `ParseConfigJSON` (или `ParseConfigYAML`) из пакета config.
<br>
*См. пример файлов конфигурации ниже и в директории `samples/`.*
```go
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
)
func main() {
// Парсинг конфигурации из JSON-файла
cfg := config.ParseConfigJSON("<PATH>")
}
```
#### Пример JSON конфигурации
```json
{
"appId": "<APP_ID>",
"appSecret": "<APP_SECRET>",
"ssoUrl": "https://sso.digitalenergy.online",
"decortUrl": "https://mr4.digitalenergy.online",
"retries": 5,
"timeout": "5m",
"sslSkipVerify": false
}
```
#### Пример YAML конфигурации
```yaml
appId: <APP_ID>
appSecret: <APP_SECRET>
ssoUrl: https://sso.digitalenergy.online
decortUrl: https://mr4.digitalenergy.online
retries: 5
timeout: 5m
sslSkipVerify: false
```
### Создание клиента ### Создание клиента
Создание клиента происходит с помощью функции-строителя `New` из основного пакета `decort-sdk`, для избежания проблем с именами, пакету можно присвоить алиас `decort`. Функция принимает конфигурацию, возвращает структуру `DecortClient`, с помощью которой можно взаимодействовать с платформой. Создание клиента происходит с помощью функции-строителя `New` из основного пакета `decort-sdk`, для избежания проблем с именами, пакету можно присвоить алиас `decort`. Функция принимает конфигурацию, возвращает структуру `DecortClient`, с помощью которой можно взаимодействовать с платформой.
@@ -128,8 +197,8 @@ func main(){
package main package main
import ( import (
"github.com/rudecs/decort-sdk/config" "repository.basistech.ru/BASIS/decort-golang-sdk/config"
decort "github.com/rudecs/decort-sdk" decort "repository.basistech.ru/BASIS/decort-golang-sdk"
) )
func main() { func main() {
@@ -142,6 +211,8 @@ func main() {
Retries: 5, Retries: 5,
} }
cfg.SetTimeout(5 * time.Minute)
// Создание клиента // Создание клиента
client := decort.New(cfg) client := decort.New(cfg)
} }
@@ -198,44 +269,44 @@ func main() {
- Обязательный или нет - поле required в комментариях; - Обязательный или нет - поле required в комментариях;
- Доп. информация (допустимые значения, значения по умолчанию). - Доп. информация (допустимые значения, значения по умолчанию).
#### Пример комментарие структуры #### Пример комментариев структуры
```go ```go
type CreateRequest struct { type CreateRequest struct {
// ID of the resource group, which will own this VM // ID of the resource group, which will own this VM
// Required: true // Required: true
RGID uint64 `url:"rgId"` RGID uint64 `url:"rgId" json:"rgId"`
// Name of this VM. // Name of this VM.
// Must be unique among all VMs (including those in DELETED state) in target resource group // Must be unique among all VMs (including those in DELETED state) in target resource group
// Required: true // Required: true
Name string `url:"name"` Name string `url:"name" json:"name"`
// Number CPUs to allocate to this VM // Number CPUs to allocate to this VM
// Required: true // Required: true
CPU uint64 `url:"cpu"` CPU uint64 `url:"cpu" json:"cpu"`
// Volume of RAM in MB to allocate to this VM // Volume of RAM in MB to allocate to this VM
// Required: true // Required: true
RAM uint64 `url:"ram"` RAM uint64 `url:"ram" json:"ram"`
// ID of the OS image to base this VM on; // ID of the OS image to base this VM on;
// Could be boot disk image or CD-ROM image // Could be boot disk image or CD-ROM image
// Required: true // Required: true
ImageID uint64 `url:"imageId"` ImageID uint64 `url:"imageId" json:"imageId"`
// Size of the boot disk in GB // Size of the boot disk in GB
// Required: false // Required: false
BootDisk uint64 `url:"bootDisk,omitempty"` BootDisk uint64 `url:"bootDisk,omitempty" json:"bootDisk,omitempty"`
// ID of SEP to create boot disk on. // ID of SEP to create boot disk on.
// Uses images SEP ID if not set // Uses images SEP ID if not set
// Required: false // Required: false
SEPID uint64 `url:"sepId,omitempty"` SEPID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`
// Pool to use if SEP ID is set, can be also empty if needed to be chosen by system // Pool to use if SEP ID is set, can be also empty if needed to be chosen by system
// Required: false // Required: false
Pool string `url:"pool,omitempty"` Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Network type // Network type
// Should be one of: // Should be one of:
@@ -243,46 +314,46 @@ type CreateRequest struct {
// - EXTNET // - EXTNET
// - NONE // - NONE
// Required: false // Required: false
NetType string `url:"netType,omitempty"` NetType string `url:"netType,omitempty" json:"netType,omitempty"`
// Network ID for connect to, // Network ID for connect to,
// for EXTNET - external network ID, // for EXTNET - external network ID,
// for VINS - VINS ID, // for VINS - VINS ID,
// when network type is not "NONE" // when network type is not "NONE"
// Required: false // Required: false
NetID uint64 `url:"netId,omitempty"` NetID uint64 `url:"netId,omitempty" json:"netId,omitempty"`
// IP address to assign to this VM when connecting to the specified network // IP address to assign to this VM when connecting to the specified network
// Required: false // Required: false
IPAddr string `url:"ipAddr,omitempty"` IPAddr string `url:"ipAddr,omitempty" json:"ipAddr,omitempty"`
// Input data for cloud-init facility // Input data for cloud-init facility
// Required: false // Required: false
Userdata string `url:"userdata,omitempty"` Userdata string `url:"userdata,omitempty" json:"userdata,omitempty"`
// Text description of this VM // Text description of this VM
// Required: false // Required: false
Description string `url:"desc,omitempty"` Description string `url:"desc,omitempty" json:"desc,omitempty"`
// Start VM upon success // Start VM upon success
// Required: false // Required: false
Start bool `url:"start,omitempty"` Start bool `url:"start,omitempty" json:"start,omitempty"`
// Stack ID // Stack ID
// Required: false // Required: false
StackID uint64 `url:"stackId,omitempty"` StackID uint64 `url:"stackId,omitempty" json:"stackId,omitempty"`
// System name // System name
// Required: false // Required: false
IS string `url:"IS,omitempty"` IS string `url:"IS,omitempty" json:"IS,omitempty"`
// Compute purpose // Compute purpose
// Required: false // Required: false
IPAType string `url:"ipaType,omitempty"` IPAType string `url:"ipaType,omitempty" json:"ipaType,omitempty"`
// Reason for action // Reason for action
// Required: false // Required: false
Reason string `url:"reason,omitempty"` Reason string `url:"reason,omitempty" json:"reason,omitempty"`
} }
``` ```
@@ -292,9 +363,9 @@ type CreateRequest struct {
package main package main
import ( import (
"github.com/rudecs/decort-sdk/config" "repository.basistech.ru/BASIS/decort-golang-sdk/config"
decort "github.com/rudecs/decort-sdk" decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"github.com/rudecs/decort-sdk/pkg/cloudapi/kvmx86" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmx86"
) )
func main() { func main() {
@@ -392,9 +463,9 @@ import (
"log" "log"
"fmt" "fmt"
"github.com/rudecs/decort-sdk/config" "repository.basistech.ru/BASIS/decort-golang-sdk/config"
decort "github.com/rudecs/decort-sdk" decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"github.com/rudecs/decort-sdk/pkg/cloudapi/kvmx86" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmx86"
) )
func main() { func main() {
@@ -429,3 +500,342 @@ func main() {
fmt.Println(res) fmt.Println(res)
} }
``` ```
### Фильтрация
Для каждого `ListRequest` в SDK есть группа функций для фильтрации ответа платформы. Для того чтобы произвести фильтрацию по заданным полям, достаточно описать анонимную функцию (предикат) в `.FilterFunc()`, например:
```go
// Создание запроса account/list
req := account.ListRequest{}
resp, err := client.CloudAPI().Account().List(context.Background(), req)
if err != nil {
log.Fatal(err)
}
// Тип filtered - ListAccount, тот же, что и у ответа платформы.
filtered := resp.
FilterFunc(func(ia account.ItemAccount) bool {
// ItemAccount открывает доступ к полям модели ответа платформы.
for _, itemAcl := range ia.ACL {
if itemAcl.UgroupID == "<UserGroupID>" { // Фильтр по ACL/UgroupID
return true
}
}
return false
})
```
Для удобства пользователей, особенно важные фильтры вынесены в отдельные функции, что облегчает фильтрацию сразу по нескольким полям:
```go
// Создание запроса account/list
req := account.ListRequest{}
resp, err := client.CloudAPI().Account().List(context.Background(), req)
if err != nil {
log.Fatal(err)
}
// Несколько фильтров объединены в конвейер
filtered := resp.
FilterByName("<NAME>").
FilterByStatus("<STATUS>")
// ....
```
Также у `compute`, `disks`, и `lb` присутствуют специфические функции фильтрации, отправляющие дополнительные запросы. В качестве параметров принимают:
- context.Context - контекст для доп. запроса
- id (или другое поле, по которому производится фильтрация)
- interfaces.Caller - DECORT-клиент для запроса
Так как эти функции возвращают не только результирующий слайс, но и возможную ошибку - конвейер придется прервать для обработки ошибки.
#### Использование на примере `compute.FilterByK8SID`:
```go
func main() {
// Чтение конфигурации из файла
cfg := config.ParseConfigJSON("<PATH>")
// Создание клиента
client := decort.New(cfg)
// Создание структуры запроса compute/list
req := compute.ListRequest{}
// Запрос
resp, err := client.CloudAPI().Compute().List(context.Background(), req)
if err != nil {
log.Fatal(err)
}
// Фильтрация по id кластера.
// Первый аргумент - контекст
// Второй - ID кластера
// Третий - DECORT-клиент
filtered, err := resp.FilterByK8SID(context.Background(), <k8sID>, client)
if err != nil {
log.Fatal(err) // Возможная ошибка запроса
}
// Доп. фильтрация и сортировка результата - worker ноды кластера
workers := filtered.FilterByK8SWorkers().SortByCreatedTime(false)
// Доп. фильтрация и сортировка результата - master ноды кластера
masters := filtered.FilterByK8SMasters().SortByCreatedTime(true)
// ....
}
```
### Сортировка
Функции сортировки так же могут быть объединены в конвейер:
```go
// Создание запроса compute/list
req := compute.ListRequest{}
resp, err := client.CloudAPI().Compute().List(context.Background(), req)
if err != nil {
log.Fatal(err)
}
// Функции сортировки имеют параметр inverse (bool):
// При значении false -> сортировка по возрастанию
// При true -> сортировка по убыванию
sorted := resp.
SortByCPU(false).
SortByRAM(false).
SortByCreatedTime(true)
// ....
```
### Сериализация
Результат преобразований легко сериализовать в JSON при помощи функции `.Serialize()`. Она принимает в себя 2 необязательных аргумента: префикс (prefix) и отступ (Indent).
В случае если функция вызывается без аргументов, то маршализация пройдет успешно, но без отступов и префиксов.
```go
// Сериализация данных с префиксом "" и отступом "\t"
serialized, err := filtered.Serialize("", "\t")
if err != nil {
log.Fatal(err)
}
// Запись сериализованных данных в файл
err = serialized.WriteToFile("<PATH>")
if err != nil {
log.Fatal(err)
}
```
#### Комплексный пример
```go
package main
import (
"context"
"log"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/compute"
)
func main() {
cfg := config.Config{
AppID: "<APP_ID>",
AppSecret: "<APP_SECRET>",
SSOURL: "<SSO_URL>",
DecortURL: "<DECORT_URL>",
Retries: 5,
}
cfg.SetTimeout(5 * time.Minute)
// Создание клиента
client := decort.New(cfg)
// Создание запроса compute/list
req := compute.ListRequest{}
resp, err := client.CloudBroker().Compute().List(context.Background(), req)
if err != nil {
log.Fatal(err)
}
// Цепь преобразований.
filtered, _ := resp.
FilterFunc(func(ic compute.ItemCompute) bool {
return ic.GUID == 123 // Фильтр по GUID
}).
FilterByName("<NAME>"). // Фильтр по имени
SortByCPU(false). // Сортировка по кол-ву ядер CPU по возрастанию
SortByCreatedTime(true). // Сортировка по времени создания по убыванию
Serialize("", "\t") // Сериализация с префиксом "" и отступом "\t"
// Serialize - терминальная функция, возвращает Serialized (обертку над []byte)
// Запись данных в файл
err = filtered.WriteToFile("<PATH>")
if err != nil {
log.Fatal(err)
}
}
```
## Работа с legacy клиентом
Работа с legacy клиентом применяется для пользователей, которые не используют для авторизации decs3o.
### Настройка конфигурации legacy клиента
Сначала, необходимо создать переменную конфигурации клиента. Конфигурация состоит как из обязательных, так и необязательных полей.
| Поле | Тип | Обязательный | Описание |
| ------------- | ------ | ------------ | ------------------------------------------------------------------ |
| Username | string | Да | username legacy пользователя |
| Password | string | Да | пароль legacy пользователя |
| DecortURL | string | Да | URL адрес платформы, с которой будет осуществляться взаимодействие |
| Retries | uint | Нет | Кол-во неудачных попыток выполнения запроса, по умолчанию - 5 |
| Timeout | config.Duration | Нет | Таймаут HTTP клиента, по умолчанию - без ограничений |
| SSLSkipVerify | bool | Нет | Пропуск проверки подлинности сертификата, по умолчанию - true |
| Token | string | Нет | JWT токен |
#### Пример конфигурации legacy клиента
```go
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
)
func main(){
// Настройка конфигурации
legacyCfg := config.LegacyConfig{
Username: "<USERNAME>",
Password: "<PASSWORD>",
DecortURL: "https://mr4.digitalenergy.online",
Retries: 5,
}
legacyCfg.SetTimeout(5 * time.Minute)
}
```
#### Парсинг legacy конфигурации из файла
Также возможно создать переменную конфигурации из JSON или YAML файла, используя функцию `ParseLegacyConfigJSON` (или `ParseLegacyConfigYAML`) из пакета config.
<br>
*См. пример файлов конфигурации ниже и в директории `samples/`.*
```go
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
)
func main() {
// Парсинг конфигурации из YAML-файла
legacyCfg := config.ParseLegacyConfigYAML("<PATH>")
}
```
#### Пример legacy JSON конфигурации
```json
{
"username": "<USERNAME>",
"password": "<PASSWORD>",
"decortUrl": "https://mr4.digitalenergy.online",
"retries": 5,
"timeout": "5m",
"sslSkipVerify": true
}
```
#### Пример legacy YAML конфигурации
```yaml
username: <USERNAME>
password: <PASSWORD>
decortUrl: https://mr4.digitalenergy.online
retries: 5
timeout: 5m
sslSkipVerify: true
```
### Создание legacy клиента
Создание клиента происходит с помощью функции-строителя `NewLegacy` из основного пакета `decort-sdk`, для избежания проблем с именами, пакету можно присвоить алиас `decort`. Функция принимает конфигурацию, возвращает структуру `DecortClient`, с помощью которой можно взаимодействовать с платформой.
#### Пример создания legacy клиента
```go
package main
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
)
func main() {
// Настройка конфигурации
legacyCfg := config.LegacyConfig{
Username: "<USERNAME>",
Password: "<PASSWORD>",
DecortURL: "https://mr4.digitalenergy.online",
Retries: 5,
}
legacyCfg.SetTimeout(5 * time.Minute)
// Создание клиента
legacyClient := decort.NewLegacy(cfg)
}
```
#### Пример выполнения запроса
```go
package main
import (
"fmt"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
)
func main() {
// Настройка конфигурации
legacyCfg := config.LegacyConfig{
Username: "<USERNAME>",
Password: "<PASSWORD>",
DecortURL: "https://mr4.digitalenergy.online",
Retries: 5,
}
// Создание клиента
legacyClient := decort.NewLegacy(cfg)
// Создание структуры запроса
// CreateRequest - реквест на создание виртуальной машины
req := kvmx86.CreateRequest{
RGID: 123,
Name: "compute",
CPU: 4,
RAM: 4096,
ImageID: 321,
}
// Выполнение запроса
res, err := client.CloudAPI().KVMX86().Create(context.Background(), req)
if err != nil {
log.Fatal(err)
}
fmt.Println(res)
}

View File

@@ -14,7 +14,7 @@ Also the library have structures for responses.
## Install ## Install
```bash ```bash
go get -u github.com/rudecs/decort-sdk go get -u repository.basistech.ru/BASIS/decort-golang-sdk
``` ```
## API List ## API List
@@ -29,8 +29,8 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/rudecs/decort-sdk/config" "repository.basistech.ru/BASIS/decort-golang-sdk/config"
"github.com/rudecs/decort-sdk/pkg/cloudapi/kvmx86" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmx86"
) )
func main() { func main() {

View File

@@ -7,12 +7,12 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/rudecs/decort-sdk/pkg/cloudapi" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi"
"github.com/rudecs/decort-sdk/pkg/cloudbroker" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker"
"github.com/google/go-querystring/query" "github.com/google/go-querystring/query"
"github.com/rudecs/decort-sdk/config" "repository.basistech.ru/BASIS/decort-golang-sdk/config"
"github.com/rudecs/decort-sdk/internal/client" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/client"
) )
// HTTP-client for platform // HTTP-client for platform

View File

@@ -1,39 +1,105 @@
package config package config
import (
"encoding/json"
"os"
"time"
"gopkg.in/yaml.v3"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Configuration for creating request to platform // Configuration for creating request to platform
type Config struct { type Config struct {
// JWT platform token // JWT platform token
// Required: false // Required: false
// Example: "qwqwdfwv68979we0q9bfv7e9sbvd89798qrwv97ff" // Example: "qwqwdfwv68979we0q9bfv7e9sbvd89798qrwv97ff"
Token string Token string `json:"token" yaml:"token"`
// Application (client) identifier for authorization // Application (client) identifier for authorization
// in the cloud platform controller in oauth2 mode. // in the cloud platform controller in oauth2 mode.
// Required: true // Required: true
// Example: "ewqfrvea7s890avw804389qwguf234h0otfi3w4eiu" // Example: "ewqfrvea7s890avw804389qwguf234h0otfi3w4eiu"
AppID string AppID string `json:"appId" yaml:"appId" validate:"required"`
// Application (client) secret code for authorization // Application (client) secret code for authorization
// in the cloud platform controller in oauth2 mode. // in the cloud platform controller in oauth2 mode.
// Example: "frvet09rvesfis0c9erv9fsov0vsdfi09ovds0f" // Example: "frvet09rvesfis0c9erv9fsov0vsdfi09ovds0f"
AppSecret string AppSecret string `json:"appSecret" yaml:"appSecret" validate:"required"`
// Platform authentication service address // Platform authentication service address
// Required: true // Required: true
// Example: "https://sso.digitalenergy.online" // Example: "https://sso.digitalenergy.online"
SSOURL string SSOURL string `json:"ssoUrl" yaml:"ssoUrl" validate:"url"`
// The address of the platform on which the actions are planned // The address of the platform on which the actions are planned
// Required: true // Required: true
// Example: "https://mr4.digitalenergy.online" // Example: "https://mr4.digitalenergy.online"
DecortURL string DecortURL string `json:"decortUrl" yaml:"decortUrl" validate:"url"`
// Amount platform request attempts // Amount platform request attempts
// Default value: 5 // Default value: 5
// Required: false // Required: false
Retries uint64 Retries uint64 `json:"retries" yaml:"retries"`
// Skip verify, true by default // Skip verify, true by default
// Required: false // Required: false
SSLSkipVerify bool SSLSkipVerify bool `json:"sslSkipVerify" yaml:"sslSkipVerify"`
// HTTP client timeout, unlimited if left empty
// Required: false
Timeout Duration `json:"timeout" yaml:"timeout"`
}
// SetTimeout is used to set HTTP client timeout.
func (c *Config) SetTimeout(dur time.Duration) {
c.Timeout = Duration(dur)
}
// ParseConfigJSON parses Config from specified JSON-formatted file.
func ParseConfigJSON(path string) (Config, error) {
file, err := os.ReadFile(path)
if err != nil {
return Config{}, err
}
var config Config
err = json.Unmarshal(file, &config)
if err != nil {
return Config{}, err
}
err = validators.ValidateConfig(config)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return Config{}, validators.ValidationError(validationError)
}
}
return config, nil
}
// ParseConfigYAML parses Config from specified YAML-formatted file.
func ParseConfigYAML(path string) (Config, error) {
file, err := os.ReadFile(path)
if err != nil {
return Config{}, err
}
var config Config
err = yaml.Unmarshal(file, &config)
if err != nil {
return Config{}, err
}
err = validators.ValidateConfig(config)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return Config{}, validators.ValidationError(validationError)
}
}
return config, nil
} }

99
config/legacy-config.go Normal file
View File

@@ -0,0 +1,99 @@
package config
import (
"encoding/json"
"os"
"time"
"gopkg.in/yaml.v3"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Legacy client configuration
type LegacyConfig struct {
// ServiceAccount username
// Required: true
// Example : "osh_mikoev"
Username string `json:"username" yaml:"username" validate:"required"`
// ServiceAccount password
// Required: true
// Example: "[1o>hYkjnJr)HI78q7t&#%8Lm"
Password string `json:"password" yaml:"password" validate:"required"`
// Platform token
// Required: false
// Example: "158e76424b0d4810b6086hgbhj928fc4a6bc06e"
Token string `json:"token" yaml:"token"`
// Address of the platform on which the actions are planned
// Required: true
// Example: "https://mr4.digitalenergy.online"
DecortURL string `json:"decortUrl" yaml:"decortUrl" validate:"url"`
// Amount platform request attempts
// Default value: 5
// Required: false
Retries uint64 `json:"retries" yaml:"retries"`
// Skip verify, true by default
// Required: false
SSLSkipVerify bool `json:"sslSkipVerify" yaml:"sslSkipVerify"`
// HTTP client timeout, unlimited if left empty
// Required: false
Timeout Duration `json:"timeout" yaml:"timeout"`
}
// SetTimeout is used to set HTTP client timeout.
func (c *LegacyConfig) SetTimeout(dur time.Duration) {
c.Timeout = Duration(dur)
}
// ParseLegacyConfigJSON parses LegacyConfig from specified JSON-formatted file.
func ParseLegacyConfigJSON(path string) (LegacyConfig, error) {
file, err := os.ReadFile(path)
if err != nil {
return LegacyConfig{}, err
}
var config LegacyConfig
err = json.Unmarshal(file, &config)
if err != nil {
return LegacyConfig{}, err
}
err = validators.ValidateConfig(config)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return LegacyConfig{}, validators.ValidationError(validationError)
}
}
return config, nil
}
// ParseLegacyConfigYAML parses LegacyConfig from specified YAML-formatted file.
func ParseLegacyConfigYAML(path string) (LegacyConfig, error) {
file, err := os.ReadFile(path)
if err != nil {
return LegacyConfig{}, err
}
var config LegacyConfig
err = yaml.Unmarshal(file, &config)
if err != nil {
return LegacyConfig{}, err
}
err = validators.ValidateConfig(config)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return LegacyConfig{}, validators.ValidationError(validationError)
}
}
return config, nil
}

50
config/timeouts.go Normal file
View File

@@ -0,0 +1,50 @@
package config
import (
"encoding/json"
"fmt"
"time"
)
// Duration is a wrapper around time.Duration (used for better user experience)
type Duration time.Duration
func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {
var v interface{}
if err := unmarshal(&v); err != nil {
return err
}
switch value := v.(type) {
case string:
tmp, err := time.ParseDuration(value)
if err != nil {
return err
}
*d = Duration(tmp)
return nil
default:
return fmt.Errorf("Invalid duration %v", value)
}
}
func (d *Duration) UnmarshalJSON(b []byte) error {
var v interface{}
if err := json.Unmarshal(b, &v); err != nil {
return err
}
switch value := v.(type) {
case string:
tmp, err := time.ParseDuration(value)
if err != nil {
return err
}
*d = Duration(tmp)
return nil
default:
return fmt.Errorf("Invalid duration %v", value)
}
}
func (d *Duration) Get() time.Duration {
return time.Duration(*d)
}

20
go.mod
View File

@@ -1,5 +1,19 @@
module github.com/rudecs/decort-sdk module repository.basistech.ru/BASIS/decort-golang-sdk
go 1.19 go 1.20
require github.com/google/go-querystring v1.1.0 require (
github.com/go-playground/validator/v10 v10.11.2
github.com/google/go-querystring v1.1.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/text v0.6.0 // indirect
)

32
go.sum
View File

@@ -1,5 +1,37 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 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/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
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=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -5,7 +5,7 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/rudecs/decort-sdk/config" "repository.basistech.ru/BASIS/decort-golang-sdk/config"
) )
func NewHttpClient(cfg config.Config) *http.Client { func NewHttpClient(cfg config.Config) *http.Client {
@@ -29,12 +29,12 @@ func NewHttpClient(cfg config.Config) *http.Client {
retries: cfg.Retries, retries: cfg.Retries,
clientID: cfg.AppID, clientID: cfg.AppID,
clientSecret: cfg.AppSecret, clientSecret: cfg.AppSecret,
SSOURL: cfg.SSOURL, ssoURL: cfg.SSOURL,
token: cfg.Token, token: cfg.Token,
expiryTime: expiredTime, expiryTime: expiredTime,
//TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}, },
Timeout: 5 * time.Minute, Timeout: cfg.Timeout.Get(),
} }
} }

View File

@@ -0,0 +1,40 @@
package client
import (
"crypto/tls"
"net/http"
"net/url"
"time"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
)
// NewLegacyHttpClient creates legacy HTTP Client
func NewLegacyHttpClient(cfg config.LegacyConfig) *http.Client {
transCfg := &http.Transport{
TLSClientConfig: &tls.Config{
//nolint:gosec
InsecureSkipVerify: cfg.SSLSkipVerify,
},
}
var expiredTime time.Time
if cfg.Token != "" {
expiredTime = time.Now().AddDate(0, 0, 1)
}
return &http.Client{
Transport: &transportLegacy{
base: transCfg,
username: url.QueryEscape(cfg.Username),
password: url.QueryEscape(cfg.Password),
retries: cfg.Retries,
token: cfg.Token,
decortURL: cfg.DecortURL,
expiryTime: expiredTime,
},
Timeout: cfg.Timeout.Get(),
}
}

View File

@@ -0,0 +1,74 @@
package client
import (
"fmt"
"io"
"net/http"
"strings"
"time"
)
type transportLegacy struct {
base http.RoundTripper
username string
password string
retries uint64
token string
decortURL string
expiryTime time.Time
}
func (t *transportLegacy) RoundTrip(request *http.Request) (*http.Response, error) {
if t.token == "" || time.Now().After(t.expiryTime) {
body := fmt.Sprintf("username=%s&password=%s", t.username, t.password)
bodyReader := strings.NewReader(body)
req, _ := http.NewRequestWithContext(request.Context(), "POST", t.decortURL+"/restmachine/cloudapi/user/authenticate", bodyReader)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := t.base.RoundTrip(req)
if err != nil {
return nil, fmt.Errorf("unable to get token: %w", err)
}
tokenBytes, _ := io.ReadAll(resp.Body)
resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("unable to get token: %s", tokenBytes)
}
token := string(tokenBytes)
t.token = token
t.expiryTime = time.Now().AddDate(0, 0, 1)
}
tokenValue := fmt.Sprintf("&authkey=%s", t.token)
tokenReader := strings.NewReader(tokenValue)
newBody := io.MultiReader(request.Body, tokenReader)
req, _ := http.NewRequestWithContext(request.Context(), request.Method, request.URL.String(), newBody)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json")
var resp *http.Response
var err error
for i := uint64(0); i < t.retries; i++ {
resp, err = t.base.RoundTrip(req)
if err == nil {
if resp.StatusCode == 200 {
return resp, nil
}
respBytes, _ := io.ReadAll(resp.Body)
err = fmt.Errorf("%s", respBytes)
resp.Body.Close()
}
if err != nil {
return nil, fmt.Errorf("could not execute request: %w", err)
}
time.Sleep(time.Second * 5)
}
return nil, fmt.Errorf("could not execute request: %w", err)
}

View File

@@ -14,7 +14,7 @@ type transport struct {
clientID string clientID string
clientSecret string clientSecret string
token string token string
SSOURL string ssoURL string
expiryTime time.Time expiryTime time.Time
} }
@@ -23,7 +23,9 @@ func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
body := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s&response_type=id_token", t.clientID, t.clientSecret) body := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s&response_type=id_token", t.clientID, t.clientSecret)
bodyReader := strings.NewReader(body) bodyReader := strings.NewReader(body)
req, _ := http.NewRequestWithContext(req.Context(), "POST", t.SSOURL+"/v1/oauth/access_token", bodyReader) t.ssoURL = strings.TrimSuffix(t.ssoURL, "/")
req, _ := http.NewRequestWithContext(req.Context(), "POST", t.ssoURL+"/v1/oauth/access_token", bodyReader)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded") req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := t.base.RoundTrip(req) resp, err := t.base.RoundTrip(req)

View File

@@ -0,0 +1,18 @@
package serialization
import (
"os"
)
type Writable interface {
WriteToFile(string) error
}
type Serialized []byte
// WriteToFile writes serialized data to specified file.
//
// Make sure to use .json extension for best compatibility.
func (s Serialized) WriteToFile(path string) error {
return os.WriteFile(path, s, 0600)
}

View File

@@ -0,0 +1,274 @@
package validators
import (
"regexp"
"strings"
"github.com/go-playground/validator/v10"
)
// 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)
}
// protoValidator is used to validate Proto fields.
func protoValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, protoValues)
}
// accessTypeValidator is used to validate AccessType fields.
func accessTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, accessTypeValues)
}
// resTypesValidator is used to validate ResTypes fields.
func resTypesValidator(fe validator.FieldLevel) bool {
fieldSlice, ok := fe.Field().Interface().([]string)
if !ok {
return false
}
for _, value := range fieldSlice {
if !StringInSlice(value, resTypesValues) {
return false
}
}
return true
}
// driverValidator is used to validate Driver fields.
func driverValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, driverValues)
}
// accountCUTypeValidator is used to validate CUType field.
func accountCUTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, accountCUTypeValues)
}
// bserviceModeValidator is used to validate Mode field.
func bserviceModeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, bserviceModeValues)
}
// computeTopologyValidator is used to validate Topology field.
func computeTopologyValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, computeTopologyValues)
}
// computePolicyValidator is used to validate Policy field.
func computePolicyValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, computePolicyValues)
}
// computeModeValidator is used to validate Mode field.
func computeModeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, computeModeValues)
}
// computeDiskTypeValidator is used to validate DiskType field.
func computeDiskTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, computeDiskTypeValues)
}
// computeNetTypeValidator is used to validate NetType field.
func computeNetTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, computeNetTypeValues)
}
// computeOrderValidator is used to validate Order field.
func computeOrderValidator(fe validator.FieldLevel) bool {
fieldSlice, ok := fe.Field().Interface().([]string)
if !ok {
return false
}
for _, value := range fieldSlice {
if !StringInSlice(value, computeOrderValues) {
return false
}
}
return true
}
// computeDataDisksValidator is used to validate DataDisks field.
func computeDataDisksValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, computeDataDisksValues)
}
// diskTypeValidator is used to validate Type field.
func diskTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, diskTypeValues)
}
// flipgroupClientTypeValidator is used to validate ClientType field.
func flipgroupClientTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, flipgroupClientTypeValues)
}
// kvmNetTypeValidator is used to validate NetType field.
func kvmNetTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, kvmNetTypeValues)
}
// lbAlgorithmValidator is used to validate Algorithm field.
func lbAlgorithmValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, lbAlgorithmValues)
}
// rgDefNetValidator is used to validate DefNet field.
func rgDefNetValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, rgDefNetValues)
}
// rgNetTypeValidator is used to validate NetType field.
func rgNetTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, rgNetTypeValues)
}
// vinsTypeValidator is used to validate Type field.
func vinsTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, vinsTypeValues)
}
// imageBootTypeValidator is used to validate BootType field.
func imageBootTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, imageBootTypeValues)
}
// imageTypeValidator is used to validate ImageType field.
func imageTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, imageTypeValues)
}
// imageDriversValidator is used to validate Drivers field.
func imageDriversValidator(fe validator.FieldLevel) bool {
fieldSlice, ok := fe.Field().Interface().([]string)
if !ok {
return false
}
for _, item := range fieldSlice {
if !StringInSlice(item, imageDriversValues) {
return false
}
}
return true
}
// imageArchitectureValidator is used to validate Architecture field.
func imageArchitectureValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, imageArchitectureValues)
}
// sepFieldTypeValidator is used to validate FieldType field.
func sepFieldTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, sepFieldTypeValues)
}
// hwPathValidator is used to validate HWPath field.
func hwPathValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
ok, _ := regexp.MatchString(`^\b[0-9a-f]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}.\d{1}$`, fieldValue)
return ok
}
// networkPluginValidator is used to validate NetworkPlugin field
func networkPluginValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
fieldValue = strings.ToLower(fieldValue)
return StringInSlice(fieldValue, networkPluginValues)
}
// networkPluginsValidator is used to validate NetworkPlugins field
func networkPluginsValidator(fe validator.FieldLevel) bool {
fieldSlice, ok := fe.Field().Interface().([]string)
if !ok {
return false
}
for _, item := range fieldSlice {
item = strings.ToLower(item)
if !StringInSlice(item, networkPluginValues) {
return false
}
}
return true
}
func interfaceStateValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
fieldValue = strings.ToLower(fieldValue)
return StringInSlice(fieldValue, interfaceStateValues)
}
func strictLooseValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
fieldValue = strings.ToLower(fieldValue)
return StringInSlice(fieldValue, strictLooseValues)
}
// name workerGroup must be more 3 symbol
func workerGroupNameValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
fieldValue = strings.Trim(fieldValue, " ")
return len(fieldValue) >= 3
}

View File

@@ -1,5 +1,30 @@
package validators package validators
import (
"errors"
"github.com/go-playground/validator/v10"
)
func ValidateRequest(req interface{}) error {
validate := getDecortValidator()
return validate.Struct(req)
}
func ValidateConfig(cfg interface{}) error {
validate := getDecortValidator()
return validate.Struct(cfg)
}
func ValidationError(fe validator.FieldError) error {
return errors.New(errorMessage(fe))
}
//nolint:errorlint
func GetErrors(err error) validator.ValidationErrors {
return err.(validator.ValidationErrors)
}
func StringInSlice(str string, target []string) bool { func StringInSlice(str string, target []string) bool {
for _, v := range target { for _, v := range target {
if v == str { if v == str {

View File

@@ -0,0 +1,239 @@
package validators
import (
"fmt"
"strings"
"github.com/go-playground/validator/v10"
)
func errorMessage(fe validator.FieldError) string {
prefix := "validation-error:"
switch fe.Tag() {
// Common Validators
case "required":
return fmt.Sprintf("%s %s is required", prefix, fe.Field())
case "gt":
return fmt.Sprintf("%s %s can't be less or equal to zero", prefix, fe.Field())
case "min":
return fmt.Sprintf("%s %s: not enough elements", prefix, fe.Field())
case "max":
return fmt.Sprintf("%s %s: too many elements", prefix, fe.Field())
case "url":
return fmt.Sprintf("%s %s: unexpected URL format", prefix, fe.Field())
case "email":
return fmt.Sprintf("%s %s: unexpected E-Mail format", prefix, fe.Field())
case "driver":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(driverValues))
case "accessType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(accessTypeValues))
case "resTypes":
return fmt.Sprintf("%s %s can contain only the following values: %s",
prefix,
fe.Field(),
joinValues(resTypesValues))
case "proto":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(protoValues))
// Account Validators
case "accountCUType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(accountCUTypeValues))
// BService Validators
case "bserviceMode":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(bserviceModeValues))
// Compute Validators
case "computeTopology":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(computeTopologyValues))
case "computePolicy":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(computePolicyValues))
case "computeMode":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(computeModeValues))
case "computeDiskType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(computeDiskTypeValues))
case "computeNetType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(computeNetTypeValues))
case "computeOrder":
return fmt.Sprintf("%s %s can contain only the following values: %s",
prefix,
fe.Field(),
joinValues(computeOrderValues))
case "computeDataDisks":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(computeDataDisksValues))
case "computeDriver":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(computeDriverValues))
// Disk Validators
case "diskType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(diskTypeValues))
// Flipgroup Validators
case "flipgroupClientType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(flipgroupClientTypeValues))
// k8s Validators
case "workerGroupName":
return fmt.Sprintf("%s %s must be more 3 symbol",
prefix,
fe.Field())
// KVM_X86/KVM_PPC Validators
case "kvmNetType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(kvmNetTypeValues))
// LB Validators
case "lbAlgorithm":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(lbAlgorithmValues))
// RG Validators
case "rgDefNet":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(rgDefNetValues))
case "rgNetType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(rgNetTypeValues))
// ViNS Validators
case "vinsType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(vinsTypeValues))
// Image Validators
case "imageBootType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(imageBootTypeValues))
case "imageType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(imageTypeValues))
case "imageDrivers":
return fmt.Sprintf("%s %s must contain only the following: %s",
prefix,
fe.Field(),
joinValues(imageDriversValues))
case "imageArchitecture":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(imageArchitectureValues))
// SEP Validators
case "sepFieldType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(sepFieldTypeValues))
// HWPath Validators
case "hwPath":
return fmt.Sprintf("%s %s must be in format 0000:1f:2b.0",
prefix,
fe.Field())
// Network plugin Validators
case "networkPlugin":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(networkPluginValues))
case "networkPlugins":
return fmt.Sprintf("%s %s must contain only the following: %s",
prefix,
fe.Field(),
joinValues(networkPluginValues))
case "strict_loose":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(strictLooseValues))
case "interfaceState":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(interfaceStateValues))
}
return fe.Error()
}
func joinValues(values []string) string {
return strings.Join(values, ", ")
}

View File

@@ -0,0 +1,189 @@
package validators
import (
"sync"
"github.com/go-playground/validator/v10"
)
var (
once sync.Once
decortValidator = validator.New()
)
// getDecortValidator returns singleton instance of DecortValidator.
func getDecortValidator() *validator.Validate {
once.Do(func() {
err := registerAllValidators(decortValidator)
if err != nil {
panic(err)
}
})
return decortValidator
}
// registerAllValidators registers all custom validators in DecortValidator.
func registerAllValidators(validate *validator.Validate) error {
err := validate.RegisterValidation("proto", protoValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("computeDriver", computeDriverValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("accessType", accessTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("resTypes", resTypesValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("driver", driverValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("imageBootType", imageBootTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("imageType", imageTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("imageDrivers", imageDriversValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("imageArchitecture", imageArchitectureValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("accountCUType", accountCUTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("bserviceMode", bserviceModeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("computeTopology", computeTopologyValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("computePolicy", computePolicyValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("computeMode", computeModeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("computeDiskType", computeDiskTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("computeNetType", computeNetTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("computeOrder", computeOrderValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("computeDataDisks", computeDataDisksValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("diskType", diskTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("flipgroupClientType", flipgroupClientTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("kvmNetType", kvmNetTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("lbAlgorithm", lbAlgorithmValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("rgDefNet", rgDefNetValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("rgNetType", rgNetTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("vinsType", vinsTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("sepFieldType", sepFieldTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("hwPath", hwPathValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("networkPlugin", networkPluginValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("networkPlugins", networkPluginsValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("strict_loose", strictLooseValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("interfaceState", interfaceStateValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("workerGroupName", workerGroupNameValidator)
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,47 @@
package validators
var (
driverValues = []string{"KVM_X86", "KVM_PPC"}
accessTypeValues = []string{"R", "RCX", "ARCXDU"}
resTypesValues = []string{"compute", "vins", "k8s", "openshift", "lb", "flipgroup"}
protoValues = []string{"tcp", "udp"}
accountCUTypeValues = []string{"CU_M", "CU_C", "CU_D", "CU_DM", "CU_S", "CU_A", "CU_NO", "CU_I", "CU_NP"}
bserviceModeValues = []string{"ABSOLUTE", "RELATIVE"}
computeTopologyValues = []string{"compute", "node"}
computePolicyValues = []string{"RECOMMENDED", "REQUIRED"}
computeModeValues = []string{"EQ", "EN", "ANY"}
computeDiskTypeValues = []string{"D", "B"}
computeNetTypeValues = []string{"EXTNET", "VINS"}
computeOrderValues = []string{"cdrom", "network", "hd"}
computeDataDisksValues = []string{"KEEP", "DETACH", "DESTROY"}
computeDriverValues = []string{"KVM_X86", "SVA_KVM_X86"}
diskTypeValues = []string{"B", "T", "D"}
flipgroupClientTypeValues = []string{"compute", "vins"}
kvmNetTypeValues = []string{"EXTNET", "VINS", "NONE"}
lbAlgorithmValues = []string{"roundrobin", "static-rr", "leastconn"}
rgDefNetValues = []string{"PRIVATE", "PUBLIC", "NONE"}
rgNetTypeValues = []string{"PUBLIC", "PRIVATE"}
vinsTypeValues = []string{"DHCP", "VIP", "EXCLUDE"}
imageBootTypeValues = []string{"uefi", "bios"}
imageTypeValues = []string{"windows", "linux", "other"}
imageDriversValues = []string{"KVM_X86"}
imageArchitectureValues = []string{"X86_64", "PPC64_LE"}
sepFieldTypeValues = []string{"int", "str", "bool", "list", "dict"}
networkPluginValues = []string{"flannel", "weawenet", "calico"}
strictLooseValues = []string{"strict", "loose"}
interfaceStateValues = []string{"on", "off"}
)

74
legacy-client.go Normal file
View File

@@ -0,0 +1,74 @@
package decortsdk
import (
"context"
"errors"
"io"
"net/http"
"strings"
"github.com/google/go-querystring/query"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/client"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker"
)
// Legacy HTTP-client for platform
type LegacyDecortClient struct {
decortURL string
client *http.Client
}
// Legacy client builder
func NewLegacy(cfg config.LegacyConfig) *LegacyDecortClient {
if cfg.Retries == 0 {
cfg.Retries = 5
}
return &LegacyDecortClient{
decortURL: cfg.DecortURL,
client: client.NewLegacyHttpClient(cfg),
}
}
// CloudAPI builder
func (ldc *LegacyDecortClient) CloudAPI() *cloudapi.CloudAPI {
return cloudapi.New(ldc)
}
// CloudBroker builder
func (ldc *LegacyDecortClient) CloudBroker() *cloudbroker.CloudBroker {
return cloudbroker.New(ldc)
}
// DecortApiCall method for sending requests to the platform
func (ldc *LegacyDecortClient) DecortApiCall(ctx context.Context, method, url string, params interface{}) ([]byte, error) {
values, err := query.Values(params)
if err != nil {
return nil, err
}
body := strings.NewReader(values.Encode())
req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+"/restmachine"+url, body)
if err != nil {
return nil, err
}
resp, err := ldc.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, errors.New(string(respBytes))
}
return respBytes, nil
}

View File

@@ -1,7 +1,7 @@
package cloudapi package cloudapi
import ( import (
"github.com/rudecs/decort-sdk/pkg/cloudapi/account" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/account"
) )
// Accessing the Account method group // Accessing the Account method group

View File

@@ -2,7 +2,7 @@
package account package account
import ( import (
"github.com/rudecs/decort-sdk/interfaces" "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
) )
// Structure for creating request to account // Structure for creating request to account

View File

@@ -2,54 +2,37 @@ package account
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"github.com/rudecs/decort-sdk/internal/validators" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for adding permission to access to account for a user // Request struct for adding permission to access to account for a user
type AddUserRequest struct { type AddUserRequest struct {
// ID of account to add to // ID of account to add to
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// Name of the user to be given rights // Name of the user to be given rights
// Required: true // Required: true
UserID string `url:"userId"` UserID string `url:"userId" json:"userId" validate:"required"`
// Account permission types: // Account permission types:
// - 'R' for read only access // - 'R' for read only access
// - 'RCX' for Write // - 'RCX' for Write
// - 'ARCXDU' for Admin // - 'ARCXDU' for Admin
// Required: true // Required: true
AccessType string `url:"accesstype"` AccessType string `url:"accesstype" json:"accesstype" validate:"required,accessType"`
}
func (arq AddUserRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
if arq.UserID == "" {
return errors.New("validation-error: field UserID can not be empty")
}
if arq.AccessType == "" {
return errors.New("validation-error: field AccessType can not be empty")
}
isValid := validators.StringInSlice(arq.AccessType, []string{"R", "RCX", "ARCXDU"})
if !isValid {
return errors.New("validation-error: field AccessType can be only R, RCX or ARCXDU")
}
return nil
} }
// AddUser gives a user access rights. // AddUser gives a user access rights.
func (a Account) AddUser(ctx context.Context, req AddUserRequest) (bool, error) { func (a Account) AddUser(ctx context.Context, req AddUserRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/addUser" url := "/cloudapi/account/addUser"

View File

@@ -3,30 +3,25 @@ package account
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for give list account audits // Request struct for give list account audits
type AuditsRequest struct { type AuditsRequest struct {
// ID of the account // ID of the account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq AuditsRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
return nil
} }
// Audits gets audit records for the specified account object // Audits gets audit records for the specified account object
func (a Account) Audits(ctx context.Context, req AuditsRequest) (ListAudits, error) { func (a Account) Audits(ctx context.Context, req AuditsRequest) (ListAudits, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/audits" url := "/cloudapi/account/audits"

View File

@@ -2,71 +2,63 @@ package account
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for creating account // Request struct for creating account
type CreateRequest struct { type CreateRequest struct {
// Display name // Display name
// Required: true // Required: true
Name string `url:"name"` Name string `url:"name" json:"name" validate:"required"`
// Name of the account // Name of the account
// Required: true // Required: true
Username string `url:"username"` Username string `url:"username" json:"username" validate:"required"`
// Email // Email
// Required: false // Required: false
EmailAddress string `url:"emailaddress,omitempty"` EmailAddress string `url:"emailaddress,omitempty" json:"emailaddress,omitempty" validate:"omitempty,email"`
// Max size of memory in MB // Max size of memory in MB
// Required: false // Required: false
MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty"` MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
// Max size of aggregated vdisks in GB // Max size of aggregated vdisks in GB
// Required: false // Required: false
MaxVDiskCapacity int64 `url:"maxVDiskCapacity,omitempty"` MaxVDiskCapacity int64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
// Max number of CPU cores // Max number of CPU cores
// Required: false // Required: false
MaxCPUCapacity int64 `url:"maxCPUCapacity,omitempty"` MaxCPUCapacity int64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
// Max sent/received network transfer peering // Max sent/received network transfer peering
// Required: false // Required: false
MaxNetworkPeerTransfer int64 `url:"maxNetworkPeerTransfer,omitempty"` MaxNetworkPeerTransfer int64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
// Max number of assigned public IPs // Max number of assigned public IPs
// Required: false // Required: false
MaxNumPublicIP int64 `url:"maxNumPublicIP,omitempty"` MaxNumPublicIP int64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
// If true send emails when a user is granted access to resources // If true send emails when a user is granted access to resources
// Required: false // Required: false
SendAccessEmails bool `url:"sendAccessEmails,omitempty"` SendAccessEmails bool `url:"sendAccessEmails" json:"sendAccessEmails"`
// Limit (positive) or disable (0) GPU resources // Limit (positive) or disable (0) GPU resources
// Required: false // Required: false
GPUUnits int64 `url:"gpu_units,omitempty"` GPUUnits int64 `url:"gpu_units,omitempty" json:"gpu_units,omitempty"`
}
func (arq CreateRequest) validate() error {
if arq.Name == "" {
return errors.New("validation-error: field Name can not be empty")
}
if arq.Username == "" {
return errors.New("validation-error: field Username can not be empty")
}
return nil
} }
// Create creates account // Create creates account
// Setting a cloud unit maximum to -1 or empty will not put any restrictions on the resource // Setting a cloud unit maximum to -1 or empty will not put any restrictions on the resource
func (a Account) Create(ctx context.Context, req CreateRequest) (uint64, error) { func (a Account) Create(ctx context.Context, req CreateRequest) (uint64, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return 0, err for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/create" url := "/cloudapi/account/create"

View File

@@ -2,33 +2,29 @@ package account
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for delete account // Request struct for delete account
type DeleteRequest struct { type DeleteRequest struct {
// ID of account to delete // ID of account to delete
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// Whether to completely delete the account // Whether to completely delete the account
// Required: false // Required: false
Permanently bool `url:"permanently,omitempty"` Permanently bool `url:"permanently,omitempty" json:"permanently,omitempty"`
}
func (arq DeleteRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID must be set")
}
return nil
} }
// Delete completes delete an account from the system Returns true if account is deleted or was already deleted or never existed // Delete completes delete an account from the system Returns true if account is deleted or was already deleted or never existed
func (a Account) Delete(ctx context.Context, req DeleteRequest) (bool, error) { func (a Account) Delete(ctx context.Context, req DeleteRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/delete" url := "/cloudapi/account/delete"

View File

@@ -2,42 +2,34 @@ package account
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for revoke access to account // Request struct for revoke access to account
type DeleteUserRequest struct { type DeleteUserRequest struct {
// ID of the account // ID of the account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// ID or emailaddress of the user to remove // ID or emailaddress of the user to remove
// Required: true // Required: true
UserID string `url:"userId"` UserID string `url:"userId" json:"userId" validate:"required"`
// Recursively revoke access rights from owned cloudspaces and vmachines // Recursively revoke access rights from owned cloudspaces and vmachines
// Required: false // Required: false
RecursiveDelete bool `url:"recursivedelete,omitempty"` RecursiveDelete bool `url:"recursivedelete,omitempty" json:"recursivedelete,omitempty"`
}
func (arq DeleteUserRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
if arq.UserID == "" {
return errors.New("validation-error: field UserID can not be empty")
}
return nil
} }
// DeleteUser revokes user access from the account // DeleteUser revokes user access from the account
func (a Account) DeleteUser(ctx context.Context, req DeleteUserRequest) (bool, error) { func (a Account) DeleteUser(ctx context.Context, req DeleteUserRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/deleteUser" url := "/cloudapi/account/deleteUser"

View File

@@ -2,31 +2,26 @@ package account
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for change status of account // Request struct for change status of account
type DisabelEnableRequest struct { type DisableEnableRequest struct {
// ID of account // ID of account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq DisabelEnableRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
return nil
} }
// Disable disables an account // Disable disables an account
func (a Account) Disable(ctx context.Context, req DisabelEnableRequest) (bool, error) { func (a Account) Disable(ctx context.Context, req DisableEnableRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/disable" url := "/cloudapi/account/disable"
@@ -45,10 +40,12 @@ func (a Account) Disable(ctx context.Context, req DisabelEnableRequest) (bool, e
} }
// Enable enables an account // Enable enables an account
func (a Account) Enable(ctx context.Context, req DisabelEnableRequest) (bool, error) { func (a Account) Enable(ctx context.Context, req DisableEnableRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/enable" url := "/cloudapi/account/enable"

View File

@@ -0,0 +1,70 @@
package account
// FilterByID returns ListAccounts with specified ID.
func (la ListAccounts) FilterByID(id uint64) ListAccounts {
predicate := func(ia ItemAccount) bool {
return ia.ID == id
}
return la.FilterFunc(predicate)
}
// FilterByName returns ListAccounts with specified Name.
func (la ListAccounts) FilterByName(name string) ListAccounts {
predicate := func(ia ItemAccount) bool {
return ia.Name == name
}
return la.FilterFunc(predicate)
}
// FilterByStatus returns ListAccounts with specified Status.
func (la ListAccounts) FilterByStatus(status string) ListAccounts {
predicate := func(ia ItemAccount) bool {
return ia.Status == status
}
return la.FilterFunc(predicate)
}
// FilterByUserGroupID returns ListAccounts with specified UserGroupID.
func (la ListAccounts) FilterByUserGroupID(userGroupID string) ListAccounts {
predicate := func(ia ItemAccount) bool {
acl := ia.ACL
for _, item := range acl {
if item.UgroupID == userGroupID {
return true
}
}
return false
}
return la.FilterFunc(predicate)
}
// FilterFunc allows filtering ListAccounts based on a user-specified predicate.
func (la ListAccounts) FilterFunc(predicate func(ItemAccount) bool) ListAccounts {
var result ListAccounts
for _, acc := range la.Data {
if predicate(acc) {
result.Data = append(result.Data, acc)
}
}
result.EntryCount = uint64(len(result.Data))
return result
}
// FindOne returns first found ItemAccount.
// If none was found, returns an empty struct.
func (la ListAccounts) FindOne() ItemAccount {
if len(la.Data) == 0 {
return ItemAccount{}
}
return la.Data[0]
}

View File

@@ -0,0 +1,149 @@
package account
import (
"testing"
)
var accounts = ListAccounts{
Data: []ItemAccount{
{
ACL: []RecordACL{
{
IsExplicit: true,
GUID: "",
Rights: "CXDRAU",
Status: "CONFIRMED",
Type: "U",
UgroupID: "timofey_tkachev_1@decs3o",
},
},
CreatedTime: 1676645275,
DeletedTime: 0,
ID: 132846,
Name: "std",
Status: "CONFIRMED",
UpdatedTime: 1676645275,
},
{
ACL: []RecordACL{
{
IsExplicit: true,
GUID: "",
Rights: "CXDRAU",
Status: "CONFIRMED",
Type: "U",
UgroupID: "not_really_timofey_tkachev_1@decs3o",
},
},
CreatedTime: 1676878820,
DeletedTime: 0,
ID: 132847,
Name: "std_2",
Status: "CONFIRMED",
UpdatedTime: 1676645275,
},
{
ACL: []RecordACL{
{
IsExplicit: true,
GUID: "",
Rights: "CXDRAU",
Status: "CONFIRMED",
Type: "U",
UgroupID: "timofey_tkachev_1@decs3o",
},
{
IsExplicit: true,
GUID: "",
Rights: "CXDRAU",
Status: "CONFIRMED",
Type: "U",
UgroupID: "second_account@decs3o",
},
},
CreatedTime: 1676883850,
DeletedTime: 1676883899,
ID: 132848,
Name: "std_broker",
Status: "DELETED",
UpdatedTime: 1676878820,
},
},
EntryCount: 3,
}
func TestFilterByID(t *testing.T) {
actual := accounts.FilterByID(132846).FindOne()
if actual.ID != 132846 {
t.Fatal("actual: ", actual.ID, " > expected: 132846")
}
}
func TestFilterByUserGroupId(t *testing.T) {
actual := accounts.FilterByUserGroupID("second_account@decs3o").FindOne()
for _, item := range actual.ACL {
if item.UgroupID == "second_account@decs3o" {
return
}
}
t.Fatal("second_account@decs3o has not been found. expected 1 found")
}
func TestFilterByName(t *testing.T) {
actual := accounts.FilterByName("std_broker").FindOne()
if actual.Name != "std_broker" {
t.Fatal("actual: ", actual.Name, " >> expected: std_broker")
}
}
func TestFilterByStatus(t *testing.T) {
actual := accounts.FilterByStatus("CONFIRMED")
if len(actual.Data) != 2 {
t.Fatal("Expected 2 elements in slice, found: ", len(actual.Data))
}
for _, item := range actual.Data {
if item.Status != "CONFIRMED" {
t.Fatal("expected CONFIRMED, found: ", item.Status)
}
}
}
func TestFilterFunc(t *testing.T) {
actual := accounts.FilterFunc(func(ia ItemAccount) bool {
return ia.DeletedTime == 0
})
for _, item := range actual.Data {
if item.DeletedTime != 0 {
t.Fatal("Expected DeletedTime = 0, found: ", item.DeletedTime)
}
}
}
func TestSortingByCreatedTime(t *testing.T) {
actual := accounts.SortByCreatedTime(false)
if actual.Data[0].Name != "std" {
t.Fatal("Expected account std as earliest, found: ", actual.Data[0].Name)
}
actual = accounts.SortByCreatedTime(true)
if actual.Data[0].Name != "std_broker" {
t.Fatal("Expected account std_broker as latest, found: ", actual.Data[0].Name)
}
}
func TestFilterEmpty(t *testing.T) {
actual := accounts.FilterByID(0)
if len(actual.Data) != 0 {
t.Fatal("Expected 0 found, actual: ", len(actual.Data))
}
}

View File

@@ -3,30 +3,25 @@ package account
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for get information about account // Request struct for get information about account
type GetRequest struct { type GetRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq GetRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
return nil
} }
// Get gets account details // Get gets account details
func (a Account) Get(ctx context.Context, req GetRequest) (*RecordAccount, error) { func (a Account) Get(ctx context.Context, req GetRequest) (*RecordAccount, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/get" url := "/cloudapi/account/get"

View File

@@ -3,23 +3,16 @@ package account
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for calculate the currently consumed units for all cloudspaces and resource groups in the account // Request struct for calculate the currently consumed units for all cloudspaces and resource groups in the account
type GetConsumedAccountUnitsRequest struct { type GetConsumedAccountUnitsRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq GetConsumedAccountUnitsRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
return nil
} }
// GetConsumedAccountUnits calculates the currently consumed units for all cloudspaces and resource groups in the account. // GetConsumedAccountUnits calculates the currently consumed units for all cloudspaces and resource groups in the account.
@@ -27,11 +20,14 @@ func (arq GetConsumedAccountUnitsRequest) validate() error {
// - CU_M: consumed memory in MB // - CU_M: consumed memory in MB
// - CU_C: number of cpu cores // - CU_C: number of cpu cores
// - CU_D: consumed vdisk storage in GB // - CU_D: consumed vdisk storage in GB
// - CU_DM: consumed max vdisk storage in GB
// - CU_I: number of public IPs // - CU_I: number of public IPs
func (a Account) GetConsumedAccountUnits(ctx context.Context, req GetConsumedAccountUnitsRequest) (*ResourceLimits, error) { func (a Account) GetConsumedAccountUnits(ctx context.Context, req GetConsumedAccountUnitsRequest) (*ResourceLimits, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/getConsumedAccountUnits" url := "/cloudapi/account/getConsumedAccountUnits"

View File

@@ -2,37 +2,21 @@ package account
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"github.com/rudecs/decort-sdk/internal/validators" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for calculate the currently consumed cloud units of the specified type for all cloudspaces and resource groups in the account // Request struct for calculate the currently consumed cloud units of the specified type for all cloudspaces and resource groups in the account
type GetConsumedCloudUnitsByTypeRequest struct { type GetConsumedCloudUnitsByTypeRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// Cloud unit resource type // Cloud unit resource type
// Required: true // Required: true
CUType string `url:"cutype"` CUType string `url:"cutype" json:"cutype" validate:"required,accountCUType"`
}
func (arq GetConsumedCloudUnitsByTypeRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
if arq.CUType == "" {
return errors.New("validation-error: field CUType can not be empty")
}
isValid := validators.StringInSlice(arq.CUType, []string{"CU_M", "CU_C", "CU_D", "CU_S", "CU_A", "CU_NO", "CU_I", "CU_NP"})
if !isValid {
return errors.New("validation-error: field AccessType can be only CU_M, CU_C, CU_D, CU_S, CU_A, CU_NO, CU_I or CU_NP")
}
return nil
} }
// GetConsumedCloudUnitsByType calculates the currently consumed cloud units of the specified type for all cloudspaces // GetConsumedCloudUnitsByType calculates the currently consumed cloud units of the specified type for all cloudspaces
@@ -42,15 +26,18 @@ func (arq GetConsumedCloudUnitsByTypeRequest) validate() error {
// - CU_M: returns consumed memory in MB // - CU_M: returns consumed memory in MB
// - CU_C: returns number of virtual cpu cores // - CU_C: returns number of virtual cpu cores
// - CU_D: returns consumed virtual disk storage in GB // - CU_D: returns consumed virtual disk storage in GB
// - CU_DM: returns consumed max virtual disk storage in GB
// - CU_S: returns consumed primary storage (NAS) in TB // - CU_S: returns consumed primary storage (NAS) in TB
// - CU_A: returns consumed secondary storage (Archive) in TB // - CU_A: returns consumed secondary storage (Archive) in TB
// - CU_NO: returns sent/received network transfer in operator in GB // - CU_NO: returns sent/received network transfer in operator in GB
// - CU_NP: returns sent/received network transfer peering in GB // - CU_NP: returns sent/received network transfer peering in GB
// - CU_I: returns number of public IPs // - CU_I: returns number of public IPs
func (a Account) GetConsumedCloudUnitsByType(ctx context.Context, req GetConsumedCloudUnitsByTypeRequest) (float64, error) { func (a Account) GetConsumedCloudUnitsByType(ctx context.Context, req GetConsumedCloudUnitsByTypeRequest) (float64, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return 0, err for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/getConsumedCloudUnitsByType" url := "/cloudapi/account/getConsumedCloudUnitsByType"

View File

@@ -2,47 +2,36 @@ package account
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for download the resources tracking files for an account // Request struct for download the resources tracking files for an account
type GetConsumtionRequest struct { type GetConsumptionRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// Epoch represents the start time // Epoch represents the start time
// Required: true // Required: true
Start uint64 `url:"start"` Start uint64 `url:"start" json:"start" validate:"required"`
// Epoch represents the end time // Epoch represents the end time
// Required: true // Required: true
End uint64 `url:"end"` End uint64 `url:"end" json:"end" validate:"required"`
} }
func (arq GetConsumtionRequest) validate() error { // GetConsumption downloads the resources tracking files for an account within a given period
if arq.AccountID == 0 { func (a Account) GetConsumption(ctx context.Context, req GetConsumptionRequest) (string, error) {
return errors.New("validation-error: field AccountID can not be empty or equal to 0") err := validators.ValidateRequest(req)
}
if arq.Start == 0 {
return errors.New("validation-error: field Start can not be empty or equal to 0")
}
if arq.End == 0 {
return errors.New("validation-error: field End can not be empty or equal to 0")
}
return nil
}
// GetConsumtion downloads the resources tracking files for an account within a given period
func (a Account) GetConsumtion(ctx context.Context, req GetConsumtionRequest) (string, error) {
err := req.validate()
if err != nil { if err != nil {
return "", err for _, validationError := range validators.GetErrors(err) {
return "", validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/getConsumtion" url := "/cloudapi/account/getConsumption"
res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil { if err != nil {
@@ -53,14 +42,16 @@ func (a Account) GetConsumtion(ctx context.Context, req GetConsumtionRequest) (s
} }
// GetConsumtionGet downloads the resources tracking files for an account within a given period // GetConsumptionGet downloads the resources tracking files for an account within a given period
func (a Account) GetConsumtionGet(ctx context.Context, req GetConsumtionRequest) (string, error) { func (a Account) GetConsumptionGet(ctx context.Context, req GetConsumptionRequest) (string, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return "", err for _, validationError := range validators.GetErrors(err) {
return "", validators.ValidationError(validationError)
}
} }
url := "/cloudapi//account/getConsumtion" url := "/cloudapi/account/getConsumption"
res, err := a.client.DecortApiCall(ctx, http.MethodGet, url, req) res, err := a.client.DecortApiCall(ctx, http.MethodGet, url, req)
if err != nil { if err != nil {

View File

@@ -3,23 +3,16 @@ package account
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for calculate the reserved units for all cloudspaces and resource groups in the account // Request struct for calculate the reserved units for all cloudspaces and resource groups in the account
type GetReservedAccountUnitsRequest struct { type GetReservedAccountUnitsRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq GetReservedAccountUnitsRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
return nil
} }
// GetReservedAccountUnits calculates the reserved units for all cloudspaces and resource groups in the account. // GetReservedAccountUnits calculates the reserved units for all cloudspaces and resource groups in the account.
@@ -28,11 +21,14 @@ func (arq GetReservedAccountUnitsRequest) validate() error {
// - CU_M: reserved memory in MB // - CU_M: reserved memory in MB
// - CU_C: number of cpu cores // - CU_C: number of cpu cores
// - CU_D: reserved vdisk storage in GB // - CU_D: reserved vdisk storage in GB
// - CU_DM: reserved max vdisk storage in GB
// - CU_I: number of public IPs // - CU_I: number of public IPs
func (a Account) GetReservedAccountUnits(ctx context.Context, req GetReservedAccountUnitsRequest) (*ResourceLimits, error) { func (a Account) GetReservedAccountUnits(ctx context.Context, req GetReservedAccountUnitsRequest) (*ResourceLimits, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/getReservedAccountUnits" url := "/cloudapi/account/getReservedAccountUnits"

View File

@@ -0,0 +1,42 @@
package account
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for getting resource consumption
type GetResourceConsumptionRequest struct {
// ID an account
// Required: true
AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
// GetResourceConsumption show amount of consumed and reserved resources (cpu, ram, disk) by specific account
func (a Account) GetResourceConsumption(ctx context.Context, req GetResourceConsumptionRequest) (*RecordResourceConsumption, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/account/getResourceConsumption"
info := RecordResourceConsumption{}
res, err := a.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
}

View File

@@ -8,17 +8,33 @@ import (
// Request struct for get list of accounts // Request struct for get list of accounts
type ListRequest struct { type ListRequest struct {
// Find by ID
// Required: false
ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"`
// Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by access control list
// Required: false
ACL string `url:"acl,omitempty" json:"acl,omitempty"`
// Find by status
// Required: false
Status string `url:"status,omitempty" json:"status,omitempty"`
// Page number // Page number
// Required: false // Required: false
Page uint64 `url:"page"` Page uint64 `url:"page,omitempty" json:"page,omitempty"`
// Page size // Page size
// Required: false // Required: false
Size uint64 `url:"size"` Size uint64 `url:"size,omitempty" json:"size,omitempty"`
} }
// List gets list all accounts the user has access to // List gets list all accounts the user has access to
func (a Account) List(ctx context.Context, req ListRequest) (ListAccounts, error) { func (a Account) List(ctx context.Context, req ListRequest) (*ListAccounts, error) {
url := "/cloudapi/account/list" url := "/cloudapi/account/list"
res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req)
@@ -33,5 +49,5 @@ func (a Account) List(ctx context.Context, req ListRequest) (ListAccounts, error
return nil, err return nil, err
} }
return list, nil return &list, nil
} }

View File

@@ -3,30 +3,65 @@ package account
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for a get list compute instances // Request struct for a get list compute instances
type ListComputesRequest struct { type ListComputesRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq ListComputesRequest) validate() error { // Find by compute id
if arq.AccountID == 0 { // Required: false
return errors.New("validation-error: field AccountID can not be empty or equal to 0") ComputeID uint64 `url:"computeId,omitempty" json:"computeId,omitempty"`
}
return nil // Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by resource group name
// Required: false
RGName string `url:"rgName,omitempty" json:"rgName,omitempty"`
// Find by resource group id
// Required: false
RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"`
// Find by tech status
// Required: false
TechStatus string `url:"techStatus,omitempty" json:"techStatus,omitempty"`
// Find by ip address
// Required: false
IPAddress string `url:"ipAddress,omitempty" json:"ipAddress,omitempty"`
// Find by external network name
// Required: false
ExtNetName string `url:"extNetName,omitempty" json:"extNetName,omitempty"`
// Find by external network id
// Required: false
ExtNetID uint64 `url:"extNetId,omitempty" json:"extNetId,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"`
} }
// ListComputes gets list all compute instances under specified account, accessible by the user // ListComputes gets list all compute instances under specified account, accessible by the user
func (a Account) ListComputes(ctx context.Context, req ListComputesRequest) (ListComputes, error) { func (a Account) ListComputes(ctx context.Context, req ListComputesRequest) (*ListComputes, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/listComputes" url := "/cloudapi/account/listComputes"
@@ -43,5 +78,5 @@ func (a Account) ListComputes(ctx context.Context, req ListComputesRequest) (Lis
return nil, err return nil, err
} }
return list, nil return &list, nil
} }

View File

@@ -10,15 +10,27 @@ import (
type ListDeletedRequest struct { type ListDeletedRequest struct {
// Page number // Page number
// Required: false // Required: false
Page uint64 `url:"page"` Page uint64 `url:"page,omitempty" json:"page,omitempty"`
// Page size // Page size
// Required: false // Required: false
Size uint64 `url:"size"` Size uint64 `url:"size,omitempty" json:"size,omitempty"`
// Find by ID
// Required: false
ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"`
// Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by access control list
// Required: false
ACL string `url:"acl,omitempty" json:"acl,omitempty"`
} }
// ListDeleted gets list all deleted accounts the user has access to // ListDeleted gets list all deleted accounts the user has access to
func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListAccounts, error) { func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListAccounts, error) {
url := "/cloudapi/account/listDeleted" url := "/cloudapi/account/listDeleted"
res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req)
@@ -33,5 +45,5 @@ func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListA
return nil, err return nil, err
} }
return list, nil return &list, nil
} }

View File

@@ -3,30 +3,49 @@ package account
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for get list deleted disks // Request struct for get list deleted disks
type ListDisksRequest struct { type ListDisksRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq ListDisksRequest) validate() error { // Find by disk id
if arq.AccountID == 0 { // Required: false
return errors.New("validation-error: field AccountID can not be empty or equal to 0") DiskID uint64 `url:"diskId,omitempty" json:"diskId,omitempty"`
}
return nil // Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by max size disk
// Required: false
DiskMaxSize uint64 `url:"diskMaxSize,omitempty" json:"diskMaxSize,omitempty"`
// Type of the disks
// Required: false
Type string `url:"type,omitempty" json:"type,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"`
} }
// ListDisks gets list all currently unattached disks under specified account // ListDisks gets list all currently unattached disks under specified account
func (a Account) ListDisks(ctx context.Context, req ListDisksRequest) (ListDisks, error) { func (a Account) ListDisks(ctx context.Context, req ListDisksRequest) (*ListDisks, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/listDisks" url := "/cloudapi/account/listDisks"
@@ -43,5 +62,5 @@ func (a Account) ListDisks(ctx context.Context, req ListDisksRequest) (ListDisks
return nil, err return nil, err
} }
return list, nil return &list, nil
} }

View File

@@ -3,30 +3,57 @@ package account
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for get list FLIPGroups // Request struct for get list FLIPGroups
type ListFLIPGroupsRequest struct { type ListFLIPGroupsRequest struct {
// ID an account // ID of the account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq ListFLIPGroupsRequest) validate() error { // Find by name
if arq.AccountID == 0 { // Required: false
return errors.New("validation-error: field AccountID can not be empty or equal to 0") Name string `url:"name,omitempty" json:"name,omitempty"`
}
return nil // Find by vinsId
// Required: false
VINSID uint64 `url:"vinsId,omitempty" json:"vinsId,omitempty"`
// Find by VINS name
// Required: false
VINSName string `url:"vinsName,omitempty" json:"vinsName,omitempty"`
// Find by external network id
// Required: false
ExtNetID uint64 `url:"extnetId,omitempty" json:"extnetId,omitempty"`
// Find by IP
// Required: false
ByIP string `url:"byIp,omitempty" json:"byIp,omitempty"`
// Find by flipGroup Id
// Required: false
FLIPGroupID uint64 `url:"flipGroupId,omitempty" json:"flipGroupId,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"`
} }
// ListFLIPGroups gets list all FLIPGroups under specified account, accessible by the user // ListFLIPGroups gets list all FLIPGroups under specified account, accessible by the user
func (a Account) ListFLIPGroups(ctx context.Context, req ListFLIPGroupsRequest) (ListFLIPGroups, error) { func (a Account) ListFLIPGroups(ctx context.Context, req ListFLIPGroupsRequest) (*ListFLIPGroups, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/listFlipGroups" url := "/cloudapi/account/listFlipGroups"
@@ -43,5 +70,5 @@ func (a Account) ListFLIPGroups(ctx context.Context, req ListFLIPGroupsRequest)
return nil, err return nil, err
} }
return list, nil return &list, nil
} }

View File

@@ -0,0 +1,26 @@
package account
import (
"context"
"encoding/json"
"net/http"
)
// ListResourceConsumption show data list amount of consumed and reserved resources (cpu, ram, disk) by specific accounts
func (a Account) ListResourceConsumption(ctx context.Context) (*ListResourceConsumption, error) {
url := "/cloudapi/account/listResourceConsumption"
info := ListResourceConsumption{}
res, err := a.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
}

View File

@@ -3,30 +3,53 @@ package account
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for get list resource groups // Request struct for get list resource groups
type ListRGRequest struct { type ListRGRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq ListRGRequest) validate() error { // Page number
if arq.AccountID == 0 { // Required: false
return errors.New("validation-error: field AccountID can not be empty or equal to 0") Page uint64 `url:"page,omitempty" json:"page,omitempty"`
}
return nil // Page size
// Required: false
Size uint64 `url:"size,omitempty" json:"size,omitempty"`
// Find by resource group id
// Required: false
RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"`
// Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by vinsId
// Required: false
VINSID uint64 `url:"vinsId,omitempty" json:"vinsId,omitempty"`
// Find by VM ID
// Required: false
VMID uint64 `url:"vmId,omitempty" json:"vmId,omitempty"`
// Find by status
// Required: false
Status string `url:"status,omitempty" json:"status,omitempty"`
} }
// ListRG gets list all resource groups under specified account, accessible by the user // ListRG gets list all resource groups under specified account, accessible by the user
func (a Account) ListRG(ctx context.Context, req ListRGRequest) (ListRG, error) { func (a Account) ListRG(ctx context.Context, req ListRGRequest) (*ListRG, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/listRG" url := "/cloudapi/account/listRG"
@@ -43,5 +66,5 @@ func (a Account) ListRG(ctx context.Context, req ListRGRequest) (ListRG, error)
return nil, err return nil, err
} }
return list, nil return &list, nil
} }

View File

@@ -3,34 +3,49 @@ package account
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for get list templates // Request struct for get list templates
type ListTemplatesRequest struct { type ListTemplatesRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// Include deleted images // Include deleted images
// Required: false // Required: false
IncludeDeleted bool `url:"includedeleted"` IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"`
}
func (arq ListTemplatesRequest) validate() error { // Find by image id
if arq.AccountID == 0 { // Required: false
return errors.New("validation-error: field AccountID can not be empty or equal to 0") ImageID uint64 `url:"imageId,omitempty" json:"imageId,omitempty"`
}
return nil // Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by type
// Required: false
Type string `url:"type,omitempty" json:"type,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"`
} }
// ListTemplates gets list templates which can be managed by this account // ListTemplates gets list templates which can be managed by this account
func (a Account) ListTemplates(ctx context.Context, req ListTemplatesRequest) (ListTemplates, error) { func (a Account) ListTemplates(ctx context.Context, req ListTemplatesRequest) (*ListTemplates, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/listTemplates" url := "/cloudapi/account/listTemplates"
@@ -47,5 +62,5 @@ func (a Account) ListTemplates(ctx context.Context, req ListTemplatesRequest) (L
return nil, err return nil, err
} }
return list, nil return &list, nil
} }

View File

@@ -3,30 +3,49 @@ package account
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for get list VINS // Request struct for get list VINS
type ListVINSRequest struct { type ListVINSRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq ListVINSRequest) validate() error { // Find by VINS ID
if arq.AccountID == 0 { // Required: false
return errors.New("validation-error: field AccountID can not be empty or equal to 0") VINSID uint64 `url:"vins,omitempty" json:"vinsId,omitempty"`
}
return nil // Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by resource group id
// Required: false
RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"`
// Find by external network ip
// Required: false
ExtIP string `url:"extIp,omitempty" json:"extIp,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"`
} }
// ListVINS gets list all ViNSes under specified account, accessible by the user // ListVINS gets list all ViNSes under specified account, accessible by the user
func (a Account) ListVINS(ctx context.Context, req ListVINSRequest) (ListVINS, error) { func (a Account) ListVINS(ctx context.Context, req ListVINSRequest) (*ListVINS, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/listVins" url := "/cloudapi/account/listVins"
@@ -43,5 +62,5 @@ func (a Account) ListVINS(ctx context.Context, req ListVINSRequest) (ListVINS, e
return nil, err return nil, err
} }
return list, nil return &list, nil
} }

View File

@@ -32,6 +32,9 @@ type ResourceLimits struct {
// Disk size, GB // Disk size, GB
CUD float64 `json:"CU_D"` CUD float64 `json:"CU_D"`
// Max disk size, GB
CUDM float64 `json:"CU_DM"`
// Number of public IP addresses // Number of public IP addresses
CUI float64 `json:"CU_I"` CUI float64 `json:"CU_I"`
@@ -70,7 +73,11 @@ type ItemAccount struct {
} }
// List of accounts // List of accounts
type ListAccounts []ItemAccount type ListAccounts struct {
Data []ItemAccount `json:"data"`
EntryCount uint64 `json:"entryCount"`
}
// Resources used // Resources used
type Resource struct { type Resource struct {
@@ -105,16 +112,33 @@ type DiskUsage struct {
DiskSize float64 `json:"disksize"` DiskSize float64 `json:"disksize"`
// Disk size max // Disk size max
DiskSizeMax uint64 `json:"disksizemax"` DiskSizeMax float64 `json:"disksizemax"`
}
// Information about resource consumption
type RecordResourceConsumption struct {
ItemResourceConsumption
// Resource limits
ResourceLimits ResourceLimits `json:"resourceLimits"`
} }
// Information about resources // Information about resources
type Resources struct { type ItemResourceConsumption struct {
// Current information about resources // Current information about resources
Current Resource `json:"Current"` Current Resource `json:"Current"`
// Reserved information about resources // Reserved information about resources
Reserved Resource `json:"Reserved"` Reserved Resource `json:"Reserved"`
// Account ID
AccountID uint64 `json:"id"`
}
type ListResourceConsumption struct {
Data []ItemResourceConsumption `json:"data"`
EntryCount uint64 `json:"entryCount"`
} }
// Information about computes // Information about computes
@@ -140,9 +164,6 @@ type RecordAccount struct {
// DCLocation // DCLocation
DCLocation string `json:"DCLocation"` DCLocation string `json:"DCLocation"`
// Resources
Resources Resources `json:"Resources"`
// CKey // CKey
CKey string `json:"_ckey"` CKey string `json:"_ckey"`
@@ -158,6 +179,12 @@ type RecordAccount struct {
// Computes // Computes
Computes Computes `json:"computes"` Computes Computes `json:"computes"`
// CPU allocation parameter
CPUAllocationParameter string `json:"cpu_allocation_parameter"`
// CPU allocation ratio
CPUAllocationRatio float64 `json:"cpu_allocation_ratio"`
// Created by // Created by
CreatedBy string `json:"createdBy"` CreatedBy string `json:"createdBy"`
@@ -165,7 +192,7 @@ type RecordAccount struct {
CreatedTime uint64 `json:"createdTime"` CreatedTime uint64 `json:"createdTime"`
// Deactivation time // Deactivation time
DeactivationTime uint64 `json:"deactivationTime"` DeactivationTime float64 `json:"deactivationTime"`
// Deleted by // Deleted by
DeletedBy string `json:"deletedBy"` DeletedBy string `json:"deletedBy"`
@@ -192,7 +219,7 @@ type RecordAccount struct {
ResourceLimits ResourceLimits `json:"resourceLimits"` ResourceLimits ResourceLimits `json:"resourceLimits"`
// Resource types // Resource types
ResourceTypes []string `json:"resourceTypes"` ResTypes []string `json:"resourceTypes"`
// Send access emails // Send access emails
SendAccessEmails bool `json:"sendAccessEmails"` SendAccessEmails bool `json:"sendAccessEmails"`
@@ -280,7 +307,13 @@ type ItemCompute struct {
} }
// List of computes // List of computes
type ListComputes []ItemCompute type ListComputes struct {
// Data
Data []ItemCompute `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about disk // Main information about disk
type ItemDisk struct { type ItemDisk struct {
@@ -307,7 +340,13 @@ type ItemDisk struct {
} }
// List of disks // List of disks
type ListDisks []ItemDisk type ListDisks struct {
// Data
Data []ItemDisk `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about VINS // Main information about VINS
type ItemVINS struct { type ItemVINS struct {
@@ -364,7 +403,13 @@ type ItemVINS struct {
} }
// List of VINS // List of VINS
type ListVINS []ItemVINS type ListVINS struct {
// Data
Data []ItemVINS `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main info about audit // Main info about audit
type ItemAudit struct { type ItemAudit struct {
@@ -478,7 +523,13 @@ type ItemRG struct {
} }
// List of Resource groups // List of Resource groups
type ListRG []ItemRG type ListRG struct {
// Data
Data []ItemRG `json:"data"`
// Enrtry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about template // Main information about template
type ItemTemplate struct { type ItemTemplate struct {
@@ -514,7 +565,13 @@ type ItemTemplate struct {
} }
// List of templates // List of templates
type ListTemplates []ItemTemplate type ListTemplates struct {
// Data
Data []ItemTemplate `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about FLIPGroup // Main information about FLIPGroup
type ItemFLIPGroup struct { type ItemFLIPGroup struct {
@@ -583,4 +640,10 @@ type ItemFLIPGroup struct {
} }
// List of FLIPGroups // List of FLIPGroups
type ListFLIPGroups []ItemFLIPGroup type ListFLIPGroups struct {
// Data
Data []ItemFLIPGroup `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}

View File

@@ -2,44 +2,32 @@ package account
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for restore a deleted account // Request struct for restore a deleted account
type RestoreRequest struct { type RestoreRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
func (arq RestoreRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
return nil
} }
// Restore restores a deleted account // Restore restores a deleted account
func (a Account) Restore(ctx context.Context, req RestoreRequest) (bool, error) { func (a Account) Restore(ctx context.Context, req RestoreRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/restore" url := "/cloudapi/account/restore"
res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) _, err = a.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil { if err != nil {
return false, err return false, err
} }
result, err := strconv.ParseBool(string(res)) return true, nil
if err != nil {
return false, err
}
return result, nil
} }

View File

@@ -0,0 +1,43 @@
package account
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 (la ListAccounts) Serialize(params ...string) (serialization.Serialized, error) {
if len(la.Data) == 0 {
return []byte{}, nil
}
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(la, prefix, indent)
}
return json.Marshal(la)
}
// 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 (ia ItemAccount) Serialize(params ...string) (serialization.Serialized, error) {
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(ia, prefix, indent)
}
return json.Marshal(ia)
}

View File

@@ -0,0 +1,60 @@
package account
import "sort"
// SortByCreatedTime sorts ListAccounts by the CreatedTime field in ascending order.
//
// If inverse param is set to true, the order is reversed.
func (la ListAccounts) SortByCreatedTime(inverse bool) ListAccounts {
if len(la.Data) < 2 {
return la
}
sort.Slice(la.Data, func(i, j int) bool {
if inverse {
return la.Data[i].CreatedTime > la.Data[j].CreatedTime
}
return la.Data[i].CreatedTime < la.Data[j].CreatedTime
})
return la
}
// SortByUpdatedTime sorts ListAccounts by the UpdatedTime field in ascending order.
//
// If inverse param is set to true, the order is reversed.
func (la ListAccounts) SortByUpdatedTime(inverse bool) ListAccounts {
if len(la.Data) < 2 {
return la
}
sort.Slice(la.Data, func(i, j int) bool {
if inverse {
return la.Data[i].UpdatedTime > la.Data[j].UpdatedTime
}
return la.Data[i].UpdatedTime < la.Data[j].UpdatedTime
})
return la
}
// SortByDeletedTime sorts ListAccounts by the DeletedTime field in ascending order.
//
// If inverse param is set to true, the order is reversed.
func (la ListAccounts) SortByDeletedTime(inverse bool) ListAccounts {
if len(la.Data) < 2 {
return la
}
sort.Slice(la.Data, func(i, j int) bool {
if inverse {
return la.Data[i].DeletedTime > la.Data[j].DeletedTime
}
return la.Data[i].DeletedTime < la.Data[j].DeletedTime
})
return la
}

View File

@@ -2,63 +2,58 @@ package account
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for updaate account // Request struct for updaate account
type UpdateRequest struct { type UpdateRequest struct {
// ID an account // ID an account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// Name of the account // Name of the account
// Required: false // Required: false
Name string `url:"name,omitempty"` Name string `url:"name,omitempty" json:"name,omitempty"`
// Max size of memory in MB // Max size of memory in MB
// Required: false // Required: false
MaxMemoryCapacity uint64 `url:"maxMemoryCapacity,omitempty"` MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
// Max size of aggregated vdisks in GB // Max size of aggregated vdisks in GB
// Required: false // Required: false
MaxVDiskCapacity uint64 `url:"maxVDiskCapacity,omitempty"` MaxVDiskCapacity int64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
// Max number of CPU cores // Max number of CPU cores
// Required: false // Required: false
MaxCPUCapacity uint64 `url:"maxCPUCapacity,omitempty"` MaxCPUCapacity int64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
// Max sent/received network transfer peering // Max sent/received network transfer peering
// Required: false // Required: false
MaxNetworkPeerTransfer uint64 `url:"maxNetworkPeerTransfer,omitempty"` MaxNetworkPeerTransfer int64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
// Max number of assigned public IPs // Max number of assigned public IPs
// Required: false // Required: false
MaxNumPublicIP uint64 `url:"maxNumPublicIP,omitempty"` MaxNumPublicIP int64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
// If true send emails when a user is granted access to resources // If true send emails when a user is granted access to resources
// Required: false // Required: false
SendAccessEmails bool `url:"sendAccessEmails,omitempty"` SendAccessEmails bool `url:"sendAccessEmails" json:"sendAccessEmails"`
// Limit (positive) or disable (0) GPU resources // Limit (positive) or disable (0) GPU resources
// Required: false // Required: false
GPUUnits uint64 `url:"gpu_units,omitempty"` GPUUnits int64 `url:"gpu_units,omitempty" json:"gpu_units,omitempty"`
}
func (arq UpdateRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
return nil
} }
// Update updates an account name and resource types and limits // Update updates an account name and resource types and limits
func (a Account) Update(ctx context.Context, req UpdateRequest) (bool, error) { func (a Account) Update(ctx context.Context, req UpdateRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/update" url := "/cloudapi/account/update"

View File

@@ -2,54 +2,37 @@ package account
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"github.com/rudecs/decort-sdk/internal/validators" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for update user access rights // Request struct for update user access rights
type UpdateUserRequest struct { type UpdateUserRequest struct {
// ID of the account // ID of the account
// Required: true // Required: true
AccountID uint64 `url:"accountId"` AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// Userid/Email for registered users or emailaddress for unregistered users // Userid/Email for registered users or emailaddress for unregistered users
// Required: true // Required: true
UserID string `url:"userId"` UserID string `url:"userId" json:"userId" validate:"required"`
// Account permission types: // Account permission types:
// - 'R' for read only access // - 'R' for read only access
// - 'RCX' for Write // - 'RCX' for Write
// - 'ARCXDU' for Admin // - 'ARCXDU' for Admin
// Required: true // Required: true
AccessType string `url:"accesstype"` AccessType string `url:"accesstype" json:"accesstype" validate:"required,accessType"`
}
func (arq UpdateUserRequest) validate() error {
if arq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
if arq.UserID == "" {
return errors.New("validation-error: field UserID can not be empty")
}
if arq.AccessType == "" {
return errors.New("validation-error: field AccessType can not be empty")
}
isValid := validators.StringInSlice(arq.AccessType, []string{"R", "RCX", "ARCXDU"})
if !isValid {
return errors.New("validation-error: field AccessType can be only R, RCX or ARCXDU")
}
return nil
} }
// UpdateUser updates user access rights // UpdateUser updates user access rights
func (a Account) UpdateUser(ctx context.Context, req UpdateUserRequest) (bool, error) { func (a Account) UpdateUser(ctx context.Context, req UpdateUserRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/account/updateUser" url := "/cloudapi/account/updateUser"

View File

@@ -1,6 +1,6 @@
package cloudapi package cloudapi
import "github.com/rudecs/decort-sdk/pkg/cloudapi/bservice" import "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice"
// Accessing the BService method group // Accessing the BService method group
func (ca *CloudAPI) BService() *bservice.BService { func (ca *CloudAPI) BService() *bservice.BService {

View File

@@ -1,7 +1,7 @@
// API Actor for managing Compute Group. This actor is a final API for endusers to manage Compute Group // API Actor for managing Compute Group. This actor is a final API for endusers to manage Compute Group
package bservice package bservice
import "github.com/rudecs/decort-sdk/interfaces" import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
// Structure for creating request to bservice // Structure for creating request to bservice
type BService struct { type BService struct {

View File

@@ -2,46 +2,38 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for BasicService // Request struct for BasicService
type CreateRequest struct { type CreateRequest struct {
// Name of the service // Name of the service
// Required: true // Required: true
Name string `url:"name"` Name string `url:"name" json:"name" validate:"required"`
// ID of the Resource Group where this service will be placed // ID of the Resource Group where this service will be placed
// Required: true // Required: true
RGID uint64 `url:"rgId"` RGID uint64 `url:"rgId" json:"rgId" validate:"required"`
// Name of the user to deploy SSH key for. Pass empty string if no SSH key deployment is required // Name of the user to deploy SSH key for. Pass empty string if no SSH key deployment is required
// Required: false // Required: false
SSHUser string `url:"sshUser,omitempty"` SSHUser string `url:"sshUser,omitempty" json:"sshUser,omitempty"`
// SSH key to deploy for the specified user. Same key will be deployed to all computes of the service // SSH key to deploy for the specified user. Same key will be deployed to all computes of the service
// Required: false // Required: false
SSHKey string `url:"sshKey,omitempty"` SSHKey string `url:"sshKey,omitempty" json:"sshKey,omitempty"`
}
func (bsrq CreateRequest) validate() error {
if bsrq.Name == "" {
return errors.New("field Name can not be empty")
}
if bsrq.RGID == 0 {
return errors.New("field RGID can not be empty or equal to 0")
}
return nil
} }
// Create creates blank BasicService instance // Create creates blank BasicService instance
func (b BService) Create(ctx context.Context, req CreateRequest) (uint64, error) { func (b BService) Create(ctx context.Context, req CreateRequest) (uint64, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return 0, err for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/create" url := "/cloudapi/bservice/create"

View File

@@ -2,35 +2,30 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for delete basic service // Request struct for delete basic service
type DeleteRequest struct { type DeleteRequest struct {
// ID of the BasicService to be delete // ID of the BasicService to be delete
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// If set to False, Basic service will be deleted to recycle bin. Otherwise destroyed immediately // If set to False, Basic service will be deleted to recycle bin. Otherwise destroyed immediately
// Required: true // Required: false
Permanently bool `url:"permanently,omitempty"` Permanently bool `url:"permanently,omitempty" json:"permanently,omitempty"`
}
func (bsrq DeleteRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
return nil
} }
// Delete deletes BasicService instance // Delete deletes BasicService instance
func (b BService) Delete(ctx context.Context, req DeleteRequest) (bool, error) { func (b BService) Delete(ctx context.Context, req DeleteRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/delete" url := "/cloudapi/bservice/delete"

View File

@@ -2,33 +2,28 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for disable service // Request struct for disable service
type DisableRequest struct { type DisableRequest struct {
// ID of the service to disable // ID of the service to disable
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
}
func (bsrq DisableRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
return nil
} }
// Disable disables service. // Disable disables service.
// Disabling a service technically means setting model status // Disabling a service technically means setting model status
// of all computes and service itself to DISABLED and stopping all computes. // of all computes and service itself to DISABLED and stopping all computes.
func (b BService) Disable(ctx context.Context, req DisableRequest) (bool, error) { func (b BService) Disable(ctx context.Context, req DisableRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/delete" url := "/cloudapi/bservice/delete"

View File

@@ -2,24 +2,17 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for disable service // Request struct for disable service
type EnableRequest struct { type EnableRequest struct {
// ID of the service to enable // ID of the service to enable
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
}
func (bsrq EnableRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
return nil
} }
// Enable enables service. // Enable enables service.
@@ -27,9 +20,11 @@ func (bsrq EnableRequest) validate() error {
// all computes and service itself to ENABLED. // all computes and service itself to ENABLED.
// It does not start computes. // It does not start computes.
func (b BService) Enable(ctx context.Context, req EnableRequest) (bool, error) { func (b BService) Enable(ctx context.Context, req EnableRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/enable" url := "/cloudapi/bservice/enable"

View File

@@ -0,0 +1,71 @@
package bservice
// FilterByID returns ListBasicServices with specified ID.
func (lbs ListBasicServices) FilterByID(id uint64) ListBasicServices {
predicate := func(ibs ItemBasicService) bool {
return ibs.ID == id
}
return lbs.FilterFunc(predicate)
}
// FilterByName returns ListBasicServices with specified Name.
func (lbs ListBasicServices) FilterByName(name string) ListBasicServices {
predicate := func(ibs ItemBasicService) bool {
return ibs.Name == name
}
return lbs.FilterFunc(predicate)
}
// FilterByRGID returns ListBasicServices with specified RGID.
func (lbs ListBasicServices) FilterByRGID(rgID uint64) ListBasicServices {
predicate := func(ibs ItemBasicService) bool {
return ibs.RGID == rgID
}
return lbs.FilterFunc(predicate)
}
// FilterByStatus returns ListBasicServices with specified Status.
func (lbs ListBasicServices) FilterByStatus(status string) ListBasicServices {
predicate := func(ibs ItemBasicService) bool {
return ibs.Status == status
}
return lbs.FilterFunc(predicate)
}
// FilterByTechStatus returns ListBasicServices with specified TechStatus.
func (lbs ListBasicServices) FilterByTechStatus(techStatus string) ListBasicServices {
predicate := func(ibs ItemBasicService) bool {
return ibs.TechStatus == techStatus
}
return lbs.FilterFunc(predicate)
}
// FilterFunc allows filtering ListResourceGroups based on a user-specified predicate.
func (lbs ListBasicServices) FilterFunc(predicate func(ItemBasicService) bool) ListBasicServices {
var result ListBasicServices
for _, item := range lbs.Data {
if predicate(item) {
result.Data = append(result.Data, item)
}
}
result.EntryCount = uint64(len(lbs.Data))
return result
}
// FindOne returns first found ItemBasicService
// If none was found, returns an empty struct.
func (lbs ListBasicServices) FindOne() ItemBasicService {
if lbs.EntryCount == 0 {
return ItemBasicService{}
}
return lbs.Data[0]
}

View File

@@ -0,0 +1,155 @@
package bservice
import "testing"
var bservices = ListBasicServices{
Data: []ItemBasicService{
{
AccountID: 1,
AccountName: "std_1",
BaseDomain: "",
CreatedBy: "sample_user_1@decs3o",
CreatedTime: 1677743675,
DeletedBy: "",
DeletedTime: 0,
GID: 212,
Groups: []uint64{},
GUID: 1,
ID: 1,
Name: "bservice_1",
ParentSrvID: 0,
ParentSrvType: "",
RGID: 7971,
RGName: "rg_1",
SSHUser: "",
Status: "CREATED",
TechStatus: "STOPPED",
UpdatedBy: "",
UpdatedTime: 0,
UserManaged: true,
},
{
AccountID: 2,
AccountName: "std_2",
BaseDomain: "",
CreatedBy: "sample_user_1@decs3o",
CreatedTime: 1677743736,
DeletedBy: "",
DeletedTime: 0,
GID: 212,
Groups: []uint64{},
GUID: 2,
ID: 2,
Name: "bservice_2",
ParentSrvID: 0,
ParentSrvType: "",
RGID: 7972,
RGName: "rg_2",
SSHUser: "",
Status: "CREATED",
TechStatus: "STOPPED",
UpdatedBy: "",
UpdatedTime: 0,
UserManaged: true,
},
{
AccountID: 3,
AccountName: "std_3",
BaseDomain: "",
CreatedBy: "sample_user_2@decs3o",
CreatedTime: 1677743830,
DeletedBy: "",
DeletedTime: 0,
GID: 212,
Groups: []uint64{},
GUID: 3,
ID: 3,
Name: "bservice_3",
ParentSrvID: 0,
ParentSrvType: "",
RGID: 7973,
RGName: "rg_3",
SSHUser: "",
Status: "ENABLED",
TechStatus: "STARTED",
UpdatedBy: "",
UpdatedTime: 0,
UserManaged: true,
},
},
EntryCount: 3,
}
func TestFilterByID(t *testing.T) {
actual := bservices.FilterByID(1).FindOne()
if actual.ID != 1 {
t.Fatal("expected ID 1, found: ", actual.ID)
}
}
func TestFilterByName(t *testing.T) {
actual := bservices.FilterByName("bservice_3").FindOne()
if actual.Name != "bservice_3" {
t.Fatal("expected Name 'bservice_3', found: ", actual.Name)
}
}
func TestFilterByRGID(t *testing.T) {
actual := bservices.FilterByRGID(7971).FindOne()
if actual.RGID != 7971 {
t.Fatal("expected RGID 7971, found: ", actual.RGID)
}
}
func TestFilterByStatus(t *testing.T) {
actual := bservices.FilterByStatus("CREATED")
if len(actual.Data) != 2 {
t.Fatal("expected 2 found, actual: ", len(actual.Data))
}
for _, item := range actual.Data {
if item.Status != "CREATED" {
t.Fatal("expected Status 'CREATED', found: ", item.Status)
}
}
}
func TestFilterByTechStatus(t *testing.T) {
actual := bservices.FilterByTechStatus("STOPPED")
if len(actual.Data) != 2 {
t.Fatal("expected 2 found, actual: ", len(actual.Data))
}
for _, item := range actual.Data {
if item.TechStatus != "STOPPED" {
t.Fatal("expected TechStatus 'STOPPED', found: ", item.TechStatus)
}
}
}
func TestFilterFunc(t *testing.T) {
actual := bservices.FilterFunc(func(ibs ItemBasicService) bool {
return ibs.CreatedBy == "sample_user_2@decs3o"
})
if len(actual.Data) > 1 {
t.Fatal("expected 1 found, actual: ", len(actual.Data))
}
if actual.FindOne().CreatedBy != "sample_user_2@decs3o" {
t.Fatal("expected 'sample_user_2@decs3o', found: ", actual.FindOne().CreatedBy)
}
}
func TestSortByCreatedTime(t *testing.T) {
actual := bservices.SortByCreatedTime(true)
if actual.Data[0].CreatedTime != 1677743830 || actual.Data[2].CreatedTime != 1677743675 {
t.Fatal("expected descending order, found ascending")
}
}

View File

@@ -3,30 +3,25 @@ package bservice
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for get detailed information about service // Request struct for get detailed information about service
type GetRequest struct { type GetRequest struct {
// ID of the service to query information // ID of the service to query information
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
}
func (bsrq GetRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
return nil
} }
// Get gets detailed specifications for the BasicService. // Get gets detailed specifications for the BasicService.
func (b BService) Get(ctx context.Context, req GetRequest) (*RecordBasicService, error) { func (b BService) Get(ctx context.Context, req GetRequest) (*RecordBasicService, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/get" url := "/cloudapi/bservice/get"

View File

@@ -2,109 +2,83 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for create new compute group within BasicService // Request struct for create new compute group within BasicService
type GroupAddRequest struct { type GroupAddRequest struct {
// ID of the Basic Service to add a group to // ID of the Basic Service to add a group to
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// Name of the Compute Group to add // Name of the Compute Group to add
// Required: true // Required: true
Name string `url:"name"` Name string `url:"name" json:"name" validate:"required"`
// Computes number. Defines how many computes must be there in the group // Computes number. Defines how many computes must be there in the group
// Required: true // Required: true
Count uint64 `url:"count"` Count uint64 `url:"count" json:"count" validate:"required"`
// Compute CPU number. All computes in the group have the same CPU count // Compute CPU number. All computes in the group have the same CPU count
// Required: true // Required: true
CPU uint64 `url:"cpu"` CPU uint64 `url:"cpu" json:"cpu" validate:"required"`
// Compute RAM volume in MB. All computes in the group have the same RAM volume // Compute RAM volume in MB. All computes in the group have the same RAM volume
// Required: true // Required: true
RAM uint64 `url:"ram"` RAM uint64 `url:"ram" json:"ram" validate:"required"`
// Compute boot disk size in GB // Compute boot disk size in GB
// Required: true // Required: true
Disk uint64 `url:"disk"` Disk uint64 `url:"disk" json:"disk" validate:"required"`
// OS image ID to create computes from // OS image ID to create computes from
// Required: true // Required: true
ImageID uint64 `url:"imageId"` ImageID uint64 `url:"imageId" json:"imageId" validate:"required"`
// Compute driver // Compute driver
// should be one of: // should be one of:
// - KVM_X86 // - KVM_X86
// - KVM_PPC // - KVM_PPC
// Required: true // Required: true
Driver string `url:"driver"` Driver string `url:"driver" json:"driver" validate:"driver"`
// Storage endpoint provider ID // Storage endpoint provider ID
// Required: false // Required: false
SEPID uint64 `url:"sepId,omitempty"` SEPID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`
// Pool to use if sepId is set, can be also empty if needed to be chosen by system // Pool to use if sepId is set, can be also empty if needed to be chosen by system
// Required: false // Required: false
SEPPool string `url:"sepPool,omitempty"` SEPPool string `url:"sepPool,omitempty" json:"sepPool,omitempty"`
// Group role tag. Can be empty string, does not have to be unique // Group role tag. Can be empty string, does not have to be unique
// Required: false // Required: false
Role string `url:"role,omitempty"` Role string `url:"role,omitempty" json:"role,omitempty"`
// List of ViNSes to connect computes to // List of ViNSes to connect computes to
// Required: false // Required: false
VINSes []uint64 `url:"vinses,omitempty"` VINSes []uint64 `url:"vinses,omitempty" json:"vinses,omitempty"`
// List of external networks to connect computes to // List of external networks to connect computes to
// Required: false // Required: false
ExtNets []uint64 `url:"extnets,omitempty"` ExtNets []uint64 `url:"extnets,omitempty" json:"extnets,omitempty"`
// Time of Compute Group readiness // Time of Compute Group readiness
// Required: false // Required: false
TimeoutStart uint64 `url:"timeoutStart"` TimeoutStart uint64 `url:"timeoutStart,omitempty" json:"timeoutStart,omitempty"`
}
func (bsrq GroupAddRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.Name == "" {
return errors.New("field Name can not be empty")
}
if bsrq.Count == 0 {
return errors.New("field Count can not be empty or equal to 0")
}
if bsrq.CPU == 0 {
return errors.New("field CPU can not be empty or equal to 0")
}
if bsrq.RAM == 0 {
return errors.New("field RAM can not be empty or equal to 0")
}
if bsrq.Disk == 0 {
return errors.New("field Disk can not be empty or equal to 0")
}
if bsrq.ImageID == 0 {
return errors.New("field ImageID can not be empty or equal to 0")
}
if bsrq.Driver == "" {
return errors.New("field Driver can not be empty")
}
return nil
} }
// GroupAdd creates new Compute Group within BasicService. // GroupAdd creates new Compute Group within BasicService.
// Compute Group is NOT started automatically, // Compute Group is NOT started automatically,
// so you need to explicitly start it // so you need to explicitly start it
func (b BService) GroupAdd(ctx context.Context, req GroupAddRequest) (uint64, error) { func (b BService) GroupAdd(ctx context.Context, req GroupAddRequest) (uint64, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return 0, err for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupAdd" url := "/cloudapi/bservice/groupAdd"

View File

@@ -2,45 +2,34 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for remove group compute // Request struct for remove group compute
type GroupComputeRemoveRequest struct { type GroupComputeRemoveRequest struct {
// ID of the Basic Service // ID of the Basic Service
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute GROUP // ID of the Compute GROUP
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
// ID of the Compute // ID of the Compute
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
func (bsrq GroupComputeRemoveRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
if bsrq.ComputeID == 0 {
return errors.New("field ComputeID can not be empty or equal to 0")
}
return nil
} }
// GroupComputeRemove makes group compute remove of the Basic Service // GroupComputeRemove makes group compute remove of the Basic Service
func (b BService) GroupComputeRemove(ctx context.Context, req GroupComputeRemoveRequest) (bool, error) { func (b BService) GroupComputeRemove(ctx context.Context, req GroupComputeRemoveRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupComputeRemove" url := "/cloudapi/bservice/groupComputeRemove"

View File

@@ -3,37 +3,29 @@ package bservice
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for get detailed information about Compute Group // Request struct for get detailed information about Compute Group
type GroupGetRequest struct { type GroupGetRequest struct {
// ID of the Basic Service of Compute Group // ID of the Basic Service of Compute Group
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute Group // ID of the Compute Group
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
}
func (bsrq GroupGetRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
return nil
} }
// GroupGet gets detailed specifications for the Compute Group // GroupGet gets detailed specifications for the Compute Group
func (b BService) GroupGet(ctx context.Context, req GroupGetRequest) (*RecordGroup, error) { func (b BService) GroupGet(ctx context.Context, req GroupGetRequest) (*RecordGroup, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupGet" url := "/cloudapi/bservice/groupGet"

View File

@@ -2,9 +2,10 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for add parent Compute Group relation emove parent Compute Group // Request struct for add parent Compute Group relation emove parent Compute Group
@@ -12,36 +13,24 @@ import (
type GroupParentAddRequest struct { type GroupParentAddRequest struct {
// ID of the Basic Service of Compute Group // ID of the Basic Service of Compute Group
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute Group // ID of the Compute Group
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
// ID of the parent Compute Group to register with the current Compute Group // ID of the parent Compute Group to register with the current Compute Group
// Required: true // Required: true
ParentID uint64 `url:"parentId"` ParentID uint64 `url:"parentId" json:"parentId" validate:"required"`
}
func (bsrq GroupParentAddRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
if bsrq.ParentID == 0 {
return errors.New("field ParentID can not be empty or equal to 0")
}
return nil
} }
// GroupParentAdd add parent Compute Group relation to the specified Compute Group // GroupParentAdd add parent Compute Group relation to the specified Compute Group
func (b BService) GroupParentAdd(ctx context.Context, req GroupParentAddRequest) (bool, error) { func (b BService) GroupParentAdd(ctx context.Context, req GroupParentAddRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupParentAdd" url := "/cloudapi/bservice/groupParentAdd"

View File

@@ -2,9 +2,10 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for remove parent Compute Group // Request struct for remove parent Compute Group
@@ -12,37 +13,25 @@ import (
type GroupParentRemoveRequest struct { type GroupParentRemoveRequest struct {
// ID of the Basic Service of Compute Group // ID of the Basic Service of Compute Group
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute Group // ID of the Compute Group
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
// ID of the parent Compute Group // ID of the parent Compute Group
// to remove from the current Compute Group // to remove from the current Compute Group
// Required: true // Required: true
ParentID uint64 `url:"parentId"` ParentID uint64 `url:"parentId" json:"parentId" validate:"required"`
}
func (bsrq GroupParentRemoveRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
if bsrq.ParentID == 0 {
return errors.New("field ParentID can not be empty or equal to 0")
}
return nil
} }
// GroupParentRemove removes parent Compute Group relation to the specified Compute Group // GroupParentRemove removes parent Compute Group relation to the specified Compute Group
func (b BService) GroupParentRemove(ctx context.Context, req GroupParentRemoveRequest) (bool, error) { func (b BService) GroupParentRemove(ctx context.Context, req GroupParentRemoveRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupParentRemove" url := "/cloudapi/bservice/groupParentRemove"

View File

@@ -2,38 +2,30 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for destroy the specified Compute Group // Request struct for destroy the specified Compute Group
type GroupRemoveRequest struct { type GroupRemoveRequest struct {
// ID of the Basic Service of Compute Group // ID of the Basic Service of Compute Group
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute Group // ID of the Compute Group
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
}
func (bsrq GroupRemoveRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
return nil
} }
// GroupRemove destroy the specified Compute Group // GroupRemove destroy the specified Compute Group
func (b BService) GroupRemove(ctx context.Context, req GroupRemoveRequest) (bool, error) { func (b BService) GroupRemove(ctx context.Context, req GroupRemoveRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupRemove" url := "/cloudapi/bservice/groupRemove"

View File

@@ -2,58 +2,41 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"github.com/rudecs/decort-sdk/internal/validators" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for resize the group // Request struct for resize the group
type GroupResizeRequest struct { type GroupResizeRequest struct {
// ID of the Basic Service of Compute Group // ID of the Basic Service of Compute Group
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute Group to resize // ID of the Compute Group to resize
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
// Either delta or absolute value of computes // Either delta or absolute value of computes
// Required: true // Required: true
Count int64 `url:"count"` Count int64 `url:"count" json:"count" validate:"required"`
// Either delta or absolute value of computes // Either delta or absolute value of computes
// Should be one of: // Should be one of:
// - ABSOLUTE // - ABSOLUTE
// - RELATIVE // - RELATIVE
// Required: true // Required: true
Mode string `url:"mode"` Mode string `url:"mode" json:"mode" validate:"bserviceMode"`
}
func (bsrq GroupResizeRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
if bsrq.Mode == "RELATIVE" && bsrq.Count == 0 {
return errors.New("field Count can not be equal to 0 if Mode if 'RELATIVE'")
}
validate := validators.StringInSlice(bsrq.Mode, []string{"RELATIVE", "ABSOLUTE"})
if !validate {
return errors.New("field Mode can only be one of 'RELATIVE' or 'ABSOLUTE'")
}
return nil
} }
// GroupResize resize the group by changing the number of computes // GroupResize resize the group by changing the number of computes
func (b BService) GroupResize(ctx context.Context, req GroupResizeRequest) (uint64, error) { func (b BService) GroupResize(ctx context.Context, req GroupResizeRequest) (uint64, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return 0, err for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupResize" url := "/cloudapi/bservice/groupResize"

View File

@@ -2,38 +2,30 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for start the specified Compute Group // Request struct for start the specified Compute Group
type GroupStartRequest struct { type GroupStartRequest struct {
// ID of the Basic Service of Compute Group // ID of the Basic Service of Compute Group
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute Group to start // ID of the Compute Group to start
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
}
func (bsrq GroupStartRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
return nil
} }
// GroupStart starts the specified Compute Group within BasicService // GroupStart starts the specified Compute Group within BasicService
func (b BService) GroupStart(ctx context.Context, req GroupStartRequest) (bool, error) { func (b BService) GroupStart(ctx context.Context, req GroupStartRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupStart" url := "/cloudapi/bservice/groupStart"

View File

@@ -2,42 +2,34 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for stop the specified Compute Group // Request struct for stop the specified Compute Group
type GroupStopRequest struct { type GroupStopRequest struct {
// ID of the Basic Service of Compute Group // ID of the Basic Service of Compute Group
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute Group to stop // ID of the Compute Group to stop
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
// Force stop Compute Group // Force stop Compute Group
// Required: true // Required: false
Force bool `url:"force,omitempty"` Force bool `url:"force,omitempty" json:"force,omitempty"`
}
func (bsrq GroupStopRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
return nil
} }
// GroupStop stops the specified Compute Group within BasicService // GroupStop stops the specified Compute Group within BasicService
func (b BService) GroupStop(ctx context.Context, req GroupStopRequest) (bool, error) { func (b BService) GroupStop(ctx context.Context, req GroupStopRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupStop" url := "/cloudapi/bservice/groupStop"

View File

@@ -2,62 +2,54 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for update existing Compute group // Request struct for update existing Compute group
type GroupUpdateRequest struct { type GroupUpdateRequest struct {
// ID of the Basic Service of Compute Group // ID of the Basic Service of Compute Group
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute Group // ID of the Compute Group
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
// Specify non-empty string to update Compute Group name // Specify non-empty string to update Compute Group name
// Required: false // Required: false
Name string `url:"name,omitempty"` Name string `url:"name,omitempty" json:"name,omitempty"`
// Specify non-empty string to update group role // Specify non-empty string to update group role
// Required: false // Required: false
Role string `url:"role,omitempty"` Role string `url:"role,omitempty" json:"role,omitempty"`
// Specify positive value to set new compute CPU count // Specify positive value to set new compute CPU count
// Required: false // Required: false
CPU uint64 `url:"cpu,omitempty"` CPU uint64 `url:"cpu,omitempty" json:"cpu,omitempty"`
// Specify positive value to set new compute RAM volume in MB // Specify positive value to set new compute RAM volume in MB
// Required: false // Required: false
RAM uint64 `url:"ram,omitempty"` RAM uint64 `url:"ram,omitempty" json:"ram,omitempty"`
// Specify new compute boot disk size in GB // Specify new compute boot disk size in GB
// Required: false // Required: false
Disk uint64 `url:"disk,omitempty"` Disk uint64 `url:"disk,omitempty" json:"disk,omitempty"`
// Force resize Compute Group // Force resize Compute Group
// Required: false // Required: false
Force bool `url:"force,omitempty"` Force bool `url:"force,omitempty" json:"force,omitempty"`
}
func (bsrq GroupUpdateRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
return nil
} }
// GroupUpdate updates existing Compute group within Basic Service and apply new settings to its computes as necessary // 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) { func (b BService) GroupUpdate(ctx context.Context, req GroupUpdateRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupUpdate" url := "/cloudapi/bservice/groupUpdate"

View File

@@ -2,42 +2,34 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for update External Network settings // Request struct for update External Network settings
type GroupUpdateExtNetRequest struct { type GroupUpdateExtNetRequest struct {
// ID of the Basic Service of Compute Group // ID of the Basic Service of Compute Group
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute Group // ID of the Compute Group
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
// List of Extnets to connect computes // List of Extnets to connect computes
// Required: false // Required: false
ExtNets []uint64 `url:"extnets,omitempty"` ExtNets []uint64 `url:"extnets,omitempty" json:"extnets,omitempty"`
}
func (bsrq GroupUpdateExtNetRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
return nil
} }
// GroupUpdateExtNet updates External Network settings for the group according to the new list // GroupUpdateExtNet updates External Network settings for the group according to the new list
func (b BService) GroupUpdateExtNet(ctx context.Context, req GroupUpdateExtNetRequest) (bool, error) { func (b BService) GroupUpdateExtNet(ctx context.Context, req GroupUpdateExtNetRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupUpdateExtnet" url := "/cloudapi/bservice/groupUpdateExtnet"

View File

@@ -2,42 +2,34 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for update VINS settings // Request struct for update VINS settings
type GroupUpdateVINSRequest struct { type GroupUpdateVINSRequest struct {
// ID of the Basic Service of Compute Group // ID of the Basic Service of Compute Group
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// ID of the Compute Group // ID of the Compute Group
// Required: true // Required: true
CompGroupID uint64 `url:"compgroupId"` CompGroupID uint64 `url:"compgroupId" json:"compgroupId" validate:"required"`
// List of ViNSes to connect computes // List of ViNSes to connect computes
// Required: false // Required: false
VINSes []uint64 `url:"vinses,omitempty"` VINSes []uint64 `url:"vinses,omitempty" json:"vinses,omitempty"`
}
func (bsrq GroupUpdateVINSRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.CompGroupID == 0 {
return errors.New("field CompGroupID can not be empty or equal to 0")
}
return nil
} }
// GroupUpdateVINS update ViNS settings for the group according to the new list // GroupUpdateVINS update ViNS settings for the group according to the new list
func (b BService) GroupUpdateVINS(ctx context.Context, req GroupUpdateVINSRequest) (bool, error) { func (b BService) GroupUpdateVINS(ctx context.Context, req GroupUpdateVINSRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/groupUpdateVins" url := "/cloudapi/bservice/groupUpdateVins"

View File

@@ -6,27 +6,51 @@ import (
"net/http" "net/http"
) )
// Request struct for get list/deleted list BasicService instances // Request struct for get list BasicService instances
type ListRequest struct { type ListRequest struct {
// Find by ID
// Required: false
ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"`
// Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// ID of the account to query for BasicService instances // ID of the account to query for BasicService instances
// Required: false // Required: false
AccountID uint64 `url:"accountId,omitempty"` AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"`
// Find by resource group name
// Required: false
RGName string `url:"rgName,omitempty" json:"rgName,omitempty"`
// ID of the resource group to query for BasicService instances // ID of the resource group to query for BasicService instances
// Required: false // Required: false
RGID uint64 `url:"rgId,omitempty"` RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"`
// Find by tech status
// Required: false
TechStatus string `url:"techStatus,omitempty" json:"techStatus,omitempty"`
// Find by status
// Required: false
Status string `url:"status,omitempty" json:"status,omitempty"`
// Find by account name
// Required: false
AccountName string `url:"accountName,omitempty" json:"accountName,omitempty"`
// Page number // Page number
// Required: false // Required: false
Page uint64 `url:"page,omitempty"` Page uint64 `url:"page,omitempty" json:"page,omitempty"`
// Page size // Page size
// Required: false // Required: false
Size uint64 `url:"size,omitempty"` Size uint64 `url:"size,omitempty" json:"size,omitempty"`
} }
// List gets list BasicService instances associated with the specified Resource Group // List gets list BasicService instances associated with the specified Resource Group
func (b BService) List(ctx context.Context, req ListRequest) (ListBasicServices, error) { func (b BService) List(ctx context.Context, req ListRequest) (*ListBasicServices, error) {
url := "/cloudapi/bservice/list" url := "/cloudapi/bservice/list"
res, err := b.client.DecortApiCall(ctx, http.MethodPost, url, req) res, err := b.client.DecortApiCall(ctx, http.MethodPost, url, req)
@@ -41,24 +65,5 @@ func (b BService) List(ctx context.Context, req ListRequest) (ListBasicServices,
return nil, err return nil, err
} }
return list, nil return &list, nil
}
// ListDeleted gets list deleted BasicService instances associated with the specified Resource Group
func (b BService) ListDeleted(ctx context.Context, req ListRequest) (ListBasicServices, error) {
url := "/cloudapi/bservice/listDeleted"
res, err := b.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
list := ListBasicServices{}
err = json.Unmarshal(res, &list)
if err != nil {
return nil, err
}
return list, nil
} }

View File

@@ -0,0 +1,45 @@
package bservice
import (
"context"
"encoding/json"
"net/http"
)
// Request struct for get list of deleted BasicService instances
type ListDeletedRequest struct {
// ID of the account to query for BasicService instances
// Required: false
AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"`
// ID of the resource group to query for BasicService instances
// Required: false
RGID uint64 `url:"rgId,omitempty" json:"rgId,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"`
}
// ListDeleted gets list deleted BasicService instances associated with the specified Resource Group
func (b BService) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListBasicServices, error) {
url := "/cloudapi/bservice/listDeleted"
res, err := b.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
list := ListBasicServices{}
err = json.Unmarshal(res, &list)
if err != nil {
return nil, err
}
return &list, nil
}

View File

@@ -35,11 +35,8 @@ type RecordBasicService struct {
// Grid ID // Grid ID
GID uint64 `json:"gid"` GID uint64 `json:"gid"`
// List of Service Compute Group IDs // List of Service Compute Groups
Groups []uint64 `json:"groups"` Groups ListGroups `json:"groups"`
// List of compute groups by name
GroupsName []string `json:"groupsName"`
// GUID // GUID
GUID uint64 `json:"guid"` GUID uint64 `json:"guid"`
@@ -95,6 +92,12 @@ type RecordBasicService struct {
// Main information about Compute // Main information about Compute
type ItemCompute struct { type ItemCompute struct {
// Account ID
AccountID uint64
// Architecture
Architecture string `json:"arch"`
// Compute group ID // Compute group ID
CompGroupID uint64 `json:"compgroupId"` CompGroupID uint64 `json:"compgroupId"`
@@ -109,11 +112,47 @@ type ItemCompute struct {
// Name // Name
Name string `json:"name"` Name string `json:"name"`
// Resource group ID
RGID uint64 `json:"rgId"`
// StackID
StackID uint64 `json:"stackId"`
// Status
Status string `json:"status"`
// Tech status
TechStatus string `json:"techStatus"`
} }
// List of Computes // List of Computes
type ListComputes []ItemCompute type ListComputes []ItemCompute
// Main information about Group
type ItemGroup struct {
// Amount of computes
Computes uint64 `json:"computes"`
// Consistency
Consistency bool `json:"consistency"`
// Group ID
ID uint64 `json:"id"`
// Group name
Name string `json:"name"`
// Status
Status string `json:"status"`
// TechStatus
TechStatus string `json:"techStatus"`
}
// List of Groups
type ListGroups []ItemGroup
// Main information about Snapshot // Main information about Snapshot
type ItemSnapshot struct { type ItemSnapshot struct {
// GUID // GUID
@@ -334,4 +373,8 @@ type ItemBasicService struct {
} }
// List of BasicServices // List of BasicServices
type ListBasicServices []ItemBasicService type ListBasicServices struct {
Data []ItemBasicService `json:"data"`
EntryCount uint64 `json:"entryCount"`
}

View File

@@ -2,31 +2,26 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for restores BasicService instance // Request struct for restores BasicService instance
type RestoreRequest struct { type RestoreRequest struct {
// ID of the BasicService to be restored // ID of the BasicService to be restored
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
}
func (bsrq RestoreRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
return nil
} }
// Restore restores BasicService instance // Restore restores BasicService instance
func (b BService) Restore(ctx context.Context, req RestoreRequest) (bool, error) { func (b BService) Restore(ctx context.Context, req RestoreRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/restore" url := "/cloudapi/bservice/restore"

View File

@@ -0,0 +1,43 @@
package bservice
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 (lbs ListBasicServices) Serialize(params ...string) (serialization.Serialized, error) {
if lbs.EntryCount == 0 {
return []byte{}, nil
}
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(lbs, prefix, indent)
}
return json.Marshal(lbs)
}
// 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 (ibs ItemBasicService) Serialize(params ...string) (serialization.Serialized, error) {
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(ibs, prefix, indent)
}
return json.Marshal(ibs)
}

View File

@@ -2,38 +2,30 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for create snapshot // Request struct for create snapshot
type SnapshotCreateRequest struct { type SnapshotCreateRequest struct {
// ID of the Basic Service // ID of the Basic Service
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// Label of the snapshot // Label of the snapshot
// Required: true // Required: true
Label string `url:"label"` Label string `url:"label" json:"label" validate:"required"`
}
func (bsrq SnapshotCreateRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.Label == "" {
return errors.New("field Label can not be empty")
}
return nil
} }
// SnapshotCreate create snapshot of the Basic Service // SnapshotCreate create snapshot of the Basic Service
func (b BService) SnapshotCreate(ctx context.Context, req SnapshotCreateRequest) (bool, error) { func (b BService) SnapshotCreate(ctx context.Context, req SnapshotCreateRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/snapshotCreate" url := "/cloudapi/bservice/snapshotCreate"

View File

@@ -2,38 +2,30 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for delete snapshot // Request struct for delete snapshot
type SnapshotDeleteRequest struct { type SnapshotDeleteRequest struct {
// ID of the Basic Service // ID of the Basic Service
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// Label of the snapshot // Label of the snapshot
// Required: true // Required: true
Label string `url:"label"` Label string `url:"label" json:"label" validate:"required"`
}
func (bsrq SnapshotDeleteRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.Label == "" {
return errors.New("field Label can not be empty")
}
return nil
} }
// SnapshotDelete delete snapshot of the Basic Service // SnapshotDelete delete snapshot of the Basic Service
func (b BService) SnapshotDelete(ctx context.Context, req SnapshotDeleteRequest) (bool, error) { func (b BService) SnapshotDelete(ctx context.Context, req SnapshotDeleteRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/snapshotDelete" url := "/cloudapi/bservice/snapshotDelete"

View File

@@ -3,30 +3,25 @@ package bservice
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for get list existing snapshots // Request struct for get list existing snapshots
type SnapshotListRequest struct { type SnapshotListRequest struct {
// ID of the Basic Service // ID of the Basic Service
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
}
func (bsrq SnapshotListRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
return nil
} }
// SnapshotList gets list existing snapshots of the Basic Service // SnapshotList gets list existing snapshots of the Basic Service
func (b BService) SnapshotList(ctx context.Context, req SnapshotListRequest) (ListSnapshots, error) { func (b BService) SnapshotList(ctx context.Context, req SnapshotListRequest) (ListSnapshots, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/snapshotList" url := "/cloudapi/bservice/snapshotList"

View File

@@ -2,38 +2,30 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for rollback snapshot // Request struct for rollback snapshot
type SnapshotRollbackRequest struct { type SnapshotRollbackRequest struct {
// ID of the Basic Service // ID of the Basic Service
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
// Label of the snapshot // Label of the snapshot
// Required: true // Required: true
Label string `url:"label"` Label string `url:"label" json:"label" validate:"required"`
}
func (bsrq SnapshotRollbackRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
if bsrq.Label == "" {
return errors.New("field Label can not be empty")
}
return nil
} }
// SnapshotRollback rollback snapshot of the Basic Service // SnapshotRollback rollback snapshot of the Basic Service
func (b BService) SnapshotRollback(ctx context.Context, req SnapshotRollbackRequest) (bool, error) { func (b BService) SnapshotRollback(ctx context.Context, req SnapshotRollbackRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/snapshotRollback" url := "/cloudapi/bservice/snapshotRollback"

View File

@@ -0,0 +1,60 @@
package bservice
import "sort"
// SortByCreatedTime sorts ListBasicServices by the CreatedTime field in ascending order.
//
// If inverse param is set to true, the order is reversed.
func (lbs ListBasicServices) SortByCreatedTime(inverse bool) ListBasicServices {
if lbs.EntryCount < 2 {
return lbs
}
sort.Slice(lbs.Data, func(i, j int) bool {
if inverse {
return lbs.Data[i].CreatedTime > lbs.Data[j].CreatedTime
}
return lbs.Data[i].CreatedTime < lbs.Data[j].CreatedTime
})
return lbs
}
// SortByUpdatedTime sorts ListBasicServices by the UpdatedTime field in ascending order.
//
// If inverse param is set to true, the order is reversed.
func (lbs ListBasicServices) SortByUpdatedTime(inverse bool) ListBasicServices {
if lbs.EntryCount < 2 {
return lbs
}
sort.Slice(lbs.Data, func(i, j int) bool {
if inverse {
return lbs.Data[i].UpdatedTime > lbs.Data[j].UpdatedTime
}
return lbs.Data[i].UpdatedTime < lbs.Data[j].UpdatedTime
})
return lbs
}
// SortByDeletedTime sorts ListBasicServices by the DeletedTime field in ascending order.
//
// If inverse param is set to true, the order is reversed.
func (lbs ListBasicServices) SortByDeletedTime(inverse bool) ListBasicServices {
if lbs.EntryCount < 2 {
return lbs
}
sort.Slice(lbs.Data, func(i, j int) bool {
if inverse {
return lbs.Data[i].DeletedTime > lbs.Data[j].DeletedTime
}
return lbs.Data[i].DeletedTime < lbs.Data[j].DeletedTime
})
return lbs
}

View File

@@ -2,33 +2,28 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for start service // Request struct for start service
type StartRequest struct { type StartRequest struct {
// ID of the service to start // ID of the service to start
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
}
func (bsrq StartRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
return nil
} }
// Start starts service. // Start starts service.
// Starting a service technically means starting computes from all // Starting a service technically means starting computes from all
// service groups according to group relations // service groups according to group relations
func (b BService) Start(ctx context.Context, req StartRequest) (bool, error) { func (b BService) Start(ctx context.Context, req StartRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/start" url := "/cloudapi/bservice/start"

View File

@@ -2,33 +2,28 @@ package bservice
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for stop service // Request struct for stop service
type StopRequest struct { type StopRequest struct {
// ID of the service to stop // ID of the service to stop
// Required: true // Required: true
ServiceID uint64 `url:"serviceId"` ServiceID uint64 `url:"serviceId" json:"serviceId" validate:"required"`
}
func (bsrq StopRequest) validate() error {
if bsrq.ServiceID == 0 {
return errors.New("field ServiceID can not be empty or equal to 0")
}
return nil
} }
// Stop stops service. // Stop stops service.
// Stopping a service technically means stopping computes from // Stopping a service technically means stopping computes from
// all service groups // all service groups
func (b BService) Stop(ctx context.Context, req StopRequest) (bool, error) { func (b BService) Stop(ctx context.Context, req StopRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/bservice/stop" url := "/cloudapi/bservice/stop"

View File

@@ -2,7 +2,7 @@
package cloudapi package cloudapi
import ( import (
"github.com/rudecs/decort-sdk/interfaces" "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
) )
// Structure for creating request to CloudAPI groups // Structure for creating request to CloudAPI groups

View File

@@ -1,7 +1,7 @@
package cloudapi package cloudapi
import ( import (
"github.com/rudecs/decort-sdk/pkg/cloudapi/compute" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute"
) )
// Accessing the Compute method group // Accessing the Compute method group

View File

@@ -2,37 +2,29 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for check all computes with current affinity label can start // Request struct for check all computes with current affinity label can start
type AffinityGroupCheckStartRequest struct { type AffinityGroupCheckStartRequest struct {
// ID of the resource group // ID of the resource group
// Required: true // Required: true
RGID uint64 `url:"rgId"` RGID uint64 `url:"rgId" json:"rgId" validate:"required"`
// Affinity group label // Affinity group label
// Required: true // Required: true
AffinityLabel string `url:"affinityLabel"` AffinityLabel string `url:"affinityLabel" json:"affinityLabel" validate:"required"`
}
func (crq AffinityGroupCheckStartRequest) validate() error {
if crq.RGID == 0 {
return errors.New("validation-error: field RGID can not be empty or equal to 0")
}
if crq.AffinityLabel == "" {
return errors.New("validation-error: field AffinityLabel can not be empty")
}
return nil
} }
// AffinityGroupCheckStart check all computes with current affinity label can start // AffinityGroupCheckStart check all computes with current affinity label can start
func (c Compute) AffinityGroupCheckStart(ctx context.Context, req AffinityGroupCheckStartRequest) (string, error) { func (c Compute) AffinityGroupCheckStart(ctx context.Context, req AffinityGroupCheckStartRequest) (string, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return "", err for _, validationError := range validators.GetErrors(err) {
return "", validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/affinityGroupCheckStart" url := "/cloudapi/compute/affinityGroupCheckStart"

View File

@@ -2,31 +2,26 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for clear affinity label for compute // Request struct for clear affinity label for compute
type AffinityLabelRemoveRequest struct { type AffinityLabelRemoveRequest struct {
// ID of the compute instance // ID of the compute instance
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
func (crq AffinityLabelRemoveRequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
return nil
} }
// AffinityLabelRemove clear affinity label for compute // AffinityLabelRemove clear affinity label for compute
func (c Compute) AffinityLabelRemove(ctx context.Context, req AffinityLabelRemoveRequest) (bool, error) { func (c Compute) AffinityLabelRemove(ctx context.Context, req AffinityLabelRemoveRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/affinityLabelRemove" url := "/cloudapi/compute/affinityLabelRemove"

View File

@@ -2,38 +2,30 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for set affinity label for compute // Request struct for set affinity label for compute
type AffinityLabelSetRequest struct { type AffinityLabelSetRequest struct {
// ID of the compute instance // ID of the compute instance
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
// Affinity group label // Affinity group label
// Required: true // Required: true
AffinityLabel string `url:"affinityLabel"` AffinityLabel string `url:"affinityLabel" json:"affinityLabel" validate:"required"`
}
func (crq AffinityLabelSetRequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
if crq.AffinityLabel == "" {
return errors.New("validation-error: field AffinityLabel can not be empty")
}
return nil
} }
// AffinityLabelSet set affinity label for compute // AffinityLabelSet set affinity label for compute
func (c Compute) AffinityLabelSet(ctx context.Context, req AffinityLabelSetRequest) (bool, error) { func (c Compute) AffinityLabelSet(ctx context.Context, req AffinityLabelSetRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/affinityLabelSet" url := "/cloudapi/compute/affinityLabelSet"

View File

@@ -3,30 +3,25 @@ package compute
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for get dict of computes // Request struct for get dict of computes
type AffinityRelationsRequest struct { type AffinityRelationsRequest struct {
// ID of the compute instance // ID of the compute instance
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
func (crq AffinityRelationsRequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
return nil
} }
// AffinityRelations gets dict of computes divided by affinity and anti affinity rules // AffinityRelations gets dict of computes divided by affinity and anti affinity rules
func (c Compute) AffinityRelations(ctx context.Context, req AffinityRelationsRequest) (*RecordAffinityRelations, error) { func (c Compute) AffinityRelations(ctx context.Context, req AffinityRelationsRequest) (*RecordAffinityRelations, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return nil, err for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/affinityRelations" url := "/cloudapi/compute/affinityRelations"

View File

@@ -2,29 +2,28 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"github.com/rudecs/decort-sdk/internal/validators" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for add affinity rule // Request struct for add affinity rule
type AffinityRuleAddRequest struct { type AffinityRuleAddRequest struct {
// ID of the compute instance // ID of the compute instance
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
// Compute or node, for whom rule applies // Compute or node, for whom rule applies
// Required: true // Required: true
Topology string `url:"topology"` Topology string `url:"topology" json:"topology" validate:"computeTopology"`
// The degree of 'strictness' of this rule // The degree of 'strictness' of this rule
// Should be one of: // Should be one of:
// - RECOMMENDED // - RECOMMENDED
// - REQUIRED // - REQUIRED
// Required: true // Required: true
Policy string `url:"policy"` Policy string `url:"policy" json:"policy" validate:"computePolicy"`
// The comparison mode is 'value', recorded by the specified 'key' // The comparison mode is 'value', recorded by the specified 'key'
// Should be one of: // Should be one of:
@@ -32,57 +31,24 @@ type AffinityRuleAddRequest struct {
// - EN // - EN
// - ANY // - ANY
// Required: true // Required: true
Mode string `url:"mode"` Mode string `url:"mode" json:"mode" validate:"computeMode"`
// Key that are taken into account when analyzing this rule will be identified // Key that are taken into account when analyzing this rule will be identified
// Required: true // Required: true
Key string `url:"key"` Key string `url:"key" json:"key" validate:"required"`
// Value that must match the key to be taken into account when analyzing this rule // Value that must match the key to be taken into account when analyzing this rule
// Required: true // Required: true
Value string `url:"value"` Value string `url:"value" json:"value" validate:"required"`
}
func (crq AffinityRuleAddRequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
if crq.Topology == "" {
return errors.New("validation-error: field Topology can not be empty")
}
validator := validators.StringInSlice(crq.Topology, []string{"compute", "node"})
if !validator {
return errors.New("validation-error: field Topology can be only compute or node")
}
if crq.Policy == "" {
return errors.New("validation-error: field Policy can not be empty")
}
validator = validators.StringInSlice(crq.Policy, []string{"RECOMMENDED", "REQUIRED"})
if !validator {
return errors.New("validation-error: field Policy can be only RECOMMENDED or REQUIRED")
}
if crq.Mode == "" {
return errors.New("validation-error: field Mode can not be empty")
}
validator = validators.StringInSlice(crq.Mode, []string{"EQ", "NE", "ANY"})
if !validator {
return errors.New("validation-error: field Mode can be only EQ, NE or ANY")
}
if crq.Key == "" {
return errors.New("validation-error: field Key can not be empty")
}
if crq.Value == "" {
return errors.New("validation-error: field Value can not be empty")
}
return nil
} }
// AffinityRuleAdd add affinity rule // AffinityRuleAdd add affinity rule
func (c Compute) AffinityRuleAdd(ctx context.Context, req AffinityRuleAddRequest) (bool, error) { func (c Compute) AffinityRuleAdd(ctx context.Context, req AffinityRuleAddRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/affinityRuleAdd" url := "/cloudapi/compute/affinityRuleAdd"

View File

@@ -2,29 +2,28 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"github.com/rudecs/decort-sdk/internal/validators" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for remove affinity rule // Request struct for remove affinity rule
type AffinityRuleRemoveRequest struct { type AffinityRuleRemoveRequest struct {
// ID of the compute instance // ID of the compute instance
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
// Compute or node, for whom rule applies // Compute or node, for whom rule applies
// Required: true // Required: true
Topology string `url:"topology"` Topology string `url:"topology" json:"topology" validate:"computeTopology"`
// The degree of 'strictness' of this rule // The degree of 'strictness' of this rule
// Should be one of: // Should be one of:
// - RECOMMENDED // - RECOMMENDED
// - REQUIRED // - REQUIRED
// Required: true // Required: true
Policy string `url:"policy"` Policy string `url:"policy" json:"policy" validate:"computePolicy"`
// The comparison mode is 'value', recorded by the specified 'key' // The comparison mode is 'value', recorded by the specified 'key'
// Should be one of: // Should be one of:
@@ -32,57 +31,24 @@ type AffinityRuleRemoveRequest struct {
// - EN // - EN
// - ANY // - ANY
// Required: true // Required: true
Mode string `url:"mode"` Mode string `url:"mode" json:"mode" validate:"computeMode"`
// Key that are taken into account when analyzing this rule will be identified // Key that are taken into account when analyzing this rule will be identified
// Required: true // Required: true
Key string `url:"key"` Key string `url:"key" json:"key" validate:"required"`
// Value that must match the key to be taken into account when analyzing this rule // Value that must match the key to be taken into account when analyzing this rule
// Required: true // Required: true
Value string `url:"value"` Value string `url:"value" json:"value" validate:"required"`
}
func (crq AffinityRuleRemoveRequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
if crq.Topology == "" {
return errors.New("validation-error: field Topology can not be empty")
}
validator := validators.StringInSlice(crq.Topology, []string{"compute", "node"})
if !validator {
return errors.New("validation-error: field Topology can be only compute or node")
}
if crq.Policy == "" {
return errors.New("validation-error: field Policy can not be empty")
}
validator = validators.StringInSlice(crq.Policy, []string{"RECOMMENDED", "REQUIRED"})
if !validator {
return errors.New("validation-error: field Policy can be only RECOMMENDED or REQUIRED")
}
if crq.Mode == "" {
return errors.New("validation-error: field Mode can not be empty")
}
validator = validators.StringInSlice(crq.Mode, []string{"EQ", "NE", "ANY"})
if !validator {
return errors.New("validation-error: field Mode can be only EQ, NE or ANY")
}
if crq.Key == "" {
return errors.New("validation-error: field Key can not be empty")
}
if crq.Value == "" {
return errors.New("validation-error: field Value can not be empty")
}
return nil
} }
// AffinityRuleRemove remove affinity rule // AffinityRuleRemove remove affinity rule
func (c Compute) AffinityRuleRemove(ctx context.Context, req AffinityRuleRemoveRequest) (bool, error) { func (c Compute) AffinityRuleRemove(ctx context.Context, req AffinityRuleRemoveRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/affinityRuleRemove" url := "/cloudapi/compute/affinityRuleRemove"

View File

@@ -2,31 +2,26 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for clear affinity rules // Request struct for clear affinity rules
type AffinityRulesClearRequest struct { type AffinityRulesClearRequest struct {
// ID of the compute instance // ID of the compute instance
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
func (crq AffinityRulesClearRequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
return nil
} }
// AffinityRulesClear clear affinity rules // AffinityRulesClear clear affinity rules
func (c Compute) AffinityRulesClear(ctx context.Context, req AffinityRulesClearRequest) (bool, error) { func (c Compute) AffinityRulesClear(ctx context.Context, req AffinityRulesClearRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/affinityRulesClear" url := "/cloudapi/compute/affinityRulesClear"

View File

@@ -2,29 +2,28 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"github.com/rudecs/decort-sdk/internal/validators" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for add anti affinity rule // Request struct for add anti affinity rule
type AntiAffinityRuleAddRequest struct { type AntiAffinityRuleAddRequest struct {
// ID of the compute instance // ID of the compute instance
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
// Compute or node, for whom rule applies // Compute or node, for whom rule applies
// Required: true // Required: true
Topology string `url:"topology"` Topology string `url:"topology" json:"topology" validate:"computeTopology"`
// The degree of 'strictness' of this rule // The degree of 'strictness' of this rule
// Should be one of: // Should be one of:
// - RECOMMENDED // - RECOMMENDED
// - REQUIRED // - REQUIRED
// Required: true // Required: true
Policy string `url:"policy"` Policy string `url:"policy" json:"policy" validate:"computePolicy"`
// The comparison mode is 'value', recorded by the specified 'key' // The comparison mode is 'value', recorded by the specified 'key'
// Should be one of: // Should be one of:
@@ -32,57 +31,24 @@ type AntiAffinityRuleAddRequest struct {
// - EN // - EN
// - ANY // - ANY
// Required: true // Required: true
Mode string `url:"mode"` Mode string `url:"mode" json:"mode" validate:"computeMode"`
// Key that are taken into account when analyzing this rule will be identified // Key that are taken into account when analyzing this rule will be identified
// Required: true // Required: true
Key string `url:"key"` Key string `url:"key" json:"key" validate:"required"`
// Value that must match the key to be taken into account when analyzing this rule // Value that must match the key to be taken into account when analyzing this rule
// Required: true // Required: true
Value string `url:"value"` Value string `url:"value" json:"value" validate:"required"`
}
func (crq AntiAffinityRuleAddRequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
if crq.Topology == "" {
return errors.New("validation-error: field Topology can not be empty")
}
validator := validators.StringInSlice(crq.Topology, []string{"compute", "node"})
if !validator {
return errors.New("validation-error: field Topology can be only compute or node")
}
if crq.Policy == "" {
return errors.New("validation-error: field Policy can not be empty")
}
validator = validators.StringInSlice(crq.Policy, []string{"RECOMMENDED", "REQUIRED"})
if !validator {
return errors.New("validation-error: field Policy can be only RECOMMENDED or REQUIRED")
}
if crq.Mode == "" {
return errors.New("validation-error: field Mode can not be empty")
}
validator = validators.StringInSlice(crq.Mode, []string{"EQ", "NE", "ANY"})
if !validator {
return errors.New("validation-error: field Mode can be only EQ, NE or ANY")
}
if crq.Key == "" {
return errors.New("validation-error: field Key can not be empty")
}
if crq.Value == "" {
return errors.New("validation-error: field Value can not be empty")
}
return nil
} }
// AntiAffinityRuleAdd add anti affinity rule // AntiAffinityRuleAdd add anti affinity rule
func (c Compute) AntiAffinityRuleAdd(ctx context.Context, req AntiAffinityRuleAddRequest) (bool, error) { func (c Compute) AntiAffinityRuleAdd(ctx context.Context, req AntiAffinityRuleAddRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/antiAffinityRuleAdd" url := "/cloudapi/compute/antiAffinityRuleAdd"

View File

@@ -2,29 +2,28 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"github.com/rudecs/decort-sdk/internal/validators" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for remove anti affinity rule // Request struct for remove anti affinity rule
type AntiAffinityRuleRemoveRequest struct { type AntiAffinityRuleRemoveRequest struct {
// ID of the compute instance // ID of the compute instance
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
// Compute or node, for whom rule applies // Compute or node, for whom rule applies
// Required: true // Required: true
Topology string `url:"topology"` Topology string `url:"topology" json:"topology" validate:"computeTopology"`
// The degree of 'strictness' of this rule // The degree of 'strictness' of this rule
// Should be one of: // Should be one of:
// - RECOMMENDED // - RECOMMENDED
// - REQUIRED // - REQUIRED
// Required: true // Required: true
Policy string `url:"policy"` Policy string `url:"policy" json:"policy" validate:"computePolicy"`
// The comparison mode is 'value', recorded by the specified 'key' // The comparison mode is 'value', recorded by the specified 'key'
// Should be one of: // Should be one of:
@@ -32,57 +31,24 @@ type AntiAffinityRuleRemoveRequest struct {
// - EN // - EN
// - ANY // - ANY
// Required: true // Required: true
Mode string `url:"mode"` Mode string `url:"mode" json:"mode" validate:"computeMode"`
// Key that are taken into account when analyzing this rule will be identified // Key that are taken into account when analyzing this rule will be identified
// Required: true // Required: true
Key string `url:"key"` Key string `url:"key" json:"key" validate:"required"`
// Value that must match the key to be taken into account when analyzing this rule // Value that must match the key to be taken into account when analyzing this rule
// Required: true // Required: true
Value string `url:"value"` Value string `url:"value" json:"value" validate:"required"`
}
func (crq AntiAffinityRuleRemoveRequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
if crq.Topology == "" {
return errors.New("validation-error: field Topology can not be empty")
}
validator := validators.StringInSlice(crq.Topology, []string{"compute", "node"})
if !validator {
return errors.New("validation-error: field Topology can be only compute or node")
}
if crq.Policy == "" {
return errors.New("validation-error: field Policy can not be empty")
}
validator = validators.StringInSlice(crq.Policy, []string{"RECOMMENDED", "REQUIRED"})
if !validator {
return errors.New("validation-error: field Policy can be only RECOMMENDED or REQUIRED")
}
if crq.Mode == "" {
return errors.New("validation-error: field Mode can not be empty")
}
validator = validators.StringInSlice(crq.Mode, []string{"EQ", "NE", "ANY"})
if !validator {
return errors.New("validation-error: field Mode can be only EQ, NE or ANY")
}
if crq.Key == "" {
return errors.New("validation-error: field Key can not be empty")
}
if crq.Value == "" {
return errors.New("validation-error: field Value can not be empty")
}
return nil
} }
// AntiAffinityRuleRemove remove anti affinity rule // AntiAffinityRuleRemove remove anti affinity rule
func (c Compute) AntiAffinityRuleRemove(ctx context.Context, req AntiAffinityRuleRemoveRequest) (bool, error) { func (c Compute) AntiAffinityRuleRemove(ctx context.Context, req AntiAffinityRuleRemoveRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/antiAffinityRuleRemove" url := "/cloudapi/compute/antiAffinityRuleRemove"

View File

@@ -2,31 +2,26 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for clear anti affinity rules // Request struct for clear anti affinity rules
type AntiAffinityRulesClearRequest struct { type AntiAffinityRulesClearRequest struct {
// ID of the compute instance // ID of the compute instance
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
func (crq AntiAffinityRulesClearRequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
return nil
} }
// AntiAffinityRulesClear clear anti affinity rules // AntiAffinityRulesClear clear anti affinity rules
func (c Compute) AntiAffinityRulesClear(ctx context.Context, req AntiAffinityRulesClearRequest) (bool, error) { func (c Compute) AntiAffinityRulesClear(ctx context.Context, req AntiAffinityRulesClearRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/antiAffinityRulesClear" url := "/cloudapi/compute/antiAffinityRulesClear"

View File

@@ -2,38 +2,30 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for attach GPU for compute // Request struct for attach GPU for compute
type AttachGPURequest struct { type AttachGPURequest struct {
// Identifier compute // Identifier compute
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
// Identifier vGPU // Identifier vGPU
// Required: true // Required: true
VGPUID uint64 `url:"vgpuId"` VGPUID uint64 `url:"vgpuId" json:"vgpuId" validate:"required"`
}
func (crq AttachGPURequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
if crq.VGPUID == 0 {
return errors.New("validation-error: field VGPUID can not be empty or equal to 0")
}
return nil
} }
// AttachGPU attach GPU for compute, returns vgpu id on success // AttachGPU attach GPU for compute, returns vgpu id on success
func (c Compute) AttachGPU(ctx context.Context, req AttachGPURequest) (uint64, error) { func (c Compute) AttachGPU(ctx context.Context, req AttachGPURequest) (uint64, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return 0, err for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/attachGpu" url := "/cloudapi/compute/attachGpu"

View File

@@ -2,38 +2,30 @@ package compute
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"strconv" "strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
) )
// Request struct for atttach PCI device // Request struct for atttach PCI device
type AttachPCIDeviceRequest struct { type AttachPCIDeviceRequest struct {
// Identifier compute // Identifier compute
// Required: true // Required: true
ComputeID uint64 `url:"computeId"` ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
// PCI device ID // PCI device ID
// Required: true // Required: true
DeviceID uint64 `url:"deviceId"` DeviceID uint64 `url:"deviceId" json:"deviceId" validate:"required"`
}
func (crq AttachPCIDeviceRequest) validate() error {
if crq.ComputeID == 0 {
return errors.New("validation-error: field ComputeID can not be empty or equal to 0")
}
if crq.DeviceID == 0 {
return errors.New("validation-error: field DeviceID can not be empty or equal to 0")
}
return nil
} }
// AttachPCIDevice attach PCI device // AttachPCIDevice attach PCI device
func (c Compute) AttachPCIDevice(ctx context.Context, req AttachPCIDeviceRequest) (bool, error) { func (c Compute) AttachPCIDevice(ctx context.Context, req AttachPCIDeviceRequest) (bool, error) {
err := req.validate() err := validators.ValidateRequest(req)
if err != nil { if err != nil {
return false, err for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
} }
url := "/cloudapi/compute/attachPciDevice" url := "/cloudapi/compute/attachPciDevice"

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