Compare commits

..

4 Commits

Author SHA1 Message Date
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
487 changed files with 6248 additions and 6679 deletions

3
.gitignore vendored
View File

@@ -1 +1,2 @@
cmd/
cmd/
.idea/

View File

@@ -1,12 +1,6 @@
## Version 1.2.1
### Bug fixes
#### Legacy Client
- Fixed password and username encoding
- Fixed request params absence in HTTP Transport
#### All
- Updated module to new repository
## Version 1.4.1
### Bug Fixes
- Fixed cloudapi/k8s/workerAdd returning value type
- Fixed cloudapi/cloudbroker/account/create/update SendAccessEmails field tags

185
README.md
View File

@@ -7,6 +7,8 @@ Decort SDK - это библиотека, написанная на языке G
- Версия 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 версии платформы
## Оглавление
@@ -16,6 +18,10 @@ Decort SDK - это библиотека, написанная на языке G
- [Cloudbroker](#cloudbroker)
- [Работа с библиотекой](#работа-с-библиотекой)
- [Настройка конфигурации клиента](#настройка-конфигурации-клиента)
- [Пример конфигурации клиента](#пример-конфигурации-клиента)
- [Парсинг конфигурации из файла](#парсинг-конфигурации-из-файла)
- [Пример JSON конфигурации](#пример-json-конфигурации)
- [Пример YAML конфигурации](#пример-yaml-конфигурации)
- [Создание клиента](#создание-клиента)
- [Создание структуры запроса](#cоздание-структуры-запроса)
- [Выполнение запроса](#выполнение-запроса)
@@ -24,6 +30,10 @@ Decort SDK - это библиотека, написанная на языке G
- [Сериализация](#сериализация)
- [Работа с legacy клиентом](#работа-с-legacy-клиентом)
- [Настройка конфигурации legacy клиента](#настройка-конфигурации-legacy-клиента)
- [Пример конфигурации legacy клиента](#пример-конфигурации-legacy-клиента)
- [Парсинг legacy конфигурации из файла](#парсинг-legacy-конфигурации-из-файла)
- [Пример legacy JSON конфигурации](#пример-legacy-json-конфигурации)
- [Пример legacy YAML конфигурации](#пример-legacy-yaml-конфигурации)
- [Создание legacy клиента](#создание-legacy-клиента)
- [Создание структуры запроса](#cоздание-структуры-запроса)
- [Выполнение запроса](#выполнение-запроса)
@@ -93,9 +103,10 @@ go get -u repository.basistech.ru/BASIS/decort-golang-sdk
Алгоритм работы с библиотекой выглядит следующим образом:
1. Настройка конфигурации клиента.
2. Создание клиента.
3. Создание структуры запроса.
4. Выполнение запроса.
2. Парсинг конфигурации из файла.
3. Создание клиента.
4. Создание структуры запроса.
5. Выполнение запроса.
### Настройка конфигурации клиента
@@ -110,11 +121,11 @@ go get -u repository.basistech.ru/BASIS/decort-golang-sdk
| SSLSkipVerify | bool | Нет | Пропуск проверки подлинности сертификата, по умолчанию - true |
| Token | string | Нет | JWT токен |
Пример кода:
#### Пример конфигурации клиента
```go
import (
"github.com/rudecs/decort-sdk/config"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
)
func main(){
// Настройка конфигурации
@@ -128,6 +139,47 @@ func main(){
}
```
#### Парсинг конфигурации из файла
Также возможно создать переменную конфигурации из 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,
"sslSkipVerify": false
}
```
#### Пример YAML конфигурации
```yaml
appId: <APP_ID>
appSecret: <APP_SECRET>
ssoUrl: https://sso.digitalenergy.online
decortUrl: https://mr4.digitalenergy.online
retries: 5
sslSkipVerify: false
```
### Создание клиента
Создание клиента происходит с помощью функции-строителя `New` из основного пакета `decort-sdk`, для избежания проблем с именами, пакету можно присвоить алиас `decort`. Функция принимает конфигурацию, возвращает структуру `DecortClient`, с помощью которой можно взаимодействовать с платформой.
@@ -138,8 +190,8 @@ func main(){
package main
import (
"github.com/rudecs/decort-sdk/config"
decort "github.com/rudecs/decort-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
)
func main() {
@@ -302,9 +354,9 @@ type CreateRequest struct {
package main
import (
"github.com/rudecs/decort-sdk/config"
decort "github.com/rudecs/decort-sdk"
"github.com/rudecs/decort-sdk/pkg/cloudapi/kvmx86"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmx86"
)
func main() {
@@ -402,9 +454,9 @@ import (
"log"
"fmt"
"github.com/rudecs/decort-sdk/config"
decort "github.com/rudecs/decort-sdk"
"github.com/rudecs/decort-sdk/pkg/cloudapi/kvmx86"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmx86"
)
func main() {
@@ -484,6 +536,52 @@ filtered := resp.
// ....
```
Также у `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)
// ....
}
```
### Сортировка
Функции сортировки так же могут быть объединены в конвейер:
@@ -536,9 +634,9 @@ import (
"context"
"log"
decort "github.com/rudecs/decort-sdk"
"github.com/rudecs/decort-sdk/config"
"github.com/rudecs/decort-sdk/pkg/cloudbroker/compute"
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() {
@@ -598,23 +696,61 @@ func main() {
| SSLSkipVerify | bool | Нет | Пропуск проверки подлинности сертификата, по умолчанию - true |
| Token | string | Нет | JWT токен |
Пример кода:
#### Пример конфигурации legacy клиента
```go
import (
"github.com/rudecs/decort-sdk/config"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
)
func main(){
// Настройка конфигурации
legacyCfg := config.LegacyConfig{
Username: "<USERNAME>",
Password: "<PASSWORD>",
Username: "<USERNAME>",
Password: "<PASSWORD>",
DecortURL: "https://mr4.digitalenergy.online",
Retries: 5,
}
}
```
#### Парсинг 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,
"sslSkipVerify": true
}
```
#### Пример legacy YAML конфигурации
```yaml
username: <USERNAME>
password: <PASSWORD>
decortUrl: https://mr4.digitalenergy.online
retries: 5
sslSkipVerify: true
```
### Создание legacy клиента
Создание клиента происходит с помощью функции-строителя `NewLegacy` из основного пакета `decort-sdk`, для избежания проблем с именами, пакету можно присвоить алиас `decort`. Функция принимает конфигурацию, возвращает структуру `DecortClient`, с помощью которой можно взаимодействовать с платформой.
@@ -625,8 +761,8 @@ func main(){
package main
import (
"github.com/rudecs/decort-sdk/config"
decort "github.com/rudecs/decort-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
)
func main() {
@@ -651,8 +787,8 @@ package main
import (
"fmt"
"github.com/rudecs/decort-sdk/config"
decort "github.com/rudecs/decort-sdk"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
decort "repository.basistech.ru/BASIS/decort-golang-sdk"
)
func main() {
@@ -685,4 +821,3 @@ func main() {
fmt.Println(res)
}
```

View File

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

View File

@@ -1,39 +1,95 @@
package config
import (
"encoding/json"
"os"
"gopkg.in/yaml.v3"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Configuration for creating request to platform
type Config struct {
// JWT platform token
// Required: false
// Example: "qwqwdfwv68979we0q9bfv7e9sbvd89798qrwv97ff"
Token string
Token string `json:"token" yaml:"token"`
// Application (client) identifier for authorization
// in the cloud platform controller in oauth2 mode.
// Required: true
// Example: "ewqfrvea7s890avw804389qwguf234h0otfi3w4eiu"
AppID string
AppID string `json:"appId" yaml:"appId" validate:"required"`
// Application (client) secret code for authorization
// in the cloud platform controller in oauth2 mode.
// Example: "frvet09rvesfis0c9erv9fsov0vsdfi09ovds0f"
AppSecret string
AppSecret string `json:"appSecret" yaml:"appSecret" validate:"required"`
// Platform authentication service address
// Required: true
// 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
// Required: true
// Example: "https://mr4.digitalenergy.online"
DecortURL string
DecortURL string `json:"decortUrl" yaml:"decortUrl" validate:"url"`
// Amount platform request attempts
// Default value: 5
// Required: false
Retries uint64
Retries uint64 `json:"retries" yaml:"retries"`
// Skip verify, true by default
// Required: false
SSLSkipVerify bool
SSLSkipVerify bool `json:"sslSkipVerify" yaml:"sslSkipVerify"`
}
// 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
}

View File

@@ -1,33 +1,89 @@
package config
import (
"encoding/json"
"os"
"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
Username string `json:"username" yaml:"username" validate:"required"`
// ServiceAccount password
// Required: true
// Example: "[1o>hYkjnJr)HI78q7t&#%8Lm"
Password string
Password string `json:"password" yaml:"password" validate:"required"`
// Platform token
// Required: false
// Example: "158e76424b0d4810b6086hgbhj928fc4a6bc06e"
Token string
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
DecortURL string `json:"decortUrl" yaml:"decortUrl" validate:"url"`
// Amount platform request attempts
// Default value: 5
// Required: false
Retries uint64
Retries uint64 `json:"retries" yaml:"retries"`
// Skip verify, true by default
// Required: false
SSLSkipVerify bool
SSLSkipVerify bool `json:"sslSkipVerify" yaml:"sslSkipVerify"`
}
// 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
}

2
go.mod
View File

@@ -5,11 +5,13 @@ go 1.20
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

7
go.sum
View File

@@ -1,3 +1,4 @@
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=
@@ -11,10 +12,14 @@ 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-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
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=
@@ -26,5 +31,7 @@ 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=
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

@@ -23,6 +23,8 @@ 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)
bodyReader := strings.NewReader(body)
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")

View File

@@ -1,6 +1,47 @@
package validators
import "github.com/go-playground/validator/v10"
import (
"github.com/go-playground/validator/v10"
"regexp"
"strings"
)
// 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 {
@@ -9,20 +50,6 @@ func accountCUTypeValidator(fe validator.FieldLevel) bool {
return StringInSlice(fieldValue, accountCUTypeValues)
}
// accountAccessTypeValidator is used to validate AccessType field.
func accountAccessTypeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, accountAccessTypeValues)
}
// bserviceDriverValidator is used to validate Driver field.
func bserviceDriverValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, bserviceDriverValues)
}
// bserviceModeValidator is used to validate Mode field.
func bserviceModeValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
@@ -65,11 +92,76 @@ func computeNetTypeValidator(fe validator.FieldLevel) bool {
return StringInSlice(fieldValue, computeNetTypeValues)
}
// computeProtoValidator is used to validate Proto field.
func computeProtoValidator(fe validator.FieldLevel) bool {
// 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, computeProtoValues)
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.
@@ -108,3 +200,59 @@ func imageArchitectureValidator(fe validator.FieldLevel) bool {
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)
}

View File

@@ -11,6 +11,11 @@ func ValidateRequest(req interface{}) error {
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))
}

View File

@@ -12,7 +12,7 @@ func errorMessage(fe validator.FieldError) string {
switch fe.Tag() {
// Default Validators
// Common Validators
case "required":
return fmt.Sprintf("%s %s is required", prefix, fe.Field())
case "gt":
@@ -26,13 +26,31 @@ func errorMessage(fe validator.FieldError) string {
case "email":
return fmt.Sprintf("%s %s: unexpected E-Mail format", prefix, fe.Field())
// Account Validators
case "accountAccessType":
return fmt.Sprintf("%s %s must be one of the followng: %s",
case "driver":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(accountAccessTypeValues))
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,
@@ -40,12 +58,6 @@ func errorMessage(fe validator.FieldError) string {
joinValues(accountCUTypeValues))
// BService Validators
case "bserviceDriver":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(bserviceDriverValues))
case "bserviceMode":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
@@ -83,14 +95,68 @@ func errorMessage(fe validator.FieldError) string {
fe.Field(),
joinValues(computeNetTypeValues))
case "computeProto":
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(computeProtoValues))
joinValues(computeDataDisksValues))
// 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))
// 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 "bootType":
case "imageBootType":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
@@ -114,6 +180,43 @@ func errorMessage(fe validator.FieldError) string {
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()

View File

@@ -34,7 +34,27 @@ func getDecortValidator() *validator.Validate {
// registerAllValidators registers all custom validators in DecortValidator.
func registerAllValidators(validate *validator.Validate) error {
err := validate.RegisterValidation("bootType", imageBootTypeValidator)
err := validate.RegisterValidation("proto", protoValidator)
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
}
@@ -54,21 +74,11 @@ func registerAllValidators(validate *validator.Validate) error {
return err
}
err = validate.RegisterValidation("accountAccessType", accountAccessTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("accountCUType", accountCUTypeValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("bserviceDriver", bserviceDriverValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("bserviceMode", bserviceModeValidator)
if err != nil {
return err
@@ -99,7 +109,77 @@ func registerAllValidators(validate *validator.Validate) error {
return err
}
err = validate.RegisterValidation("computeProto", computeProtoValidator)
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
}

View File

@@ -1,21 +1,46 @@
package validators
var (
accountAccessTypeValues = []string{"R", "RCX", "ARCXDU"}
accountCUTypeValues = []string{"CU_M", "CU_C", "CU_D", "CU_S", "CU_A", "CU_NO", "CU_I", "CU_NP"}
driverValues = []string{"KVM_X86", "KVM_PPC"}
accessTypeValues = []string{"R", "RCX", "ARCXDU"}
resTypesValues = []string{"compute", "vins", "k8s", "openshift", "lb", "flipgroup"}
protoValues = []string{"tcp", "udp"}
bserviceDriverValues = []string{"KVM_X86, KVM_PPC"}
bserviceModeValues = []string{"ABSOLUTE", "RELATIVE"}
accountCUTypeValues = []string{"CU_M", "CU_C", "CU_D", "CU_S", "CU_A", "CU_NO", "CU_I", "CU_NP"}
computeTopologyValues = []string{"compute", "node"}
computePolicyValues = []string{"RECOMMENDED", "REQUIRED"}
computeModeValues = []string{"EQ", "EN", "ANY"}
computeDiskTypeValues = []string{"D", "B"}
computeNetTypeValues = []string{"EXTNET", "VINS"}
computeProtoValues = []string{"tcp", "udp"}
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"}
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"}
)

View File

@@ -23,7 +23,7 @@ type AddUserRequest struct {
// - 'RCX' for Write
// - 'ARCXDU' for Admin
// Required: true
AccessType string `url:"accesstype" json:"accesstype" validate:"required,accountAccessType"`
AccessType string `url:"accesstype" json:"accesstype" validate:"required,accessType"`
}
// AddUser gives a user access rights.

View File

@@ -44,7 +44,7 @@ type CreateRequest struct {
// If true send emails when a user is granted access to resources
// Required: false
SendAccessEmails bool `url:"sendAccessEmails,omitempty" json:"sendAccessEmails,omitempty"`
SendAccessEmails bool `url:"sendAccessEmails" json:"sendAccessEmails"`
// Limit (positive) or disable (0) GPU resources
// Required: false

View File

@@ -158,6 +158,12 @@ type RecordAccount struct {
// 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
CreatedBy string `json:"createdBy"`
@@ -165,7 +171,7 @@ type RecordAccount struct {
CreatedTime uint64 `json:"createdTime"`
// Deactivation time
DeactivationTime uint64 `json:"deactivationTime"`
DeactivationTime float64 `json:"deactivationTime"`
// Deleted by
DeletedBy string `json:"deletedBy"`
@@ -192,7 +198,7 @@ type RecordAccount struct {
ResourceLimits ResourceLimits `json:"resourceLimits"`
// Resource types
ResourceTypes []string `json:"resourceTypes"`
ResTypes []string `json:"resourceTypes"`
// Send access emails
SendAccessEmails bool `json:"sendAccessEmails"`

View File

@@ -3,8 +3,6 @@ package account
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
@@ -26,15 +24,10 @@ func (a Account) Restore(ctx context.Context, req RestoreRequest) (bool, error)
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 {
return false, err
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
return true, nil
}

View File

@@ -20,31 +20,31 @@ type UpdateRequest struct {
// Max size of memory in MB
// Required: false
MaxMemoryCapacity uint64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
// Max size of aggregated vdisks in GB
// Required: false
MaxVDiskCapacity uint64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
MaxVDiskCapacity int64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
// Max number of CPU cores
// Required: false
MaxCPUCapacity uint64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
MaxCPUCapacity int64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
// Max sent/received network transfer peering
// Required: false
MaxNetworkPeerTransfer uint64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
MaxNetworkPeerTransfer int64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
// Max number of assigned public IPs
// Required: false
MaxNumPublicIP uint64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
MaxNumPublicIP int64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
// If true send emails when a user is granted access to resources
// Required: false
SendAccessEmails bool `url:"sendAccessEmails,omitempty" json:"sendAccessEmails,omitempty"`
SendAccessEmails bool `url:"sendAccessEmails" json:"sendAccessEmails"`
// Limit (positive) or disable (0) GPU resources
// Required: false
GPUUnits uint64 `url:"gpu_units,omitempty" json:"gpu_units,omitempty"`
GPUUnits int64 `url:"gpu_units,omitempty" json:"gpu_units,omitempty"`
}
// Update updates an account name and resource types and limits

View File

@@ -23,7 +23,7 @@ type UpdateUserRequest struct {
// - 'RCX' for Write
// - 'ARCXDU' for Admin
// Required: true
AccessType string `url:"accesstype" json:"accesstype" validate:"required,accountAccessType"`
AccessType string `url:"accesstype" json:"accesstype" validate:"required,accessType"`
}
// UpdateUser updates user access rights

View File

@@ -43,7 +43,7 @@ type GroupAddRequest struct {
// - KVM_X86
// - KVM_PPC
// Required: true
Driver string `url:"driver" json:"driver" validate:"bserviceDriver"`
Driver string `url:"driver" json:"driver" validate:"driver"`
// Storage endpoint provider ID
// Required: false

View File

@@ -35,11 +35,8 @@ type RecordBasicService struct {
// Grid ID
GID uint64 `json:"gid"`
// List of Service Compute Group IDs
Groups []uint64 `json:"groups"`
// List of compute groups by name
GroupsName []string `json:"groupsName"`
// List of Service Compute Groups
Groups ListGroups `json:"groups"`
// GUID
GUID uint64 `json:"guid"`
@@ -95,6 +92,12 @@ type RecordBasicService struct {
// Main information about Compute
type ItemCompute struct {
// Account ID
AccountID uint64
// Architecture
Architecture string `json:"arch"`
// Compute group ID
CompGroupID uint64 `json:"compgroupId"`
@@ -109,11 +112,47 @@ type ItemCompute struct {
// 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
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
type ItemSnapshot struct {
// GUID

View File

@@ -0,0 +1,41 @@
package compute
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for getting boot order
type BootOrderGetRequest struct {
// Compute ID
// Required: true
ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
// BootOrderGet gets actual compute boot order information
func (c Compute) BootOrderGet(ctx context.Context, req BootOrderGetRequest) ([]string, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/compute/bootOrderGet"
res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
orders := make([]string, 0)
err = json.Unmarshal(res, &orders)
if err != nil {
return nil, err
}
return orders, nil
}

View File

@@ -0,0 +1,49 @@
package compute
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for setting boot order
type BootOrderSetRequest struct {
// ID of compute instance
// Required: true
ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
// List of boot devices
// Should be one of:
// - cdrom
// - network
// - hd
// Required: true
Order []string `url:"order" json:"order" validate:"min=1,computeOrder"`
}
// BootOrderSet sets compute boot order
func (c Compute) BootOrderSet(ctx context.Context, req BootOrderSetRequest) ([]string, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/compute/bootOrderSet"
res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
orders := make([]string, 0)
err = json.Unmarshal(res, &orders)
if err != nil {
return nil, err
}
return orders, nil
}

View File

@@ -0,0 +1,47 @@
package compute
import (
"context"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
"strconv"
)
// Request struct for changing link state
type ChangeLinkStateRequest struct {
// Compute ID
// Required: true
ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
// Interface name or MAC address
// Required: true
Interface string `url:"interface" json:"interface" validate:"required"`
// Interface state
// Must be either "on" or "off"
// Required: true
State string `url:"state" json:"state" validate:"required,interfaceState"`
}
// ChangeLinkState changes the status link virtual of compute
func (c Compute) ChangeLinkState(ctx context.Context, req ChangeLinkStateRequest) (bool, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/compute/changeLinkState"
res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
}

View File

@@ -22,6 +22,11 @@ type DiskAddRequest struct {
// Required: true
Size uint64 `url:"size" json:"size" validate:"required"`
// Storage endpoint provider ID
// By default the same with boot disk
// Required: false
SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`
// Type of the disk
// Should be one of:
// - D
@@ -29,11 +34,6 @@ type DiskAddRequest struct {
// Required: false
DiskType string `url:"diskType,omitempty" json:"diskType,omitempty" validate:"omitempty,computeDiskType"`
// Storage endpoint provider ID
// By default the same with boot disk
// Required: false
SepID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`
// Pool name
// By default will be chosen automatically
// Required: false

View File

@@ -17,6 +17,10 @@ type DiskAttachRequest struct {
// ID of the disk to attach
// Required: true
DiskID uint64 `url:"diskId" json:"diskId" validate:"required"`
// Type of the disk B;D
// Required: false
DiskType string `url:"diskType,omitempty" json:"diskType,omitempty" validate:"omitempty,computeDiskType"`
}
// DiskAttach attach disk to compute

View File

@@ -1,5 +1,13 @@
package compute
import (
"context"
"repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8s"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/lb"
)
// FilterByID returns ListComputes with specified ID.
func (lc ListComputes) FilterByID(id uint64) ListComputes {
predicate := func(ic ItemCompute) bool {
@@ -36,7 +44,7 @@ func (lc ListComputes) FilterByTechStatus(techStatus string) ListComputes {
return lc.FilterFunc(predicate)
}
// FilterByDiskID return ListComputes with specified DiskID.
// FilterByDiskID returns ListComputes with specified DiskID.
func (lc ListComputes) FilterByDiskID(diskID uint64) ListComputes {
predicate := func(ic ItemCompute) bool {
for _, disk := range ic.Disks {
@@ -50,6 +58,88 @@ func (lc ListComputes) FilterByDiskID(diskID uint64) ListComputes {
return lc.FilterFunc(predicate)
}
// FilterByK8SID returns master and worker nodes (ListComputes) inside specified K8S cluster.
func (lc ListComputes) FilterByK8SID(ctx context.Context, k8sID uint64, decortClient interfaces.Caller) (ListComputes, error) {
caller := k8s.New(decortClient)
req := k8s.GetRequest{
K8SID: k8sID,
}
cluster, err := caller.Get(ctx, req)
if err != nil {
return nil, err
}
predicate := func(ic ItemCompute) bool {
for _, info := range cluster.K8SGroups.Masters.DetailedInfo {
if info.ID == ic.ID {
return true
}
}
for _, worker := range cluster.K8SGroups.Workers {
for _, info := range worker.DetailedInfo {
if info.ID == ic.ID {
return true
}
}
}
return false
}
return lc.FilterFunc(predicate), nil
}
// K8SMasters is used to filter master nodes. Best used after FilterByK8SID function.
func (lc ListComputes) FilterByK8SMasters() ListComputes {
predicate := func(ic ItemCompute) bool {
for _, rule := range ic.AntiAffinityRules {
if rule.Value == "master" {
return true
}
}
return false
}
return lc.FilterFunc(predicate)
}
// K8SMasters is used to filter worker nodes. Best used after FilterByK8SID function.
func (lc ListComputes) FilterByK8SWorkers() ListComputes {
predicate := func(ic ItemCompute) bool {
for _, rule := range ic.AntiAffinityRules {
if rule.Value == "worker" {
return true
}
}
return false
}
return lc.FilterFunc(predicate)
}
// FilterByLBID returns ListComputes used by specified Load Balancer.
func (lc ListComputes) FilterByLBID(ctx context.Context, lbID uint64, decortClient interfaces.Caller) (ListComputes, error) {
caller := lb.New(decortClient)
req := lb.GetRequest{
LBID: lbID,
}
foundLB, err := caller.Get(ctx, req)
if err != nil {
return nil, err
}
predicate := func(ic ItemCompute) bool {
return ic.ID == foundLB.PrimaryNode.ComputeID || ic.ID == foundLB.SecondaryNode.ComputeID
}
return lc.FilterFunc(predicate), nil
}
// FilterFunc allows filtering ListComputes based on a user-specified predicate.
func (lc ListComputes) FilterFunc(predicate func(ItemCompute) bool) ListComputes {
var result ListComputes

View File

@@ -4,7 +4,7 @@ import "testing"
var computes = ListComputes{
ItemCompute{
ACL: []interface{}{},
ACL: ListACL{},
AccountID: 132847,
AccountName: "std_2",
AffinityLabel: "",
@@ -85,7 +85,7 @@ var computes = ListComputes{
VirtualImageID: 0,
},
ItemCompute{
ACL: []interface{}{},
ACL: ListACL{},
AccountID: 132848,
AccountName: "std_broker",
AffinityLabel: "",
@@ -150,92 +150,92 @@ var computes = ListComputes{
}
func TestFilterByID(t *testing.T) {
actual := computes.FilterByID(48500).FindOne()
actual := computes.FilterByID(48500).FindOne()
if actual.ID != 48500 {
t.Fatal("expected ID 48500, found: ", actual.ID)
}
if actual.ID != 48500 {
t.Fatal("expected ID 48500, found: ", actual.ID)
}
actualEmpty := computes.FilterByID(0)
actualEmpty := computes.FilterByID(0)
if len(actualEmpty) != 0 {
t.Fatal("expected empty, actual: ", len(actualEmpty))
}
if len(actualEmpty) != 0 {
t.Fatal("expected empty, actual: ", len(actualEmpty))
}
}
func TestFilterByName(t *testing.T) {
actual := computes.FilterByName("test").FindOne()
actual := computes.FilterByName("test").FindOne()
if actual.Name != "test" {
t.Fatal("expected compute with name 'test', found: ", actual.Name)
}
if actual.Name != "test" {
t.Fatal("expected compute with name 'test', found: ", actual.Name)
}
}
func TestFilterByStatus(t *testing.T) {
actual := computes.FilterByStatus("ENABLED")
actual := computes.FilterByStatus("ENABLED")
for _, item := range actual {
if item.Status != "ENABLED" {
t.Fatal("expected ENABLED status, found: ", item.Status)
}
}
for _, item := range actual {
if item.Status != "ENABLED" {
t.Fatal("expected ENABLED status, found: ", item.Status)
}
}
}
func TestFilterByTechStatus(t *testing.T) {
actual := computes.FilterByTechStatus("STARTED").FindOne()
actual := computes.FilterByTechStatus("STARTED").FindOne()
if actual.ID != 48556 {
t.Fatal("expected 48556 with STARTED techStatus, found: ", actual.ID)
}
if actual.ID != 48556 {
t.Fatal("expected 48556 with STARTED techStatus, found: ", actual.ID)
}
}
func TestFilterByDiskID(t *testing.T) {
actual := computes.FilterByDiskID(65248).FindOne()
actual := computes.FilterByDiskID(65248).FindOne()
if actual.ID != 48556 {
t.Fatal("expected 48556 with DiskID 65248, found: ", actual.ID)
}
if actual.ID != 48556 {
t.Fatal("expected 48556 with DiskID 65248, found: ", actual.ID)
}
}
func TestFilterFunc(t *testing.T) {
actual := computes.FilterFunc(func(ic ItemCompute) bool {
return ic.Registered == true
})
actual := computes.FilterFunc(func(ic ItemCompute) bool {
return ic.Registered == true
})
if len(actual) != 2 {
t.Fatal("expected 2 elements found, actual: ", len(actual))
}
if len(actual) != 2 {
t.Fatal("expected 2 elements found, actual: ", len(actual))
}
for _, item := range actual {
if item.Registered != true {
t.Fatal("expected Registered to be true, actual: ", item.Registered)
}
}
for _, item := range actual {
if item.Registered != true {
t.Fatal("expected Registered to be true, actual: ", item.Registered)
}
}
}
func TestSortingByCreatedTime(t *testing.T) {
actual := computes.SortByCreatedTime(false)
actual := computes.SortByCreatedTime(false)
if actual[0].Name != "test" {
t.Fatal("expected 'test', found: ", actual[0].Name)
}
if actual[0].Name != "test" {
t.Fatal("expected 'test', found: ", actual[0].Name)
}
actual = computes.SortByCreatedTime(true)
if actual[0].Name != "compute_2" {
t.Fatal("expected 'compute_2', found: ", actual[0].Name)
}
actual = computes.SortByCreatedTime(true)
if actual[0].Name != "compute_2" {
t.Fatal("expected 'compute_2', found: ", actual[0].Name)
}
}
func TestSortingByCPU(t *testing.T) {
actual := computes.SortByCPU(false)
actual := computes.SortByCPU(false)
if actual[0].CPU != 4{
t.Fatal("expected 4 CPU cores, found: ", actual[0].CPU)
}
if actual[0].CPU != 4 {
t.Fatal("expected 4 CPU cores, found: ", actual[0].CPU)
}
actual = computes.SortByCPU(true)
actual = computes.SortByCPU(true)
if actual[0].CPU != 6 {
t.Fatal("expected 6 CPU cores, found: ", actual[0].CPU)
}
if actual[0].CPU != 6 {
t.Fatal("expected 6 CPU cores, found: ", actual[0].CPU)
}
}

View File

@@ -1,5 +1,7 @@
package compute
import "strconv"
// Access Control List
type RecordACL struct {
// Account ACL list
@@ -12,10 +14,27 @@ type RecordACL struct {
RGACL ListACL `json:"rgAcl"`
}
type Explicit bool
func (e *Explicit) UnmarshalJSON(b []byte) error {
if b[0] == '"' {
b = b[1 : len(b)-1]
}
res, err := strconv.ParseBool(string(b))
if err != nil {
return err
}
*e = Explicit(res)
return nil
}
// ACL information
type ItemACL struct {
// Explicit
Explicit bool `json:"explicit"`
Explicit Explicit `json:"explicit"`
// GUID
GUID string `json:"guid"`
@@ -131,6 +150,9 @@ type RecordNetAttach struct {
// Default GW
DefGW string `json:"defGw"`
// Enabled
Enabled bool `json:"enabled"`
// FLIPGroup ID
FLIPGroupID uint64 `json:"flipgroupId"`
@@ -159,7 +181,7 @@ type RecordNetAttach struct {
NetType string `json:"netType"`
// PCI slot
PCISlot uint64 `json:"pciSlot"`
PCISlot int64 `json:"pciSlot"`
// QOS
QOS QOS `json:"qos"`
@@ -464,6 +486,9 @@ type ItemVNFInterface struct {
// Default GW
DefGW string `json:"defGw"`
// Enabled
Enabled bool `json:"enabled"`
// FLIPGroup ID
FLIPGroupID uint64 `json:"flipgroupId"`
@@ -492,7 +517,7 @@ type ItemVNFInterface struct {
NetType string `json:"netType"`
// PCI slot
PCISlot uint64 `json:"pciSlot"`
PCISlot int64 `json:"pciSlot"`
// QOS
QOS QOS `json:"qos"`
@@ -592,7 +617,7 @@ type ItemComputeDisk struct {
Passwd string `json:"passwd"`
// PCI slot
PCISlot uint64 `json:"pciSlot"`
PCISlot int64 `json:"pciSlot"`
// Pool
Pool string `json:"pool"`
@@ -709,8 +734,7 @@ type IOTune struct {
// Main information about compute
type ItemCompute struct {
// Access Control List
ACL []interface{} `json:"acl"`
ACL ListACL `json:"acl"`
// Account ID
AccountID uint64 `json:"accountId"`
@@ -877,7 +901,7 @@ type InfoDisk struct {
ID uint64 `json:"id"`
// PCISlot
PCISlot uint64 `json:"pciSlot"`
PCISlot int64 `json:"pciSlot"`
}
// List information about computes

View File

@@ -29,7 +29,7 @@ type PFWAddRequest struct {
// Network protocol
// either "tcp" or "udp"
// Required: true
Proto string `url:"proto" json:"proto" validate:"computeProto"`
Proto string `url:"proto" json:"proto" validate:"proto"`
}
// PFWAdd add port forward rule

View File

@@ -24,7 +24,7 @@ type UserGrantRequest struct {
// - 'RCX' for Write
// - 'ARCXDU' for Admin
// Required: true
AccessType string `url:"accesstype" json:"accesstype" validate:"accountAccessType"`
AccessType string `url:"accesstype" json:"accesstype" validate:"accessType"`
}
// UserGrant grant user access to the compute

View File

@@ -24,7 +24,7 @@ type UserUpdateRequest struct {
// - 'RCX' for Write
// - 'ARCXDU' for Admin
// Required: true
AccessType string `url:"accesstype" json:"accesstype" validate:"accountAccessType"`
AccessType string `url:"accesstype" json:"accesstype" validate:"accessType"`
}
// UserUpdate updates user access to the compute

View File

@@ -2,7 +2,6 @@ package disks
import (
"context"
"errors"
"net/http"
"strconv"
@@ -13,15 +12,15 @@ import (
type CreateRequest struct {
// ID of the account
// Required: true
AccountID uint64 `url:"accountId" json:"accountId"`
AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// ID of the grid (platform)
// Required: true
GID uint64 `url:"gid" json:"gid"`
GID uint64 `url:"gid" json:"gid" validate:"required"`
// Name of disk
// Required: true
Name string `url:"name" json:"name"`
Name string `url:"name" json:"name" validate:"required"`
// Description of disk
// Required: false
@@ -36,7 +35,7 @@ type CreateRequest struct {
// - D=Data
// - T=Temp
// Required: true
Type string `url:"type" json:"type"`
Type string `url:"type" json:"type" validate:"diskType"`
// Size in GB default is 0
// Required: false
@@ -55,29 +54,13 @@ type CreateRequest struct {
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
}
func (drq CreateRequest) validate() error {
if drq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
if drq.GID == 0 {
return errors.New("validation-error: field GID can not be empty or equal to 0")
}
if drq.Name == "" {
return errors.New("validation-error: field Name can not be empty")
}
validType := validators.StringInSlice(drq.Type, []string{"B", "D", "T"})
if !validType {
return errors.New("validation-error: field Type must be set as B, D or T")
}
return nil
}
// Create creates a disk
func (d Disks) Create(ctx context.Context, req CreateRequest) (uint64, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return 0, err
for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/create"

View File

@@ -2,16 +2,17 @@ package disks
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request for delete disk
type DeleteRequest struct {
// ID of disk to delete
// Required: true
DiskID uint64 `url:"diskId" json:"diskId"`
DiskID uint64 `url:"diskId" json:"diskId" validate:"required"`
// Detach disk from machine first
// Required: false
@@ -26,19 +27,13 @@ type DeleteRequest struct {
Reason string `url:"reason,omitempty" json:"reason,omitempty"`
}
func (d DeleteRequest) validate() error {
if d.DiskID == 0 {
return errors.New("validation-error: field DiskID must be set")
}
return nil
}
// Delete deletes disk by ID
func (d Disks) Delete(ctx context.Context, req DeleteRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/delete"

View File

@@ -2,42 +2,34 @@ package disks
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for multiple disks
type DisksDeleteRequest struct {
// List of disk ids to delete
// Required: true
DisksIDs []uint64 `url:"diskIds" json:"diskIds"`
DisksIDs []uint64 `url:"diskIds" json:"diskIds" validate:"required"`
// Reason for deleting the disks
// Required: true
Reason string `url:"reason" json:"reason"`
Reason string `url:"reason" json:"reason" validate:"required"`
// Whether to completely delete the disks, works only with non attached disks
// Required: false
Permanently bool `url:"permanently,omitempty" json:"permanently,omitempty"`
}
func (drq DisksDeleteRequest) validate() error {
if len(drq.DisksIDs) == 0 {
return errors.New("validation-error: field DisksIDs must include one or more disks ids")
}
if drq.Reason == "" {
return errors.New("validation-error: field Reason must be set")
}
return nil
}
// DeleteDisks deletes multiple disks permanently
func (d Disks) DeleteDisks(ctx context.Context, req DisksDeleteRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/deleteDisks"

View File

@@ -1,5 +1,14 @@
package disks
import (
"context"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8s"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/lb"
)
// FilterByID returns ListDisks with specified ID.
func (ld ListDisks) FilterByID(id uint64) ListDisks {
predicate := func(idisk ItemDisk) bool {
@@ -36,6 +45,69 @@ func (ld ListDisks) FilterByTechStatus(techStatus string) ListDisks {
return ld.FilterFunc(predicate)
}
// FilterByComputeID is used to filter ListDisks attached to specified compute.
func (ld ListDisks) FilterByComputeID(computeID uint64) ListDisks {
predicate := func(idisk ItemDisk) bool {
for k := range idisk.Computes {
if k == strconv.FormatUint(computeID, 10) {
return true
}
}
return false
}
return ld.FilterFunc(predicate)
}
// FilterByK8SID is used to filter ListDisks by specified K8S cluster.
func (ld ListDisks) FilterByK8SID(ctx context.Context, k8sID uint64, decortClient interfaces.Caller) (ListDisks, error) {
caller := k8s.New(decortClient)
req := k8s.GetRequest{
K8SID: k8sID,
}
cluster, err := caller.Get(ctx, req)
if err != nil {
return nil, err
}
var result ListDisks
for _, masterCompute := range cluster.K8SGroups.Masters.DetailedInfo {
result = append(result, ld.FilterByComputeID(masterCompute.ID)...)
}
for _, workerGroup := range cluster.K8SGroups.Workers {
for _, workerCompute := range workerGroup.DetailedInfo {
result = append(result, ld.FilterByComputeID(workerCompute.ID)...)
}
}
return result, nil
}
// FilterByLBID is used to filter ListDisks used by computes inside specified Load Balancer.
func (ld ListDisks) FilterByLBID(ctx context.Context, lbID uint64, decortClient interfaces.Caller) (ListDisks, error) {
caller := lb.New(decortClient)
req := lb.GetRequest{
LBID: lbID,
}
foundLB, err := caller.Get(ctx, req)
if err != nil {
return nil, err
}
var result ListDisks
result = append(result, ld.FilterByComputeID(foundLB.PrimaryNode.ComputeID)...)
result = append(result, ld.FilterByComputeID(foundLB.SecondaryNode.ComputeID)...)
return result, nil
}
// FilterFunc allows filtering ListDisks based on a user-specified predicate.
func (ld ListDisks) FilterFunc(predicate func(ItemDisk) bool) ListDisks {
var result ListDisks
@@ -58,3 +130,62 @@ func (ld ListDisks) FindOne() ItemDisk {
return ld[0]
}
// FilterByID returns ListDisksUnattached with specified ID.
func (lu ListDisksUnattached) FilterByID(id uint64) ListDisksUnattached {
predicate := func(idisk ItemDiskUnattached) bool {
return idisk.ID == id
}
return lu.FilterFunc(predicate)
}
// FilterByName returns ListDisksUnattached with specified Name.
func (lu ListDisksUnattached) FilterByName(name string) ListDisksUnattached {
predicate := func(idisk ItemDiskUnattached) bool {
return idisk.Name == name
}
return lu.FilterFunc(predicate)
}
// FilterByStatus returns ListDisksUnattached with specified Status.
func (lu ListDisksUnattached) FilterByStatus(status string) ListDisksUnattached {
predicate := func(idisk ItemDiskUnattached) bool {
return idisk.Status == status
}
return lu.FilterFunc(predicate)
}
// FilterByTechStatus returns ListDisksUnattached with specified TechStatus.
func (lu ListDisksUnattached) FilterByTechStatus(techStatus string) ListDisksUnattached {
predicate := func(idisk ItemDiskUnattached) bool {
return idisk.TechStatus == techStatus
}
return lu.FilterFunc(predicate)
}
// FilterFunc allows filtering ListDisksUnattached based on a user-specified predicate.
func (lu ListDisksUnattached) FilterFunc(predicate func(ItemDiskUnattached) bool) ListDisksUnattached {
var result ListDisksUnattached
for _, item := range lu {
if predicate(item) {
result = append(result, item)
}
}
return result
}
// FindOne returns first found ItemDiskUnattached
// If none was found, returns an empty struct.
func (lu ListDisksUnattached) FindOne() ItemDiskUnattached {
if len(lu) == 0 {
return ItemDiskUnattached{}
}
return lu[0]
}

View File

@@ -1,6 +1,8 @@
package disks
import "testing"
import (
"testing"
)
var disks = ListDisks{
ItemDisk{
@@ -175,3 +177,198 @@ func TestSortByCreatedTime(t *testing.T) {
t.Fatal("expected ID 65193, found: ", actual[0].ID)
}
}
var unattachedDisks = ListDisksUnattached{
{
CKey: "",
Meta: []interface{}{
"cloudbroker",
"disk",
1,
},
AccountID: 149,
AccountName: "test_account1",
ACL: map[string]interface{}{},
BootPartition: 0,
CreatedTime: 1681477547,
DeletedTime: 0,
Description: "",
DestructionTime: 0,
DiskPath: "",
GID: 2002,
GUID: 22636,
ID: 22636,
ImageID: 0,
Images: []uint64{},
IOTune: IOTune{
TotalIOPSSec: 2000,
},
IQN: "",
Login: "",
Milestones: 43834,
Name: "test_disk",
Order: 0,
Params: "",
ParentID: 0,
Password: "",
PCISlot: -1,
Pool: "data05",
PresentTo: []uint64{},
PurgeAttempts: 0,
PurgeTime: 0,
RealityDeviceNumber: 0,
ReferenceID: "",
ResID: "79bd3bd8-3424-48d3-963f-1870d506f169",
ResName: "volumes/volume_22636",
Role: "",
SEPID: 1,
Shareable: false,
SizeMax: 0,
SizeUsed: 0,
Snapshots: nil,
Status: "CREATED",
TechStatus: "ALLOCATED",
Type: "D",
VMID: 0,
},
{
CKey: "",
Meta: []interface{}{
"cloudbroker",
"disk",
1,
},
AccountID: 150,
AccountName: "test_account",
ACL: map[string]interface{}{},
BootPartition: 0,
CreatedTime: 1681477558,
DeletedTime: 0,
Description: "",
DestructionTime: 0,
DiskPath: "",
GID: 2002,
GUID: 22637,
ID: 22637,
ImageID: 0,
Images: []uint64{},
IOTune: IOTune{
TotalIOPSSec: 2000,
},
IQN: "",
Login: "",
Milestones: 43834,
Name: "test_disk",
Order: 0,
Params: "",
ParentID: 0,
Password: "",
PCISlot: -1,
Pool: "data05",
PresentTo: []uint64{
27,
27,
},
PurgeAttempts: 0,
PurgeTime: 0,
RealityDeviceNumber: 0,
ReferenceID: "",
ResID: "79bd3bd8-3424-48d3-963f-1870d506f169",
ResName: "volumes/volume_22637",
Role: "",
SEPID: 1,
Shareable: false,
SizeMax: 0,
SizeUsed: 0,
Snapshots: nil,
Status: "CREATED",
TechStatus: "ALLOCATED",
Type: "B",
VMID: 0,
},
}
func TestListDisksUnattached_FilterByID(t *testing.T) {
actual := unattachedDisks.FilterByID(22636)
if len(actual) == 0 {
t.Fatal("No elements were found")
}
actualItem := actual.FindOne()
if actualItem.ID != 22636 {
t.Fatal("expected ID 22636, found: ", actualItem.ID)
}
}
func TestListDisksUnattached_FilterByName(t *testing.T) {
actual := unattachedDisks.FilterByName("test_disk")
if len(actual) != 2 {
t.Fatal("expected 2 elements, found: ", len(actual))
}
for _, item := range actual {
if item.Name != "test_disk" {
t.Fatal("expected 'test_disk' name, found: ", item.Name)
}
}
}
func TestListDisksUnattached_FilterByStatus(t *testing.T) {
actual := unattachedDisks.FilterByStatus("CREATED")
if len(actual) == 0 {
t.Fatal("No elements were found")
}
for _, item := range actual {
if item.Status != "CREATED" {
t.Fatal("expected 'CREATED' status, found: ", item.Status)
}
}
}
func TestListDisksUnattached_FilterByTechStatus(t *testing.T) {
actual := unattachedDisks.FilterByTechStatus("ALLOCATED")
if len(actual) == 0 {
t.Fatal("No elements were found")
}
for _, item := range actual {
if item.TechStatus != "ALLOCATED" {
t.Fatal("expected 'ALLOCATED' techStatus, found: ", item.TechStatus)
}
}
}
func TestListDisksUnattached_FilterFunc(t *testing.T) {
actual := unattachedDisks.FilterFunc(func(id ItemDiskUnattached) bool {
return len(id.PresentTo) == 2
})
if len(actual) == 0 {
t.Fatal("No elements were found")
}
if len(actual[0].PresentTo) != 2 {
t.Fatal("expected 2 elements in PresentTo, found: ", len(actual[0].PresentTo))
}
}
func TestListDisksUnattached_SortByCreatedTime(t *testing.T) {
actual := unattachedDisks.SortByCreatedTime(false)
if actual[0].ID != 22636 {
t.Fatal("expected ID 22636, found: ", actual[0].ID)
}
actual = unattachedDisks.SortByCreatedTime(true)
if actual[0].ID != 22637 {
t.Fatal("expected ID 22637, found: ", actual[0].ID)
}
}

View File

@@ -3,31 +3,26 @@ package disks
import (
"context"
"encoding/json"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get information about disk
type GetRequest struct {
// ID of the disk
// Required: true
DiskID uint64 `url:"diskId" json:"diskId"`
}
func (drq GetRequest) validate() error {
if drq.DiskID == 0 {
return errors.New("validation-error: field DiskID can not be empty or equal to 0")
}
return nil
DiskID uint64 `url:"diskId" json:"diskId" validate:"required"`
}
// Get gets disk details
// Notice: the devicename field is the name as it is passed to the kernel (kname in linux) for unattached disks this field has no relevant value
func (d Disks) Get(ctx context.Context, req GetRequest) (*RecordDisk, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return nil, err
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/get"

View File

@@ -2,16 +2,17 @@ package disks
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for limit IO
type LimitIORequest struct {
// ID of the disk to limit
// Required: true
DiskID uint64 `url:"diskId" json:"diskId"`
DiskID uint64 `url:"diskId" json:"diskId" validate:"required"`
// Alias for total_iops_sec for backwards compatibility
// Required: false
@@ -70,21 +71,15 @@ type LimitIORequest struct {
SizeIOPSSec uint64 `url:"size_iops_sec,omitempty" json:"size_iops_sec,omitempty"`
}
func (drq LimitIORequest) validate() error {
if drq.DiskID == 0 {
return errors.New("validation-error: field DiskID can not be empty or equal to 0")
}
return nil
}
// LimitIO limit IO for a certain disk
// total and read/write options are not allowed to be combined
// see http://libvirt.org/formatdomain.html#elementsDisks iotune section for more details
func (d Disks) LimitIO(ctx context.Context, req LimitIORequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/limitIO"

View File

@@ -9,8 +9,8 @@ import (
// Request struct for get list types of disks
type ListTypesRequest struct {
// Show detailed disk types by seps
// Required: false
Detailed bool `url:"detailed" json:"detailed"`
// Required: true
Detailed bool `url:"detailed" json:"detailed" validate:"required"`
}
// ListTypes gets list defined disk types

View File

@@ -14,7 +14,7 @@ type ListUnattachedRequest struct {
}
// ListUnattached gets list of unattached disks
func (d Disks) ListUnattached(ctx context.Context, req ListUnattachedRequest) (ListDisks, error) {
func (d Disks) ListUnattached(ctx context.Context, req ListUnattachedRequest) (ListDisksUnattached, error) {
url := "/cloudapi/disks/listUnattached"
res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req)
@@ -22,7 +22,7 @@ func (d Disks) ListUnattached(ctx context.Context, req ListUnattachedRequest) (L
return nil, err
}
list := ListDisks{}
list := ListDisksUnattached{}
err = json.Unmarshal(res, &list)
if err != nil {

View File

@@ -114,9 +114,146 @@ type ItemDisk struct {
VMID uint64 `json:"vmid"`
}
type ItemDiskUnattached struct {
// CKey
CKey string `json:"_ckey"`
// Meta
Meta []interface{} `json:"_meta"`
// Account ID
AccountID uint64 `json:"accountId"`
// Account name
AccountName string `json:"accountName"`
// Access Control List
ACL map[string]interface{} `json:"acl"`
// Boot Partition
BootPartition uint64 `json:"bootPartition"`
// Created time
CreatedTime uint64 `json:"createdTime"`
// Deleted time
DeletedTime uint64 `json:"deletedTime"`
// Description
Description string `json:"desc"`
// Destruction time
DestructionTime uint64 `json:"destructionTime"`
// Disk path
DiskPath string `json:"diskPath"`
// Grid ID
GID uint64 `json:"gid"`
// GUID
GUID uint64 `json:"guid"`
// ID
ID uint64 `json:"id"`
// Image ID
ImageID uint64 `json:"imageId"`
// Images
Images []uint64 `json:"images"`
// IOTune
IOTune IOTune `json:"iotune"`
// IQN
IQN string `json:"iqn"`
// Login
Login string `json:"login"`
// Milestones
Milestones uint64 `json:"milestones"`
// Name
Name string `json:"name"`
// Order
Order uint64 `json:"order"`
// Params
Params string `json:"params"`
// Parent ID
ParentID uint64 `json:"parentId"`
// Password
Password string `json:"passwd"`
//PCISlot
PCISlot int64 `json:"pciSlot"`
// Pool
Pool string `json:"pool"`
// Present to
PresentTo []uint64 `json:"presentTo"`
// Purge attempts
PurgeAttempts uint64 `json:"purgeAttempts"`
// Purge time
PurgeTime uint64 `json:"purgeTime"`
// Reality device number
RealityDeviceNumber uint64 `json:"realityDeviceNumber"`
// Reference ID
ReferenceID string `json:"referenceId"`
// Resource ID
ResID string `json:"resId"`
// Resource name
ResName string `json:"resName"`
// Role
Role string `json:"role"`
// ID SEP
SEPID uint64 `json:"sepId"`
// Shareable
Shareable bool `json:"shareable"`
// Size max
SizeMax uint64 `json:"sizeMax"`
// Size used
SizeUsed float64 `json:"sizeUsed"`
// List of snapshots
Snapshots ListSnapshots `json:"snapshots"`
// Status
Status string `json:"status"`
// Tech status
TechStatus string `json:"techStatus"`
// Type
Type string `json:"type"`
// Virtual machine ID
VMID uint64 `json:"vmid"`
}
// List of disks
type ListDisks []ItemDisk
// List of unattached disks
type ListDisksUnattached []ItemDiskUnattached
// Main information about snapshot
type ItemSnapshot struct {
// GUID
@@ -240,7 +377,7 @@ type RecordDisk struct {
ParentID uint64 `json:"parentId"`
// PCI slot
PCISlot uint64 `json:"pciSlot"`
PCISlot int64 `json:"pciSlot"`
// Pool
Pool string `json:"pool"`

View File

@@ -2,38 +2,30 @@ package disks
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for rename disk
type RenameRequest struct {
// ID of the disk to rename
// Required: true
DiskID uint64 `url:"diskId" json:"diskId"`
DiskID uint64 `url:"diskId" json:"diskId" validate:"required"`
// New name of disk
// Required: true
Name string `url:"name" json:"name"`
}
func (drq RenameRequest) validate() error {
if drq.DiskID == 0 {
return errors.New("validation-error: field DiskID can not be empty or equal to 0")
}
if drq.Name == "" {
return errors.New("validation-error: field Name can not be empty")
}
return nil
Name string `url:"name" json:"name" validate:"required"`
}
// Rename rename disk
func (d Disks) Rename(ctx context.Context, req RenameRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/rename"

View File

@@ -2,31 +2,21 @@ package disks
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for resize disk
type ResizeRequest struct {
// ID of the disk to resize
// Required: true
DiskID uint64 `url:"diskId" json:"diskId"`
DiskID uint64 `url:"diskId" json:"diskId" validate:"required"`
// New size of the disk in GB
// Required: true
Size uint64 `url:"size" json:"size"`
}
func (drq ResizeRequest) validate() error {
if drq.DiskID == 0 {
return errors.New("validation-error: field DiskID can not be empty or equal to 0")
}
if drq.Size == 0 {
return errors.New("validation-error: field Size can not be empty or equal to 0")
}
return nil
Size uint64 `url:"size" json:"size" validate:"required"`
}
// Resize resize disk
@@ -34,9 +24,11 @@ func (drq ResizeRequest) validate() error {
// in that case please stop and start your machine after changing the disk size, for your changes to be reflected.
// This method will not be used for disks, assigned to computes. Only unassigned disks and disks, assigned with "old" virtual machines.
func (d Disks) Resize(ctx context.Context, req ResizeRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/resize"
@@ -59,9 +51,11 @@ func (d Disks) Resize(ctx context.Context, req ResizeRequest) (bool, error) {
// in that case please stop and start your machine after changing the disk size, for your changes to be reflected.
// This method will not be used for disks, assigned to "old" virtual machines. Only unassigned disks and disks, assigned with computes.
func (d Disks) Resize2(ctx context.Context, req ResizeRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/resize2"

View File

@@ -2,38 +2,30 @@ package disks
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for restore a deleted unattached disk
type RestoreRequest struct {
// ID of the disk to restore
// Required: true
DiskID uint64 `url:"diskId" json:"diskId"`
DiskID uint64 `url:"diskId" json:"diskId" validate:"required"`
// Reason for restoring the disk
// Required: true
Reason string `url:"reason" json:"reason"`
}
func (drq RestoreRequest) validate() error {
if drq.DiskID == 0 {
return errors.New("validation-error: field DiskID can not be empty or equal to 0")
}
if drq.Reason == "" {
return errors.New("validation-error: field Reason can not be empty")
}
return nil
Reason string `url:"reason" json:"reason" validate:"required"`
}
// Restore restore a deleted unattached disk from recycle bin
func (d Disks) Restore(ctx context.Context, req RestoreRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/restore"

View File

@@ -41,3 +41,39 @@ func (idisk ItemDisk) Serialize(params ...string) (serialization.Serialized, err
return json.Marshal(idisk)
}
// 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 (lu ListDisksUnattached) Serialize(params ...string) (serialization.Serialized, error) {
if len(lu) == 0 {
return []byte{}, nil
}
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(lu, prefix, indent)
}
return json.Marshal(lu)
}
// 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 (idisk ItemDiskUnattached) Serialize(params ...string) (serialization.Serialized, error) {
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(idisk, prefix, indent)
}
return json.Marshal(idisk)
}

View File

@@ -2,31 +2,26 @@ package disks
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for share data disk
type ShareRequest struct {
// ID of the disk to share
// Required: true
DiskID uint64 `url:"diskId" json:"diskId"`
}
func (drq ShareRequest) validate() error {
if drq.DiskID == 0 {
return errors.New("validation-error: field DiskID can not be empty or equal to 0")
}
return nil
DiskID uint64 `url:"diskId" json:"diskId" validate:"required"`
}
// Share shares data disk
func (d Disks) Share(ctx context.Context, req ShareRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/share"

View File

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

View File

@@ -2,42 +2,34 @@ package disks
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for rollback snapshot
type SnapshotRollbackRequest struct {
// ID of the disk
// Required: true
DiskID uint64 `url:"diskId" json:"diskId"`
DiskID uint64 `url:"diskId" json:"diskId" validate:"required"`
// Label of the snapshot to rollback
// Required: true
Label string `url:"label" json:"label"`
// Required: false
Label string `url:"label,omitempty" json:"label,omitempty"`
// Timestamp of the snapshot to rollback
// Required: true
TimeStamp uint64 `url:"timestamp" json:"timestamp"`
}
func (drq SnapshotRollbackRequest) validate() error {
if drq.DiskID == 0 {
return errors.New("validation-error: field DiskID can not be empty or equal to 0")
}
if drq.Label == "" && drq.TimeStamp == 0 {
return errors.New("validation-error: field Label or field TimeStamp can not be empty")
}
return nil
// Required: false
TimeStamp uint64 `url:"timestamp,omitempty" json:"timestamp,omitempty"`
}
// SnapshotRollback rollback an individual disk snapshot
func (d Disks) SnapshotRollback(ctx context.Context, req SnapshotRollbackRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/snapshotRollback"

View File

@@ -58,3 +58,60 @@ func (ld ListDisks) SortByDeletedTime(inverse bool) ListDisks {
return ld
}
// SortByCreatedTime sorts ListDisksUnattached by the CreatedTime field in ascending order.
//
// If inverse param is set to true, the order is reversed.
func (lu ListDisksUnattached) SortByCreatedTime(inverse bool) ListDisksUnattached {
if len(lu) < 2 {
return lu
}
sort.Slice(lu, func(i, j int) bool {
if inverse {
return lu[i].CreatedTime > lu[j].CreatedTime
}
return lu[i].CreatedTime < lu[j].CreatedTime
})
return lu
}
// SortByDestructionTime sorts ListDisksUnattached by the DestructionTime field in ascending order.
//
// If inverse param is set to true, the order is reversed.
func (lu ListDisksUnattached) SortByDestructionTime(inverse bool) ListDisksUnattached {
if len(lu) < 2 {
return lu
}
sort.Slice(lu, func(i, j int) bool {
if inverse {
return lu[i].DestructionTime > lu[j].DestructionTime
}
return lu[i].DestructionTime < lu[j].DestructionTime
})
return lu
}
// SortByDeletedTime sorts ListDisksUnattached by the DeletedTime field in ascending order.
//
// If inverse param is set to true, the order is reversed.
func (lu ListDisksUnattached) SortByDeletedTime(inverse bool) ListDisksUnattached {
if len(lu) < 2 {
return lu
}
sort.Slice(lu, func(i, j int) bool {
if inverse {
return lu[i].DeletedTime > lu[j].DeletedTime
}
return lu[i].DeletedTime < lu[j].DeletedTime
})
return lu
}

View File

@@ -2,31 +2,26 @@ package disks
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for unshare data disk
type UnshareRequest struct {
// ID of the disk to unshare
// Required: true
DiskID uint64 `url:"diskId" json:"diskId"`
}
func (drq UnshareRequest) validate() error {
if drq.DiskID == 0 {
return errors.New("validation-error: field DiskID can not be empty or equal to 0")
}
return nil
DiskID uint64 `url:"diskId" json:"diskId" validate:"required"`
}
// Unshare unshares data disk
func (d Disks) Unshare(ctx context.Context, req UnshareRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/disks/unshare"

View File

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

View File

@@ -3,30 +3,25 @@ package extnet
import (
"context"
"encoding/json"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get list computes
type ListComputesRequest struct {
// Filter by account ID
// Required: true
AccountID uint64 `url:"accountId" json:"accountId"`
}
func (erq ListComputesRequest) validate() error {
if erq.AccountID == 0 {
return errors.New("validation-error: field AccountID can not be empty or equal to 0")
}
return nil
AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
}
// ListComputes gets computes from account with extnets
func (e ExtNet) ListComputes(ctx context.Context, req ListComputesRequest) (ListExtNetComputes, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return nil, err
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/extnet/listComputes"

View File

@@ -59,6 +59,9 @@ type ListExtNetComputes []ItemExtNetCompute
// QOS
type QOS struct {
// EBurst
EBurst uint64 `json:"eBurst"`
// ERate
ERate uint64 `json:"eRate"`
@@ -107,6 +110,23 @@ type VNFs struct {
DHCP uint64 `json:"dhcp"`
}
type Excluded struct {
// ClientType
ClientType string `json:"clientType"`
// IP
IP string `json:"ip"`
// MAC
MAC string `json:"mac"`
// Type
Type string `json:"type"`
// VMID
VMID uint64 `json:"vmId"`
}
// Detailed information about external network
type RecordExtNet struct {
// CKey
@@ -134,7 +154,7 @@ type RecordExtNet struct {
DNS []string `json:"dns"`
// Excluded
Excluded []string `json:"excluded"`
Excluded []Excluded `json:"excluded"`
// Free IPs
FreeIPs uint64 `json:"free_ips"`

View File

@@ -2,38 +2,30 @@ package flipgroup
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for add compute instance
type ComputeAddRequest struct {
// ID of the Floating IP group to add compute instance to
// Required: true
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId"`
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId" validate:"required"`
// ID of the compute instance to add to this group
// Required: true
ComputeID uint64 `url:"computeId" json:"computeId"`
}
func (frq ComputeAddRequest) validate() error {
if frq.FLIPGroupID == 0 {
return errors.New("field FLIPGroupID can not be empty or equal to 0")
}
if frq.ComputeID == 0 {
return errors.New("field ComputeID can not be empty or equal to 0")
}
return nil
ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
// ComputeAdd add compute instance to the Floating IP group
func (f FLIPGroup) ComputeAdd(ctx context.Context, req ComputeAddRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/flipgroup/computeAdd"

View File

@@ -2,38 +2,30 @@ package flipgroup
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for remove compute instance
type ComputeRemoveRequest struct {
// ID of the Floating IP group to remove compute instance from
// Required: true
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId"`
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId" validate:"required"`
// ID of the compute instance to remove
// Required: true
ComputeID uint64 `url:"computeId" json:"computeId"`
}
func (frq ComputeRemoveRequest) validate() error {
if frq.FLIPGroupID == 0 {
return errors.New("field FLIPGroupID can not be empty or equal to 0")
}
if frq.ComputeID == 0 {
return errors.New("field ComputeID can not be empty or equal to 0")
}
return nil
ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
// ComputeRemove remove compute instance from the Floating IP group
func (f FLIPGroup) ComputeRemove(ctx context.Context, req ComputeRemoveRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/flipgroup/computeRemove"

View File

@@ -3,7 +3,6 @@ package flipgroup
import (
"context"
"encoding/json"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
@@ -13,28 +12,28 @@ import (
type CreateRequest struct {
// Account ID
// Required: true
AccountID uint64 `url:"accountId" json:"accountId"`
AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// FLIPGroup name
// Required: true
Name string `url:"name" json:"name"`
Name string `url:"name" json:"name" validate:"required"`
// Network type
// Should be one of:
// - EXTNET
// - VINS
// Required: true
NetType string `url:"netType" json:"netType"`
NetType string `url:"netType" json:"netType" validate:"computeNetType"`
// ID of external network or VINS
// Required: true
NetID uint64 `url:"netId" json:"netId"`
NetID uint64 `url:"netId" json:"netId" validate:"required"`
// Type of client
// - 'compute'
// - 'vins' (will be later)
// Required: true
ClientType string `url:"clientType" json:"clientType"`
ClientType string `url:"clientType" json:"clientType" validate:"flipgroupClientType"`
// IP address to associate with this group. If empty, the platform will autoselect IP address
// Required: false
@@ -45,33 +44,13 @@ type CreateRequest struct {
Description string `url:"desc,omitempty" json:"desc,omitempty"`
}
func (frq CreateRequest) validate() error {
if frq.AccountID == 0 {
return errors.New("field AccountID can not be empty or equal to 0")
}
if frq.NetID == 0 {
return errors.New("field NetID can not be empty or equal to 0")
}
if frq.Name == "" {
return errors.New("field Name can not be empty")
}
validator := validators.StringInSlice(frq.NetType, []string{"EXTNET", "VINS"})
if !validator {
return errors.New("field Name can be only EXTNET or VINS")
}
validator = validators.StringInSlice(frq.ClientType, []string{"compute", "node"})
if !validator {
return errors.New("field Name can be only compute or node")
}
return nil
}
// Create method will create a new FLIPGorup in the specified Account
func (f FLIPGroup) Create(ctx context.Context, req CreateRequest) (*RecordFLIPGroup, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return nil, err
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/flipgroup/create"

View File

@@ -2,31 +2,26 @@ package flipgroup
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for delete FLIPGroup
type DeleteRequest struct {
// FLIPGroup ID
// Required: true
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId"`
}
func (frq DeleteRequest) validate() error {
if frq.FLIPGroupID == 0 {
return errors.New("field FLIPGroupID can not be empty or equal to 0")
}
return nil
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId" validate:"required"`
}
// Delete method wil delete Floating IP group
func (f FLIPGroup) Delete(ctx context.Context, req DeleteRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/flipgroup/delete"

View File

@@ -2,39 +2,34 @@ package flipgroup
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for edit FLIPGroup
type EditRequest struct {
// FLIPGroup ID
// Required: true
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId"`
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId" validate:"required"`
// FLIPGroup name
// Required: true
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// FLIPGroup description
// Required: true
// Required: false
Description string `url:"desc,omitempty" json:"desc,omitempty"`
}
func (frq EditRequest) validate() error {
if frq.FLIPGroupID == 0 {
return errors.New("field FLIPGroupID can not be empty or equal to 0")
}
return nil
}
// Edit edits FLIPGroup fields
func (f FLIPGroup) Edit(ctx context.Context, req EditRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/flipgroup/edit"

View File

@@ -3,30 +3,25 @@ package flipgroup
import (
"context"
"encoding/json"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get information about FLIPGroup
type GetRequest struct {
// FLIPGroup ID
// Required: true
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId"`
}
func (frq GetRequest) validate() error {
if frq.FLIPGroupID == 0 {
return errors.New("field FLIPGroupID can not be empty or equal to 0")
}
return nil
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId" validate:"required"`
}
// Get gets details of the specified Floating IP group
func (f FLIPGroup) Get(ctx context.Context, req GetRequest) (*ItemFLIPGroup, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return nil, err
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/flipgroup/get"

View File

@@ -24,7 +24,7 @@ type CreateRequest struct {
// Boot type of image bios or UEFI
// Required: true
BootType string `url:"boottype" json:"boottype" validate:"required,bootType"`
BootType string `url:"boottype" json:"boottype" validate:"required,imageBootType"`
// Image type
// Should be:

View File

@@ -3,29 +3,25 @@ package k8ci
import (
"context"
"encoding/json"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get information about K8CI
type GetRequest struct {
// ID of the K8 catalog item to get
// Required: true
K8CIID uint64 `url:"k8ciId" json:"k8ciId"`
}
func (krq GetRequest) validate() error {
if krq.K8CIID == 0 {
return errors.New("field K8CIID can not be empty or equal to 0")
}
return nil
K8CIID uint64 `url:"k8ciId" json:"k8ciId" validate:"required"`
}
// Get gets details of the specified K8 catalog item
func (k K8CI) Get(ctx context.Context, req GetRequest) (*RecordK8CI, error) {
if err := req.validate(); err != nil {
return nil, err
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8ci/get"

View File

@@ -23,6 +23,9 @@ type RecordK8CI struct {
// Name
Name string `json:"name"`
// Network plugins
NetworkPlugins []string `json:"networkPlugins"`
// Version
Version string `json:"version"`
}

View File

@@ -2,28 +2,34 @@ package k8s
import (
"context"
"errors"
"net/http"
"strings"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for create kubernetes cluster
type CreateRequest struct {
// Name of Kubernetes cluster
// Required: true
Name string `url:"name" json:"name"`
Name string `url:"name" json:"name" validate:"required"`
// Resource Group ID for cluster placement
// Required: true
RGID uint64 `url:"rgId" json:"rgId"`
RGID uint64 `url:"rgId" json:"rgId" validate:"required"`
// ID of Kubernetes catalog item (k8sci) for cluster
// Required: true
K8SCIID uint64 `url:"k8ciId" json:"k8ciId"`
K8SCIID uint64 `url:"k8ciId" json:"k8ciId" validate:"required"`
// Name for first worker group created with cluster
// Required: true
WorkerGroupName string `url:"workerGroupName" json:"workerGroupName"`
WorkerGroupName string `url:"workerGroupName" json:"workerGroupName" validate:"required"`
// Network plugin
// Must be one of these values: flannel, weawenet, calico
// Required: true
NetworkPlugin string `url:"networkPlugin" json:"networkPlugin" validate:"required,networkPlugin"`
// ID of SEP to create boot disks for master nodes. Uses images SEP ID if not set
// Required: false
@@ -102,28 +108,13 @@ type CreateRequest struct {
Description string `url:"desc,omitempty" json:"desc,omitempty"`
}
func (krq CreateRequest) validate() error {
if krq.Name == "" {
return errors.New("validation-error: field Name can not be empty")
}
if krq.RGID == 0 {
return errors.New("validation-error: field RGID can not be empty or equal to 0")
}
if krq.K8SCIID == 0 {
return errors.New("validation-error: field K8SCIID can not be empty or equal to 0")
}
if krq.WorkerGroupName == "" {
return errors.New("validation-error: field WorkerGroupName can not be empty")
}
return nil
}
// Create creates a new Kubernetes cluster in the specified Resource Group
func (k8s K8S) Create(ctx context.Context, req CreateRequest) (string, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return "", err
for _, validationError := range validators.GetErrors(err) {
return "", validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/create"

View File

@@ -2,36 +2,31 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for delete kubernetes cluster
type DeleteRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// True if cluster is destroyed permanently.
// Otherwise it can be restored from Recycle Bin
// Required: true
Permanently bool `url:"permanently" json:"permanently"`
}
func (krq DeleteRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
return nil
Permanently bool `url:"permanently" json:"permanently" validate:"required"`
}
// Delete deletes kubernetes cluster
func (k8s K8S) Delete(ctx context.Context, req DeleteRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/delete"

View File

@@ -2,45 +2,34 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for delete master from group
type DeleteMasterFromGroupRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// ID of the masters compute group
// Required: true
MasterGroupID uint64 `url:"masterGroupId" json:"masterGroupId"`
MasterGroupID uint64 `url:"masterGroupId" json:"masterGroupId" validate:"required"`
// List of Compute IDs of master nodes to delete
// Required: true
MasterIDs []string `url:"masterIds" json:"masterIds"`
}
func (krq DeleteMasterFromGroupRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.MasterGroupID == 0 {
return errors.New("validation-error: field MasterGroupID can not be empty or equal to 0")
}
if len(krq.MasterIDs) == 0 {
return errors.New("validation-error: field MasterIDs can not be empty")
}
return nil
MasterIDs []string `url:"masterIds" json:"masterIds" validate:"min=1"`
}
// DeleteMasterFromGroup deletes compute from masters group in selected Kubernetes cluster
func (k8s K8S) DeleteMasterFromGroup(ctx context.Context, req DeleteMasterFromGroupRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/deleteMasterFromGroup"

View File

@@ -2,45 +2,34 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for delete worker from group
type DeleteWorkerFromGroupRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// ID of the workers compute group
// Required: true
WorkersGroupID uint64 `url:"workersGroupId" json:"workersGroupId"`
WorkersGroupID uint64 `url:"workersGroupId" json:"workersGroupId" validate:"required"`
// Compute ID of worker node to delete
// Required: true
WorkerID uint64 `url:"workerId" json:"workerId"`
}
func (krq DeleteWorkerFromGroupRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.WorkersGroupID == 0 {
return errors.New("validation-error: field WorkersGroupID can not be empty or equal to 0")
}
if krq.WorkerID == 0 {
return errors.New("validation-error: field WorkerID can not be empty or equal to 0")
}
return nil
WorkerID uint64 `url:"workerId" json:"workerId" validate:"required"`
}
// DeleteWorkerFromGroup deletes worker compute from workers group in selected Kubernetes cluster
func (k8s K8S) DeleteWorkerFromGroup(ctx context.Context, req DeleteWorkerFromGroupRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/deleteWorkerFromGroup"

View File

@@ -2,31 +2,26 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for disable/enable kubernetes cluster
type DisabelEnableRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
}
func (krq DisabelEnableRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
return nil
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
}
// Disable disables kubernetes cluster by ID
func (k8s K8S) Disable(ctx context.Context, req DisabelEnableRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/disable"
@@ -46,9 +41,11 @@ func (k8s K8S) Disable(ctx context.Context, req DisabelEnableRequest) (bool, err
// Enable enables kubernetes cluster by ID
func (k8s K8S) Enable(ctx context.Context, req DisabelEnableRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/enable"

View File

@@ -3,42 +3,34 @@ package k8s
import (
"context"
"encoding/json"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get information about group of kubernetes cluster
type FindGroupByLabelRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// List of labels to search
// Required: true
Labels []string `url:"labels" json:"labels"`
Labels []string `url:"labels" json:"labels" validate:"min=1"`
// If true and more than one label provided, select only groups that have all provided labels.
// If false - groups that have at least one label
// Required: true
Strict bool `url:"strict" json:"strict"`
}
func (krq FindGroupByLabelRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if len(krq.Labels) == 0 {
return errors.New("validation-error: field Labels can not be empty")
}
return nil
// Required: false
Strict bool `url:"strict,omitempty" json:"strict,omitempty"`
}
// FindGroupByLabel find worker group information by one on more labels
func (k8s K8S) FindGroupByLabel(ctx context.Context, req FindGroupByLabelRequest) (ListK8SGroups, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return nil, err
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/findGroupByLabel"

View File

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

View File

@@ -2,30 +2,25 @@ package k8s
import (
"context"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get configuration of kubernetes cluster
type GetConfigRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
}
func (krq GetConfigRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
return nil
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
}
// GetConfig gets configuration data to access Kubernetes cluster
func (k8s K8S) GetConfig(ctx context.Context, req GetConfigRequest) (string, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return "", err
for _, validationError := range validators.GetErrors(err) {
return "", validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/getConfig"

View File

@@ -2,37 +2,29 @@ package k8s
import (
"context"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get node annotations
type GetNodeAnnotationsRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// Node ID
// Required: true
NodeID uint64 `url:"nodeId" json:"nodeId"`
}
func (krq GetNodeAnnotationsRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.NodeID == 0 {
return errors.New("validation-error: field NodeID can not be empty or equal to 0")
}
return nil
NodeID uint64 `url:"nodeId" json:"nodeId" validate:"required"`
}
// GetNodeAnnotations gets kubernetes cluster worker node annotations
func (k8s K8S) GetNodeAnnotations(ctx context.Context, req GetNodeAnnotationsRequest) (string, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return "", err
for _, validationError := range validators.GetErrors(err) {
return "", validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/getNodeAnnotations"

View File

@@ -2,37 +2,29 @@ package k8s
import (
"context"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get node labels
type GetNodeLabelsRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// Node ID
// Required: false
NodeID uint64 `url:"nodeId" json:"nodeId"`
}
func (krq GetNodeLabelsRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.NodeID == 0 {
return errors.New("validation-error: field NodeID can not be empty or equal to 0")
}
return nil
// Required: true
NodeID uint64 `url:"nodeId" json:"nodeId" validate:"required"`
}
// GetNodeLabels gets kubernetes cluster worker node labels
func (k8s K8S) GetNodeLabels(ctx context.Context, req GetNodeLabelsRequest) (string, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return "", err
for _, validationError := range validators.GetErrors(err) {
return "", validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/getNodeLabels"

View File

@@ -2,37 +2,29 @@ package k8s
import (
"context"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get node taints
type GetNodeTaintsRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// Node ID
// Required: false
NodeID uint64 `url:"nodeId" json:"nodeId"`
}
func (krq GetNodeTaintsRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.NodeID == 0 {
return errors.New("validation-error: field NodeID can not be empty or equal to 0")
}
return nil
// Required: true
NodeID uint64 `url:"nodeId" json:"nodeId" validate:"required"`
}
// GetNodeTaints gets kubernetes cluster worker node taints
func (k8s K8S) GetNodeTaints(ctx context.Context, req GetNodeTaintsRequest) (string, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return "", err
for _, validationError := range validators.GetErrors(err) {
return "", validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/getNodeTaints"

View File

@@ -101,6 +101,9 @@ type RecordK8S struct {
// Name
Name string `json:"name"`
// Network plugin
NetworkPlugin string `json:"networkPlugin"`
// Resource group ID
RGID uint64 `json:"rgId"`
@@ -246,6 +249,9 @@ type ItemK8SCluster struct {
// Name
Name string `json:"name"`
// Network plugin
NetworkPlugin string `json:"networkPlugin"`
// Resource group ID
RGID uint64 `json:"rgId"`

View File

@@ -2,31 +2,26 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for restore kubernetes cluster
type RestoreRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
}
func (krq RestoreRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
return nil
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
}
// Restore restore kubernetes cluster from Recycle Bin
func (k8s K8S) Restore(ctx context.Context, req RestoreRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/restore"

View File

@@ -2,31 +2,26 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for start kubernetes cluster
type StartRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
}
func (krq StartRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
return nil
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
}
// Start starts kubernetes cluster by ID
func (k8s K8S) Start(ctx context.Context, req StartRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/start"

View File

@@ -2,31 +2,26 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for stop kubernetes cluster
type StopRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
}
func (krq StopRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
return nil
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
}
// Stop stops kubernetes cluster by ID
func (k8s K8S) Stop(ctx context.Context, req StopRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/stop"

View File

@@ -2,16 +2,17 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for update kubernetes cluster
type UpdateRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// New name to set.
// If empty string is passed, name is not updated
@@ -24,19 +25,13 @@ type UpdateRequest struct {
Description string `url:"desc,omitempty" json:"desc,omitempty"`
}
func (krq UpdateRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
return nil
}
// Update updates name or description of Kubernetes cluster
func (k8s K8S) Update(ctx context.Context, req UpdateRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/update"

View File

@@ -2,57 +2,47 @@ package k8s
import (
"context"
"errors"
"encoding/json"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for add worker to a kubernetes cluster
type WorkerAddRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// ID of the workers compute group
// Required: true
WorkersGroupID uint64 `url:"workersGroupId" json:"workersGroupId"`
WorkersGroupID uint64 `url:"workersGroupId" json:"workersGroupId" validate:"required"`
// How many worker nodes to add
// Required: true
Num uint64 `url:"num" json:"num"`
}
func (krq WorkerAddRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.WorkersGroupID == 0 {
return errors.New("validation-error: field WorkersGroupID can not be empty or equal to 0")
}
if krq.Num == 0 {
return errors.New("validation-error: field Num can not be empty or equal to 0")
}
return nil
Num uint64 `url:"num" json:"num" validate:"required"`
}
// WorkerAdd add worker nodes to a Kubernetes cluster
func (k8s K8S) WorkerAdd(ctx context.Context, req WorkerAddRequest) (bool, error) {
err := req.validate()
func (k8s K8S) WorkerAdd(ctx context.Context, req WorkerAddRequest) ([]uint64, error) {
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/workerAdd"
res, err := k8s.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
return nil, err
}
result, err := strconv.ParseBool(string(res))
result := make([]uint64, 0)
err = json.Unmarshal(res, &result)
if err != nil {
return false, err
return nil, err
}
return result, nil

View File

@@ -2,45 +2,34 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for hard reset kubernetes cluster
type WorkerResetRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// ID of the workers compute group
// Required: true
WorkersGroupID uint64 `url:"workersGroupId" json:"workersGroupId"`
WorkersGroupID uint64 `url:"workersGroupId" json:"workersGroupId" validate:"required"`
// Compute ID of worker node to reset
// Required: true
WorkerID uint64 `url:"workerId" json:"workerId"`
}
func (krq WorkerResetRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.WorkersGroupID == 0 {
return errors.New("validation-error: field WorkersGroupID can not be empty or equal to 0")
}
if krq.WorkerID == 0 {
return errors.New("validation-error: field WorkerID can not be empty or equal to 0")
}
return nil
WorkerID uint64 `url:"workerId" json:"workerId" validate:"required"`
}
// WorkerReset hard reset (compute start + stop) worker node of the Kubernetes cluster
func (k8s K8S) WorkerReset(ctx context.Context, req WorkerResetRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/workerReset"

View File

@@ -2,45 +2,34 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for restart worker node
type WorkerRestartRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// ID of the workers compute group
// Required: true
WorkersGroupID uint64 `url:"workersGroupId" json:"workersGroupId"`
WorkersGroupID uint64 `url:"workersGroupId" json:"workersGroupId" validate:"required"`
// Compute ID of worker node to restart
// Required: true
WorkerID uint64 `url:"workerId" json:"workerId"`
}
func (krq WorkerRestartRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.WorkersGroupID == 0 {
return errors.New("validation-error: field WorkersGroupID can not be empty or equal to 0")
}
if krq.WorkerID == 0 {
return errors.New("validation-error: field WorkerID can not be empty or equal to 0")
}
return nil
WorkerID uint64 `url:"workerId" json:"workerId" validate:"required"`
}
// WorkerRestart soft restart (reboot OS) worker node of the Kubernetes cluster
func (k8s K8S) WorkerRestart(ctx context.Context, req WorkerRestartRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/workerRestart"

View File

@@ -2,20 +2,21 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for add workers group
type WorkersGroupAddRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// Worker group name
// Required: true
Name string `url:"name" json:"name"`
Name string `url:"name" json:"name" validate:"required"`
// ID of SEP to create boot disks for default worker nodes group. Uses images SEP ID if not set
// Required: false
@@ -57,33 +58,25 @@ type WorkersGroupAddRequest struct {
WorkerDisk uint64 `url:"workerDisk,omitempty" json:"workerDisk,omitempty"`
}
func (krq WorkersGroupAddRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.Name == "" {
return errors.New("validation-error: field Name must be set")
}
return nil
}
// WorkersGroupAdd adds workers group to Kubernetes cluster
func (k8s K8S) WorkersGroupAdd(ctx context.Context, req WorkersGroupAddRequest) (bool, error) {
err := req.validate()
func (k8s K8S) WorkersGroupAdd(ctx context.Context, req WorkersGroupAddRequest) (uint64, error) {
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/workersGroupAdd"
res, err := k8s.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
return 0, err
}
result, err := strconv.ParseBool(string(res))
result, err := strconv.ParseUint(string(res), 10, 64)
if err != nil {
return false, err
return 0, err
}
return result, nil

View File

@@ -2,38 +2,30 @@ package k8s
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for delete workers group
type WorkersGroupDeleteRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// Worker group ID
// Required: true
WorkersGroupID uint64 `url:"workersGroupId" json:"workersGroupId"`
}
func (krq WorkersGroupDeleteRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.WorkersGroupID == 0 {
return errors.New("validation-error: field WorkersGroupID can not be empty or equal to 0")
}
return nil
WorkersGroupID uint64 `url:"workersGroupId" json:"workersGroupId" validate:"required"`
}
// WorkersGroupDelete deletes workers group from Kubernetes cluster
func (k8s K8S) WorkersGroupDelete(ctx context.Context, req WorkersGroupDeleteRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/workersGroupDelete"

View File

@@ -3,37 +3,29 @@ package k8s
import (
"context"
"encoding/json"
"errors"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get information about worker group
type WorkersGroupGetByNameRequest struct {
// Kubernetes cluster ID
// Required: true
K8SID uint64 `url:"k8sId" json:"k8sId"`
K8SID uint64 `url:"k8sId" json:"k8sId" validate:"required"`
// Worker group name
// Required: true
GroupName string `url:"groupName" json:"groupName"`
}
func (krq WorkersGroupGetByNameRequest) validate() error {
if krq.K8SID == 0 {
return errors.New("validation-error: field K8SID can not be empty or equal to 0")
}
if krq.GroupName == "" {
return errors.New("validation-error: field WorkersGroupID can not be empty")
}
return nil
GroupName string `url:"groupName" json:"groupName" validate:"required"`
}
// WorkersGroupGetByName gets worker group metadata by name
func (k8s K8S) WorkersGroupGetByName(ctx context.Context, req WorkersGroupGetByNameRequest) (*RecordK8SGroups, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return nil, err
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/k8s/workersGroupGetByName"

View File

@@ -2,34 +2,35 @@ package kvmppc
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for create KVM PowerPC VM
type CreateRequest struct {
// ID of the resource group, which will own this VM
// Required: true
RGID uint64 `url:"rgId" json:"rgId"`
RGID uint64 `url:"rgId" json:"rgId" validate:"required"`
// Name of this VM.
// Must be unique among all VMs (including those in DELETED state) in target resource group
// Required: true
Name string `url:"name" json:"name"`
Name string `url:"name" json:"name" validate:"required"`
// Number CPUs to allocate to this VM
// Required: true
CPU uint64 `url:"cpu" json:"cpu"`
CPU uint64 `url:"cpu" json:"cpu" validate:"required"`
// Volume of RAM in MB to allocate to this VM
// Required: true
RAM uint64 `url:"ram" json:"ram"`
RAM uint64 `url:"ram" json:"ram" validate:"required"`
// ID of the OS image to base this VM on;
// Could be boot disk image or CD-ROM image
// Required: true
ImageID uint64 `url:"imageId" json:"imageId"`
ImageID uint64 `url:"imageId" json:"imageId" validate:"required"`
// Size of the boot disk in GB
// Required: false
@@ -50,7 +51,7 @@ type CreateRequest struct {
// - EXTNET
// - NONE
// Required: false
NetType string `url:"netType,omitempty" json:"netType,omitempty"`
NetType string `url:"netType,omitempty" json:"netType,omitempty" validate:"omitempty,kvmNetType"`
// Network ID for connect to,
// for EXTNET - external network ID,
@@ -84,31 +85,13 @@ type CreateRequest struct {
IPAType string `url:"ipaType,omitempty" json:"ipaType,omitempty"`
}
func (krq CreateRequest) validate() error {
if krq.RGID == 0 {
return errors.New("validation-error: field RGID can not be empty or equal to 0")
}
if krq.Name == "" {
return errors.New("validation-error: field Name can not be empty")
}
if krq.CPU == 0 {
return errors.New("validation-error: field CPU can not be empty or equal to 0")
}
if krq.RAM == 0 {
return errors.New("validation-error: field RAM can not be empty or equal to 0")
}
if krq.ImageID == 0 {
return errors.New("validation-error: field ImageID can not be empty or equal to 0")
}
return nil
}
// Create creates KVM PowerPC VM based on specified OS image
func (k KVMPPC) Create(ctx context.Context, req CreateRequest) (uint64, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return 0, err
for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
}
url := "/cloudapi/kvmppc/create"

View File

@@ -2,42 +2,43 @@ package kvmppc
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for create KVM PowerPC VM from scratch
type CreateBlankRequest struct {
// ID of the resource group, which will own this VM
// Required: true
RGID uint64 `url:"rgId" json:"rgId"`
RGID uint64 `url:"rgId" json:"rgId" validate:"required"`
// Name of this VM.
// Must be unique among all VMs (including those in DELETED state) in target resource group
// Required: true
Name string `url:"name" json:"name"`
Name string `url:"name" json:"name" validate:"required"`
// Number CPUs to allocate to this VM
// Required: true
CPU uint64 `url:"cpu" json:"cpu"`
CPU uint64 `url:"cpu" json:"cpu" validate:"required"`
// Volume of RAM in MB to allocate to this VM
// Required: true
RAM uint64 `url:"ram" json:"ram"`
RAM uint64 `url:"ram" json:"ram" validate:"required"`
// Size of the boot disk in GB
// Required: true
BootDisk uint64 `url:"bootDisk" json:"bootDisk"`
BootDisk uint64 `url:"bootDisk" json:"bootDisk" validate:"required"`
// ID of SEP to create boot disk on.
// Uses images SEP ID if not set
// Required: true
SEPID uint64 `url:"sepId" json:"sepId"`
SEPID uint64 `url:"sepId" json:"sepId" validate:"required"`
// Pool to use if SEP ID is set, can be also empty if needed to be chosen by system
// Required: true
Pool string `url:"pool" json:"pool"`
Pool string `url:"pool" json:"pool" validate:"required"`
// Network type
// Should be one of:
@@ -45,7 +46,7 @@ type CreateBlankRequest struct {
// - EXTNET
// - NONE
// Required: false
NetType string `url:"netType,omitempty" json:"netType,omitempty"`
NetType string `url:"netType,omitempty" json:"netType,omitempty" validate:"omitempty,kvmNetType"`
// Network ID for connect to,
// for EXTNET - external network ID,
@@ -63,37 +64,13 @@ type CreateBlankRequest struct {
Description string `url:"desc,omitempty" json:"desc,omitempty"`
}
func (krq CreateBlankRequest) validate() error {
if krq.RGID == 0 {
return errors.New("validation-error: field RGID can not be empty or equal to 0")
}
if krq.Name == "" {
return errors.New("validation-error: field Name can not be empty")
}
if krq.CPU == 0 {
return errors.New("validation-error: field CPU can not be empty or equal to 0")
}
if krq.RAM == 0 {
return errors.New("validation-error: field RAM can not be empty or equal to 0")
}
if krq.BootDisk == 0 {
return errors.New("validation-error: field BootDisk can not be empty or equal to 0")
}
if krq.SEPID == 0 {
return errors.New("validation-error: field SepID can not be empty or equal to 0")
}
if krq.Pool == "" {
return errors.New("validation-error: field Pool can not be empty")
}
return nil
}
// CreateBlank creates KVM PowerPC VM from scratch
func (k KVMPPC) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return 0, err
for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
}
url := "/cloudapi/kvmppc/createBlank"

View File

@@ -2,34 +2,35 @@ package kvmx86
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for create KVM x86 VM
type CreateRequest struct {
// ID of the resource group, which will own this VM
// Required: true
RGID uint64 `url:"rgId" json:"rgId"`
RGID uint64 `url:"rgId" json:"rgId" validate:"required"`
// Name of this VM.
// Must be unique among all VMs (including those in DELETED state) in target resource group
// Required: true
Name string `url:"name" json:"name"`
Name string `url:"name" json:"name" validate:"required"`
// Number CPUs to allocate to this VM
// Required: true
CPU uint64 `url:"cpu" json:"cpu"`
CPU uint64 `url:"cpu" json:"cpu" validate:"required"`
// Volume of RAM in MB to allocate to this VM
// Required: true
RAM uint64 `url:"ram" json:"ram"`
RAM uint64 `url:"ram" json:"ram" validate:"required"`
// ID of the OS image to base this VM on;
// Could be boot disk image or CD-ROM image
// Required: true
ImageID uint64 `url:"imageId" json:"imageId"`
ImageID uint64 `url:"imageId" json:"imageId" validate:"required"`
// Size of the boot disk in GB
// Required: false
@@ -50,7 +51,7 @@ type CreateRequest struct {
// - EXTNET
// - NONE
// Required: false
NetType string `url:"netType,omitempty" json:"netType,omitempty"`
NetType string `url:"netType,omitempty" json:"netType,omitempty" validate:"omitempty,kvmNetType"`
// Network ID for connect to,
// for EXTNET - external network ID,
@@ -84,31 +85,13 @@ type CreateRequest struct {
IPAType string `url:"ipaType,omitempty" json:"ipaType,omitempty"`
}
func (krq CreateRequest) validate() error {
if krq.RGID == 0 {
return errors.New("validation-error: field RGID can not be empty or equal to 0")
}
if krq.Name == "" {
return errors.New("validation-error: field Name can not be empty")
}
if krq.CPU == 0 {
return errors.New("validation-error: field CPU can not be empty or equal to 0")
}
if krq.RAM == 0 {
return errors.New("validation-error: field RAM can not be empty or equal to 0")
}
if krq.ImageID == 0 {
return errors.New("validation-error: field ImageID can not be empty or equal to 0")
}
return nil
}
// Create creates KVM x86 VM based on specified OS image
func (k KVMX86) Create(ctx context.Context, req CreateRequest) (uint64, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return 0, err
for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
}
url := "/cloudapi/kvmx86/create"

View File

@@ -2,42 +2,43 @@ package kvmx86
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for create KVM x86 VM from scratch
type CreateBlankRequest struct {
// ID of the resource group, which will own this VM
// Required: true
RGID uint64 `url:"rgId" json:"rgId"`
RGID uint64 `url:"rgId" json:"rgId" validate:"required"`
// Name of this VM.
// Must be unique among all VMs (including those in DELETED state) in target resource group
// Required: true
Name string `url:"name" json:"name"`
Name string `url:"name" json:"name" validate:"required"`
// Number CPUs to allocate to this VM
// Required: true
CPU uint64 `url:"cpu" json:"cpu"`
CPU uint64 `url:"cpu" json:"cpu" validate:"required"`
// Volume of RAM in MB to allocate to this VM
// Required: true
RAM uint64 `url:"ram" json:"ram"`
RAM uint64 `url:"ram" json:"ram" validate:"required"`
// Size of the boot disk in GB
// Required: true
BootDisk uint64 `url:"bootDisk" json:"bootDisk"`
BootDisk uint64 `url:"bootDisk" json:"bootDisk" validate:"required"`
// ID of SEP to create boot disk on.
// Uses images SEP ID if not set
// Required: true
SEPID uint64 `url:"sepId" json:"sepId"`
SEPID uint64 `url:"sepId" json:"sepId" validate:"required"`
// Pool to use if sepId is set, can be also empty if needed to be chosen by system
// Required: true
Pool string `url:"pool" json:"pool"`
Pool string `url:"pool" json:"pool" validate:"required"`
// Network type
// Should be one of:
@@ -45,7 +46,7 @@ type CreateBlankRequest struct {
// - EXTNET
// - NONE
// Required: false
NetType string `url:"netType,omitempty" json:"netType,omitempty"`
NetType string `url:"netType,omitempty" json:"netType,omitempty" validate:"omitempty,kvmNetType"`
// Network ID for connect to,
// for EXTNET - external network ID,
@@ -63,37 +64,13 @@ type CreateBlankRequest struct {
Description string `url:"desc,omitempty" json:"desc,omitempty"`
}
func (krq CreateBlankRequest) validate() error {
if krq.RGID == 0 {
return errors.New("validation-error: field RGID can not be empty or equal to 0")
}
if krq.Name == "" {
return errors.New("validation-error: field Name can not be empty")
}
if krq.CPU == 0 {
return errors.New("validation-error: field CPU can not be empty or equal to 0")
}
if krq.RAM == 0 {
return errors.New("validation-error: field RAM can not be empty or equal to 0")
}
if krq.BootDisk == 0 {
return errors.New("validation-error: field BootDisk can not be empty or equal to 0")
}
if krq.SEPID == 0 {
return errors.New("validation-error: field SepID can not be empty or equal to 0")
}
if krq.Pool == "" {
return errors.New("validation-error: field Pool can not be empty")
}
return nil
}
// CreateBlank creates KVM x86 VM from scratch
func (k KVMX86) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return 0, err
for _, validationError := range validators.GetErrors(err) {
return 0, validators.ValidationError(validationError)
}
}
url := "/cloudapi/kvmx86/createBlank"

View File

@@ -2,20 +2,21 @@ package lb
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for create backend
type BackendCreateRequest struct {
// ID of the load balancer instance to backendCreate
// Required: true
LBID uint64 `url:"lbId" json:"lbId"`
LBID uint64 `url:"lbId" json:"lbId" validate:"required"`
// Must be unique among all backends of this load balancer - name of the new backend to create
// Required: true
BackendName string `url:"backendName" json:"backendName"`
BackendName string `url:"backendName" json:"backendName" validate:"required"`
// Algorithm
// Should be one of:
@@ -23,7 +24,7 @@ type BackendCreateRequest struct {
// - static-rr
// - leastconn
// Required: false
Algorithm string `url:"algorithm,omitempty" json:"algorithm,omitempty"`
Algorithm string `url:"algorithm,omitempty" json:"algorithm,omitempty" validate:"omitempty,lbAlgorithm"`
// Interval in milliseconds between two consecutive availability
// checks of the server that is considered available
@@ -66,22 +67,13 @@ type BackendCreateRequest struct {
Weight uint64 `url:"weight,omitempty" json:"weight,omitempty"`
}
func (lbrq BackendCreateRequest) validate() error {
if lbrq.LBID == 0 {
return errors.New("validation-error: field LBID can not be empty or equal to 0")
}
if lbrq.BackendName == "" {
return errors.New("validation-error: field BackendName can not be empty")
}
return nil
}
// BackendCreate creates new backend on the specified load balancer
func (l LB) BackendCreate(ctx context.Context, req BackendCreateRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/backendCreate"

View File

@@ -2,39 +2,31 @@ package lb
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for delete backend
type BackendDeleteRequest struct {
// ID of the load balancer instance to BackendDelete
// Required: true
LBID uint64 `url:"lbId" json:"lbId"`
LBID uint64 `url:"lbId" json:"lbId" validate:"required"`
// Cannot be emtpy string - name of the backend to delete
// Required: true
BackendName string `url:"backendName" json:"backendName"`
}
func (lbrq BackendDeleteRequest) validate() error {
if lbrq.LBID == 0 {
return errors.New("validation-error: field LBID can not be empty or equal to 0")
}
if lbrq.BackendName == "" {
return errors.New("validation-error: field BackendName can not be empty")
}
return nil
BackendName string `url:"backendName" json:"backendName" validate:"required"`
}
// BackendDelete deletes backend from the specified load balancer.
// Warning: you cannot undo this action!
func (l LB) BackendDelete(ctx context.Context, req BackendDeleteRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/backendDelete"

View File

@@ -2,32 +2,33 @@ package lb
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for add server definition to the backend
type BackendServerAddRequest struct {
// ID of the load balancer instance to BackendServerAdd
// Required: true
LBID uint64 `url:"lbId" json:"lbId"`
LBID uint64 `url:"lbId" json:"lbId" validate:"required"`
// Must match one of the existing backens - name of the backend to add servers to
// Required: true
BackendName string `url:"backendName" json:"backendName"`
BackendName string `url:"backendName" json:"backendName" validate:"required"`
// Must be unique among all servers defined for this backend - name of the server definition to add
// Required: true
ServerName string `url:"serverName" json:"serverName"`
ServerName string `url:"serverName" json:"serverName" validate:"required"`
// IP address of the server
// Required: true
Address string `url:"address" json:"address"`
Address string `url:"address" json:"address" validate:"required"`
// Port number on the server
// Required: true
Port uint64 `url:"port" json:"port"`
Port uint64 `url:"port" json:"port" validate:"required"`
// Set to disabled if this server should be used regardless of its state
// Required: false
@@ -71,31 +72,13 @@ type BackendServerAddRequest struct {
Weight uint64 `url:"weight,omitempty" json:"weight,omitempty"`
}
func (lbrq BackendServerAddRequest) validate() error {
if lbrq.LBID == 0 {
return errors.New("validation-error: field LBID can not be empty or equal to 0")
}
if lbrq.BackendName == "" {
return errors.New("validation-error: field BackendName can not be empty")
}
if lbrq.ServerName == "" {
return errors.New("validation-error: field ServerName can not be empty")
}
if lbrq.Address == "" {
return errors.New("validation-error: field Address can not be empty")
}
if lbrq.Port == 0 {
return errors.New("validation-error: field Port can not be empty or equal to 0")
}
return nil
}
// BackendServerAdd adds server definition to the backend on the specified load balancer
func (l LB) BackendServerAdd(ctx context.Context, req BackendServerAddRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/backendServerAdd"

View File

@@ -2,46 +2,35 @@ package lb
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for delete server definition
type BackendServerDeleteRequest struct {
// ID of the load balancer instance to BackendServerDelete
// Required: true
LBID uint64 `url:"lbId" json:"lbId"`
LBID uint64 `url:"lbId" json:"lbId" validate:"required"`
// Must match one of the existing backens - name of the backend to add servers to
// Required: true
BackendName string `url:"backendName" json:"backendName"`
BackendName string `url:"backendName" json:"backendName" validate:"required"`
// Must be unique among all servers defined for this backend - name of the server definition to add
// Required: true
ServerName string `url:"serverName" json:"serverName"`
}
func (lbrq BackendServerDeleteRequest) validate() error {
if lbrq.LBID == 0 {
return errors.New("validation-error: field LBID can not be empty or equal to 0")
}
if lbrq.BackendName == "" {
return errors.New("validation-error: field BackendName can not be empty")
}
if lbrq.ServerName == "" {
return errors.New("validation-error: field ServerName can not be empty")
}
return nil
ServerName string `url:"serverName" json:"serverName" validate:"required"`
}
// BackendServerDelete deletes server definition from the backend on the specified load balancer.
// Warning: you cannot undo this action!
func (l LB) BackendServerDelete(ctx context.Context, req BackendServerDeleteRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/backendServerDelete"

View File

@@ -2,32 +2,33 @@ package lb
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for update server
type BackendServerUpdateRequest struct {
// ID of the load balancer instance to BackendServerAdd
// Required: true
LBID uint64 `url:"lbId" json:"lbId"`
LBID uint64 `url:"lbId" json:"lbId" validate:"required"`
// Must match one of the existing backens - name of the backend to add servers to
// Required: true
BackendName string `url:"backendName" json:"backendName"`
BackendName string `url:"backendName" json:"backendName" validate:"required"`
// Must be unique among all servers defined for this backend - name of the server definition to add
// Required: true
ServerName string `url:"serverName" json:"serverName"`
ServerName string `url:"serverName" json:"serverName" validate:"required"`
// IP address of the server
// Required: true
Address string `url:"address" json:"address"`
Address string `url:"address" json:"address" validate:"required"`
// Port number on the server
// Required: true
Port uint64 `url:"port" json:"port"`
Port uint64 `url:"port" json:"port" validate:"required"`
// Set to disabled if this server should be used regardless of its state
// Required: false
@@ -71,31 +72,13 @@ type BackendServerUpdateRequest struct {
Weight uint64 `url:"weight,omitempty" json:"weight,omitempty"`
}
func (lbrq BackendServerUpdateRequest) validate() error {
if lbrq.LBID == 0 {
return errors.New("validation-error: field LBID can not be empty or equal to 0")
}
if lbrq.BackendName == "" {
return errors.New("validation-error: field BackendName can not be empty")
}
if lbrq.ServerName == "" {
return errors.New("validation-error: field ServerName can not be empty")
}
if lbrq.Address == "" {
return errors.New("validation-error: field Address can not be empty")
}
if lbrq.Port == 0 {
return errors.New("validation-error: field Port can not be empty or equal to 0")
}
return nil
}
// BackendServerUpdate updates server definition on the backend of load balancer
func (l LB) BackendServerUpdate(ctx context.Context, req BackendServerUpdateRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/backendServerUpdate"

View File

@@ -2,20 +2,21 @@ package lb
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for update backend
type BackendUpdateRequest struct {
// ID of the load balancer instance to backendCreate
// Required: true
LBID uint64 `url:"lbId" json:"lbId"`
LBID uint64 `url:"lbId" json:"lbId" validate:"required"`
// Must be unique among all backends of this load balancer - name of the new backend to create
// Required: true
BackendName string `url:"backendName" json:"backendName"`
BackendName string `url:"backendName" json:"backendName" validate:"required"`
// Algorithm
// Should be one of:
@@ -23,7 +24,7 @@ type BackendUpdateRequest struct {
// - static-rr
// - leastconn
// Required: false
Algorithm string `url:"algorithm,omitempty" json:"algorithm,omitempty"`
Algorithm string `url:"algorithm,omitempty" json:"algorithm,omitempty" validate:"omitempty,lbAlgorithm"`
// Interval in milliseconds between two consecutive availability
// checks of the server that is considered available
@@ -66,22 +67,13 @@ type BackendUpdateRequest struct {
Weight uint64 `url:"weight,omitempty" json:"weight,omitempty"`
}
func (lbrq BackendUpdateRequest) validate() error {
if lbrq.LBID == 0 {
return errors.New("validation-error: field LBID can not be empty or equal to 0")
}
if lbrq.BackendName == "" {
return errors.New("validation-error: field BackendName can not be empty")
}
return nil
}
// BackendUpdate updates existing backend on the specified load balancer. Note that backend name cannot be changed
func (l LB) BackendUpdate(ctx context.Context, req BackendUpdateRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/backendUpdate"

View File

@@ -2,32 +2,27 @@ package lb
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for reset config
type ConfigResetRequest struct {
// ID of the load balancer instance to ConfigReset
// Required: true
LBID uint64 `url:"lbId" json:"lbId"`
}
func (lbrq ConfigResetRequest) validate() error {
if lbrq.LBID == 0 {
return errors.New("validation-error: field LBID can not be empty or equal to 0")
}
return nil
LBID uint64 `url:"lbId" json:"lbId" validate:"required"`
}
// ConfigReset reset current software configuration of the specified load balancer.
// Warning: this action cannot be undone!
func (l LB) ConfigReset(ctx context.Context, req ConfigResetRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/configReset"

View File

@@ -2,61 +2,47 @@ package lb
import (
"context"
"errors"
"net/http"
"strings"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for create load balancer
type CreateRequest struct {
// ID of the resource group where this load balancer instance will be located
// Required: true
RGID uint64 `url:"rgId" json:"rgId"`
RGID uint64 `url:"rgId" json:"rgId" validate:"required"`
// Name of the load balancer.
// Must be unique among all load balancers in this Resource Group
// Required: true
Name string `url:"name" json:"name"`
Name string `url:"name" json:"name" validate:"required"`
// External network to connect this load balancer to
// Required: true
ExtNetID uint64 `url:"extnetId" json:"extnetId"`
ExtNetID uint64 `url:"extnetId" json:"extnetId" validate:"required"`
// Internal network (VINS) to connect this load balancer to
// Required: true
VINSID uint64 `url:"vinsId" json:"vinsId"`
VINSID uint64 `url:"vinsId" json:"vinsId" validate:"required"`
// Start now Load balancer
// Required: false
Start bool `url:"start" json:"start"`
// Required: true
Start bool `url:"start" json:"start" validate:"required"`
// Text description of this load balancer
// Required: false
Description string `url:"desc,omitempty" json:"desc,omitempty"`
}
func (lbrq CreateRequest) validate() error {
if lbrq.RGID == 0 {
return errors.New("validation-error: field RGID can not be empty or equal to 0")
}
if lbrq.Name == "" {
return errors.New("validation-error: field Name can not be empty")
}
if lbrq.ExtNetID == 0 {
return errors.New("validation-error: field ExtNetID can not be empty or equal to 0")
}
if lbrq.VINSID == 0 {
return errors.New("validation-error: field VINSID can not be empty or equal to 0")
}
return nil
}
// Create method will create a new load balancer instance
func (l LB) Create(ctx context.Context, req CreateRequest) (string, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return "", err
for _, validationError := range validators.GetErrors(err) {
return "", validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/create"

View File

@@ -2,35 +2,30 @@ package lb
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for delete load balancer
type DeleteRequest struct {
// ID of the load balancer instance to delete
// Required: true
LBID uint64 `url:"lbId" json:"lbId"`
LBID uint64 `url:"lbId" json:"lbId" validate:"required"`
// Set to true to delete load balancer immediately bypassing recycle bin
// Required: false
Permanently bool `url:"permanently,omitempty" json:"permanently,omitempty"`
}
func (lbrq DeleteRequest) validate() error {
if lbrq.LBID == 0 {
return errors.New("validation-error: field LBID can not be empty or equal to 0")
}
return nil
}
// Delete deletes specified load balancer
func (l LB) Delete(ctx context.Context, req DeleteRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/delete"

View File

@@ -2,31 +2,26 @@ package lb
import (
"context"
"errors"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for disable/enable load balancer
type DisableEnableRequest struct {
// ID of the load balancer instance to disable/enable
// Required: true
LBID uint64 `url:"lbId" json:"lbId"`
}
func (lbrq DisableEnableRequest) validate() error {
if lbrq.LBID == 0 {
return errors.New("validation-error: field LBID can not be empty or equal to 0")
}
return nil
LBID uint64 `url:"lbId" json:"lbId" validate:"required"`
}
// Disable disables specified load balancer instance
func (l LB) Disable(ctx context.Context, req DisableEnableRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/disable"
@@ -46,9 +41,11 @@ func (l LB) Disable(ctx context.Context, req DisableEnableRequest) (bool, error)
// Enable enables specified load balancer instance
func (l LB) Enable(ctx context.Context, req DisableEnableRequest) (bool, error) {
err := req.validate()
err := validators.ValidateRequest(req)
if err != nil {
return false, err
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/lb/enable"

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