# Dynamix SDK

Dynamix SDK - это библиотека, написанная на языке GO, позволяющая взаимодействовать с API облачной платформы **Dynamix**. Библиотека содержит в себе структуры и методы, необходимые для отправки запросов. Dynamix SDK имеет встроенный http-клиент и поддерживает разные способы авторизации на платформе. Библиотека так же содержит в себе модели ответов от платформы.

## Версии

    - Версия 9.0.х Dynamix-SDK соответствует 4.1.0 версии платформы
    - Версия 10.0.х Dynamix-SDK соответствует 4.2.0 версии платформы
    - Версия 11.0.х Dynamix-SDK соответствует 4.3.0 версии платформы
    - Версия 12.x.х Dynamix-SDK соответствует 4.4.0 версии платформы
    - Версия 13.x.х Dynamix-SDK соответствует 4.5.0 версии платформы

## Оглавление

- [Dynamix SDK](#decort-sdk)
  - [Версии](#версии)
  - [Оглавление](#оглавление)
  - [Установка](#установка)
  - [Список API](#список-api)
    - [Cloudapi](#cloudapi)
    - [Cloudbroker](#cloudbroker)
    - [SDN](#sdn)
  - [Работа с библиотекой](#работа-с-библиотекой)
    - [Настройка конфигурации клиента](#настройка-конфигурации-клиента)
      - [Пример конфигурации клиента](#пример-конфигурации-клиента)
      - [Парсинг конфигурации из файла](#парсинг-конфигурации-из-файла)
      - [Пример JSON конфигурации](#пример-json-конфигурации)
      - [Пример YAML конфигурации](#пример-yaml-конфигурации)
    - [Создание клиента](#создание-клиента)
    - [Пример](#пример)
    - [Создание структуры запроса](#создание-структуры-запроса)
      - [Пример комментариев структуры](#пример-комментариев-структуры)
      - [Пример создания запроса для развертывания виртуальной машины:](#пример-создания-запроса-для-развертывания-виртуальной-машины)
    - [Выполнение запроса](#выполнение-запроса)
      - [Пример выполнения запроса](#пример-выполнения-запроса)
      - [Пример выполнения GetRaw и ListRaw запросов](#пример-выполнения-getraw-и-listraw-запросов)
    - [Фильтрация](#фильтрация)
      - [Использование на примере `compute.FilterByK8SID`:](#использование-на-примере-computefilterbyk8sid)
    - [Сортировка](#сортировка)
    - [Сериализация](#сериализация)
      - [Комплексный пример](#комплексный-пример)
    - [Получение списка уникальных идентификаторов ID объекта](#получение-списка-уникальных-идентификаторов-id-объекта)
    - [Методы поля Result для группы tasks](#методы-поля-result-для-группы-tasks)
  - [Работа с legacy клиентом](#работа-с-legacy-клиентом)
    - [Настройка конфигурации legacy клиента](#настройка-конфигурации-legacy-клиента)
      - [Пример конфигурации legacy клиента](#пример-конфигурации-legacy-клиента)
      - [Парсинг legacy конфигурации из файла](#парсинг-legacy-конфигурации-из-файла)
      - [Пример legacy JSON конфигурации](#пример-legacy-json-конфигурации)
      - [Пример legacy YAML конфигурации](#пример-legacy-yaml-конфигурации)
    - [Создание legacy клиента](#создание-legacy-клиента)
      - [Пример создания legacy клиента](#пример-создания-legacy-клиента)
      - [Пример выполнения запроса](#пример-выполнения-запроса-1)
  - [Работа с BVS клиентом](#работа-с-bvs-клиентом)
    - [Настройка параметров BVS в кабинете администратора](#настройка-параметров-bvs-в-кабинете-администратора)
    - [Настройка конфигурации BVS клиента](#настройка-конфигурации-bvs-клиента)
    - [Описание структуры token](#описание-структуры-token)
      - [Пример конфигурации BVS клиента](#пример-конфигурации-bvs-клиента)
      - [Парсинг BVS конфигурации из файла](#парсинг-bvs-конфигурации-из-файла)
      - [Парсинг BVS токена из файла](#парсинг-bvs-токена-из-файла)
      - [Пример BVS JSON конфигурации](#пример-bvs-json-конфигурации)
      - [Пример BVS YAML конфигурации](#пример-bvs-yaml-конфигурации)
    - [Создание BVS клиента](#создание-bvs-клиента)
      - [Пример создания BVS клиента](#пример-создания-bvs-клиента)
      - [Пример получения BVS токена](#пример-получения-bvs-токена)
      - [Пример обновления BVS токена](#пример-обновления-bvs-токена)
      - [Пример выполнения запроса](#пример-выполнения-запроса-2)
      - [Пример валидации запросов, имеющих в своей структуре поле RAM (или MasterRam/WorkerRAM)](#пример-валидации-запросов-имеющих-в-своей-структуре-поле-ram-или-masterramworkerram)
      - [Пример выполнения запроса](#пример-выполнения-запроса-3)
    - [Работа с универсальным клиентом](#работа-с-универсальным-клиентом)
      - [Настройка конфигурации универсального клиента](#настройка-конфигурации-универсального-клиента)
        - [Пример конфигурации универсального клиента](#пример-конфигурации-универсального-клиента)
        - [Парсинг универсальной конфигурации из файла](#парсинг-универсальной-конфигурации-из-файла)
      - [Создание универсального клиента](#создание-универсального-клиента)
        - [Пример создания универсального клиента](#пример-создания-универсального-клиента)
        - [Пример выполнения запроса](#пример-выполнения-запроса-4)
    - [Проверка соответствия версии платформы и версии dynamix](#проверка-соответствия-версии-платформы-и-версии-dynamix)
        - [Пример выполнения запроса](#пример-выполнения-запроса-5)
    - [Создание mock клиента](#создание-mock-клиента)
      - [Пример создания mock клиента](#пример-создания-mock-клиента)

## Установка

Выполните команду в терминале:

```bash
go get -u repository.basistech.ru/BASIS/dynamix-golang-sdk/v13
```

## Список API

Библиотека поддерживает две группы API платформы:

- `cloudapi` - пользовательская группа, которая позволяет воспользоваться всем стардартным функционалом платформы;
- `cloudbroker` - административная группа, которая позволяет воспользоваться всем стандартным функционалом платформы и расширенными возможностями, включающими в себя управление пользователями, ресурсами, платформами размещения ресурсов и т.д.
- `sdn` - группа для работы с SDN;

### Cloudapi

`Cloudapi` позволяет выполнять запросы к группе пользовательских конечных точек
Данная группа ручек позволяет выполнять следующие операции в платформе:

- `Account` - управление аккаунтами - внутренними учетными записями платформы, которые являются владельцами вычислительных ресурсов;
- `Audit` - получение информации о событиях системы;
- `BService` - управление группами виртуальных машин (computes);
- `Compute` - управление виртуальными машинами (индивидуально);
- `Disks` - управление виртуальными дисками;
- `DPDK` - управление виртуальными сетями DPDK;
- `ExtNet` - управление виртуальными сетями, отвечающими за внешний доступ;
- `FLIPgroup` - управление группами "плавающими" ip - адресами;
- `Image` - управление образами операционных систем;
- `K8CI` - получение информации о конвейере для создания кластера;
- `K8S` - управление кластерами kubernetes;
- `KVMx86` - создание виртуальной машины x86;
- `LB` - управление балансировщиками нагрузки;
- `Locations` - получение информации о grid площадки;
- `Prometheus` - получение статистики prometheus;
- `RG` - управление ресурсными группами аккаунта;
- `Security group` – управление группами безопасности;
- `SEP` - управление storage endpoint (sep);
- `Storage policy` – получение информации о политиках хранения;
- `Tasks` - получение информации о ходе выполнения асинхронных задач (например, создание кластера);
- `Trunk` - получение информации о транковых портах;
- `VFPool` - управление пулом виртуальных сетевых функций;
- `VINS` - управление виртуальными изолированными сетями;
- `Zone` - управление зонами.

### Cloudbroker

`Cloudbroker` позволяет выполнять запросы к группе пользовательских конечных точек
Данная группа ручек позволяет выполнять следующие операции в платформе:

- `Account` - управление аккаунтами - внутренними учетными записями платформы, которые являются владельцами вычислительных ресурсов;
- `Audit` - получение информации о событиях системы;
- `APIAccess` - управление доступом к API и его объектам;
- `Backup` - управление резервным копированием;
- `BService` - управление группами виртуальных машин (computes);
- `Compute` - управление виртуальными машинами (индивидуально);
- `Disks` - управление виртуальными дисками;
- `DPDK` - управление виртуальными сетями DPDK;
- `ExtNet` - управление виртуальными сетями, отвечающими за внешний доступ;
- `FLIPGroup` - управление группами с «плавающими» ip адресами;
- `Grid` - управление площадками;
- `Group` - управление группами пользователей;
- `Image` - управление образами операционных систем;
- `K8CI` - управление конвейром для создания кластера;
- `K8S` - управление кластерами kubernetes;
- `KVMx86` - создание виртуальной машины x86;
- `LB` - управление балансировщиками нагрузки;
- `Node` - управление нодами платформы;
- `PCIDevice` - управление устройствами;
- `Prometheus` - получение статистики prometheus;
- `Resmon` - получение статистики resource monitoring;
- `RG` - управление ресурсными группами аккаунта;
- `Security group` – управление группами безопасности;
- `SEP` - управление storage endpoint (sep);
- `Storage policy` – управление политиками хранения;
- `Tasks` - получение информации о ходе выполнения асинхронных задач (например, создание кластера);
- `Trunk` - управление транковыми портами;
- `User` - управление пользователями (индивидуально);
- `VGPU` - управление виртуальными графическими процессорами;
- `VFPool` - управление пулом виртуальных сетевых функций;
- `VINS` - управление виртуальными изолированными сетями.
- `Zone` - управление зонами.

### SDN

`SDN` позволяет выполнять запросы к группе пользовательских конечных точек
Данная группа ручек позволяет выполнять следующие операции в платформе:

- `Access group` - управление группами доступа;
- `Address pool` - управление пулами адресов;
- `DefaultSecurityPolicies` - управление политиками хранения по умолчанию;
- `ExtNet` - управление виртуальными сетями, отвечающими за внешний доступ;
- `FloatingIPs` - управление плавающими IP-адресами;
- `Logical ports` - управление логическими портами;
- `NetworkObjectGroups` - управление группами объектов сети;
- `Routers` - управление роутерами;
- `SecurityPolicies` - управление политиками хранения;
- `Segments` - управление сегментами;

## Работа с библиотекой

Алгоритм работы с библиотекой выглядит следующим образом:

1. Выполнение одного из действий:
- настройка конфигурации клиента;
- парсинг конфигурации из файла.
2. Создание клиента.
3. Создание структуры запроса.
4. Выполнение запроса.

### Настройка конфигурации клиента

Сначала, необходимо создать переменную конфигурации клиента. Конфигурация состоит как из обязательных, так и необязательных полей.
| Поле | Тип | Обязательный | Описание |
| --- | --- | --- | --- |
| AppID | string | Да | app_id ключа для выполнения запросов |
| AppSecret | string | Да | app_secret ключ для выполнения запроса |
| SSOURL | string | Да | URL адрес сервиса аутентификации и авторизации |
| DecortURL | string | Да | URL адрес платформы, с которой будет осуществляться взаимодействие |
| Retries | uint | Нет | Кол-во неудачных попыток выполнения запроса, по умолчанию - 5 |
| Timeout | config.Duration | Нет | Таймаут HTTP клиента, по умолчанию - без ограничений |
| SSLSkipVerify | bool | Нет | Пропуск проверки подлинности сертификата |
| Token | string | Нет | JWT токен |

##### Пример конфигурации клиента

```go
import (
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
)

func main(){
    // Настройка конфигурации
    cfg := config.Config{
        AppID:     "<APP_ID>",
        AppSecret: "<APP_SECRET>",
        SSOURL:    "https://sso.digitalenergy.online",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    cfg.SetTimeout(5 * time.Minute)
}
```

#### Парсинг конфигурации из файла

Также возможно создать переменную конфигурации из JSON или YAML файла, используя функцию `ParseConfigJSON` (или `ParseConfigYAML`) из пакета config.
<br>
*См. пример файлов конфигурации ниже и в директории `samples/`.*

```go
import (
	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
)

func main() {
	// Парсинг конфигурации из JSON-файла
	cfg, _ := config.ParseConfigJSON("<PATH>")
}
```

#### Пример JSON конфигурации

```json
{
    "appId": "<APP_ID>",
    "appSecret": "<APP_SECRET>",
    "ssoUrl": "https://sso.digitalenergy.online",
    "decortUrl": "https://mr4.digitalenergy.online",
    "retries": 5,
    "timeout": "5m",
    "sslSkipVerify": false
}
```

#### Пример YAML конфигурации

```yaml
appId: <APP_ID>
appSecret: <APP_SECRET>
ssoUrl: https://sso.digitalenergy.online
decortUrl: https://mr4.digitalenergy.online
retries: 5
timeout: 5m
sslSkipVerify: false
```

### Создание клиента

Создание клиента происходит с помощью функции-строителя `New` из основного пакета `decort-sdk`, для избежания проблем с именами, пакету можно присвоить алиас `decort`. Функция принимает конфигурацию, возвращает структуру `DecortClient`, с помощью которой можно взаимодействовать с платформой.

### Пример

```go
package main

import (
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
)

func main() {
    // Настройка конфигурации
    cfg := config.Config{
        AppID:     "<APPID>",
        AppSecret: "<APPSECRET>",
        SSOURL:    "https://sso.digitalenergy.online",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    cfg.SetTimeout(5 * time.Minute)

    // Создание клиента
    client := decort.New(cfg)
}
```

### Создание структуры запроса

Структуры запросов определены в пакетах:

- `pkg/cloudapi` - для `cloudapi`
- `pkg/cloudbroker` - для `cloudbroker`
- `pkg/sdn` - для `sdn`

В каждом пакете находятся пакеты групп API:

- **cloudapi**:
    - `pkg/cloudapi/account` - для `Account`
    - `pkg/cloudapi/audit` - для `Audit`
    - `pkg/cloudapi/bservice` - для `Basic Service`
    - `pkg/cloudapi/compute` - для `Compute`
    - `pkg/cloudapi/disks` - для `Disks`
    - `pkg/cloudapi/dpdknet` - для `DPDK`
    - `pkg/cloudapi/extnet` - для `ExtNet`
    - `pkg/cloudapi/flipgroup` - для `FLIPGroup`
    - `pkg/cloudapi/image` - для `Image`
    - `pkg/cloudapi/k8ci` - для `K8CI`
    - `pkg/cloudapi/k8s` - для `K8S`
    - `pkg/cloudapi/kvmx86` - для `KVMX86`
    - `pkg/cloudapi/lb` - для `LB`
    - `pkg/cloudapi/locations` - для `Locations`
    - `pkg/cloudapi/prometheus` - для `Prometheus`
    - `pkg/cloudapi/rg` - для `RG`
    - `pkg/cloudapi/secgroup` - для `Security group`
    - `pkg/cloudapi/sep` - для `SEP`
    - `pkg/cloudapi/stpolicy` - для `Storage policy`
    - `pkg/cloudapi/tasks` - для `Tasks`
    - `pkg/cloudapi/trunk` - для `Trunk`
    - `pkg/cloudapi/vfpool` - для `VFPool`
    - `pkg/cloudapi/vins` - для `VINS`
    - `pkg/cloudapi/zone` - для `Zone`
- **cloudbroker**:
    - `pkg/cloudbroker/account` - для `Account`
    - `pkg/cloudbroker/audit` - для `Audit`
    - `pkg/cloudbroker/apiaccess` - для `APIAccess`
    - `pkg/cloudbroker/backup` - для `Backup`
    - `pkg/cloudbroker/bservice` - для `Basic Service`
    - `pkg/cloudbroker/compute` - для `Compute`
    - `pkg/cloudbroker/disks` - для `Disks`
    - `pkg/cloudbroker/dpdknet` - для `DPDK`
    - `pkg/cloudbroker/extnet` - для `ExtNet`
    - `pkg/cloudbroker/flipgroup` - для `FLIPGroup`
    - `pkg/cloudbroker/grid` - для `Grid`
    - `pkg/cloudbroker/group` - для `Group`
    - `pkg/cloudbroker/image` - для `Image`
    - `pkg/cloudbroker/k8ci` - для `K8CI`
    - `pkg/cloudbroker/k8s` - для `K8S`
    - `pkg/cloudbroker/kvmx86` - для `KVMX86`
    - `pkg/cloudbroker/lb` - для `LB`
    - `pkg/cloudbroker/node` - для `Node`
    - `pkg/cloudbroker/pcidevice` - для `PCIDevice`
    - `pkg/cloudbroker/prometheus` - для `Prometheus`
    - `pkg/cloudbroker/resmon` - для `Resmon`
    - `pkg/cloudbroker/rg` - для `RG`
    - `pkg/cloudbroker/secgroup` - для `Security group`
    - `pkg/cloudbroker/sep` - для `SEP`
    - `pkg/cloudbroker/stpolicy` - для `Storage policy`
    - `pkg/cloudbroker/tasks` - для `Tasks`
    - `pkg/cloudbroker/trunk` - для `Trunk`
    - `pkg/cloudbroker/user` - для `User`
    - `pkg/cloudbroker/vgpu` - для `VGPU`
    - `pkg/cloudbroker/vfpool` - для `VFPool`
    - `pkg/cloudbroker/vins` - для `VINS`
    - `pkg/cloudbroker/zone` - для `Zone`
- **sdn**:
    - `pkg/sdn/acsgroups` - для `Access groups`
    - `pkg/sdn/adrspools` - для `Address pool`
    - `pkg/sdn/defsecpolicies` - для `DefaultSecurityPolicies`
    - `pkg/sdn/external_networks` - для `ExtNet`
    - `pkg/sdn/flips` - для `FloatingIPs`
    - `pkg/sdn/logicalports` - для `Logical ports`
    - `pkg/sdn/netobjgroups` - для `NetworkObjectGroups`
    - `pkg/sdn/routers` - для `Routers`
    - `pkg/sdn/secpolicies` - для `SecurityPolicies`
    - `pkg/sdn/segments` - для `Segments`

Все поля структуры имеют описание, в которых содержится:

- Их назначение;
- Обязательный или нет - поле required в комментариях;
- Доп. информация (допустимые значения, значения по умолчанию).

#### Пример комментариев структуры

```go
type CreateRequest struct {
	// ID of the resource group, which will own this VM
	// Required: true
	RGID uint64 `url:"rgId" json:"rgId"` 

	// 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"`

	// Number CPUs to allocate to this VM
	// Required: true
	CPU uint64 `url:"cpu" json:"cpu"`

	// Volume of RAM in MB to allocate to this VM
	// Required: true
	RAM uint64 `url:"ram" json:"ram"`

	// 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"`

	// Size of the boot disk in GB
	// Required: false
	BootDisk uint64 `url:"bootDisk,omitempty" json:"bootDisk,omitempty"`

	// ID of SEP to create boot disk on.
	// Uses images SEP ID if not set
	// Required: false
	SEPID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`

	// Pool to use if SEP ID is set, can be also empty if needed to be chosen by system
	// Required: false
	Pool string `url:"pool,omitempty" json:"pool,omitempty"`

	// Network type
	// Should be one of:
	//	- VINS
	//	- EXTNET
	//	- NONE
	// Required: false
	NetType string `url:"netType,omitempty" json:"netType,omitempty"`

	// Network ID for connect to,
	// for EXTNET - external network ID,
	// for VINS - VINS ID,
	// when network type is not "NONE"
	// Required: false
	NetID uint64 `url:"netId,omitempty" json:"netId,omitempty"`

	// IP address to assign to this VM when connecting to the specified network
	// Required: false
	IPAddr string `url:"ipAddr,omitempty" json:"ipAddr,omitempty"`

	// Input data for cloud-init facility
	// Required: false
	Userdata string `url:"userdata,omitempty" json:"userdata,omitempty"`

	// Text description of this VM
	// Required: false
	Description string `url:"desc,omitempty" json:"desc,omitempty"`

	// Start VM upon success
	// Required: false
	Start bool `url:"start,omitempty" json:"start,omitempty"`

	// Node ID
	// Required: false
	NodeID uint64 `url:"nodeId,omitempty" json:"nodeId,omitempty"`

	// System name
	// Required: false
	IS string `url:"IS,omitempty" json:"IS,omitempty"`

	// Compute purpose
	// Required: false
	IPAType string `url:"ipaType,omitempty" json:"ipaType,omitempty"`

	
}
```

#### Пример создания запроса для развертывания виртуальной машины:

```go
package main

import (
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/pkg/cloudapi/kvmx86"
)

func main() {
    // Настройка конфигурации
    cfg := config.Config{
        AppID:     "<APPID>",
        AppSecret: "<APPSECRET>",
        SSOURL:    "https://sso.digitalenergy.online",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    // Создание клиента
    client := decort.New(cfg)

    // Создание структуры запроса
    // CreateRequest - реквест на создание виртуальной машины
    req := kvmx86.CreateRequest{
        RGID:    123,
        Name:    "compute",
        CPU:     4,
        RAM:     4096,
        ImageID: 321,
    }
}
```

### Выполнение запроса

Чтобы выполнить запрос, необходимо:

1. Вызвать у клиента метод, отвечающий за определение группы API для взаимодействия, это может быть `.CloudAPI()`, `.CloudBroker()` или `.SDN()`. Данные методы возвращают соответствующие структуры, с помощью которых можно совершать запросы.
2. Вызвать у возвращенной структуры метод, определяющий группу ручек для взаимодействия.

   Доступные методы для `.CloudAPI()`:

    - `.Account()` - для работы с `Account`
    - `.Audit()` - для работы с `Audit`
    - `.BService()` - для работы с `BService`
    - `.Compute()` - для работы с `Compute`
    - `.Disks()` - для работы с `Disks`
    - `.DPDKNet()` - для работы с `DPDK`
    - `.ExtNet()` - для работы с `ExtNet`
    - `.FLIPgroup()` - для работы с `FLIPGroup`
    - `.Image()` - для работы с `Image`
    - `.K8CI()` - для работы с `K8CI`
    - `.K8S()` - для работы с `K8S`
    - `.KVMx86()` - для работы с `KVMX86`
    - `.LB()` - для работы с `LB`
    - `.Locations()` - для работы с `Locations`
    - `.Prometheus()` - для работы с `Prometheus`
    - `.RG()` - для работы с `RG`
    - `.SecurityGroup()` - для работы с `Security Group`
    - `.SEP()` - для работы с `SEP`
    - `.StPolicy()` - для работы с `Storage Policy`
    - `.Tasks()` - для работы с `Tasks`
    - `.Trunk()` - для работы с `Trunk`
    - `.VFPool()` - для работы с `VFPool`
    - `.VINS()` - для работы с `VINS`
    - `.Zone()` - для работы с `Zone`

   Доступные методы для `.CloudBroker()`:

    - `.Account()` - для работы с `Account`
    - `.Audit()` - для работы с `Audit`
    - `.APIAccess()` - для работы с `APIAccess`
    - `.Backup()` - для работы с `Backup`
    - `.BService()` - для работы с `BService`
    - `.Compute()` - для работы с `Compute`
    - `.Disks()` - для работы с `Disks`
    - `.DPDKNet()` - для работы с `DPDK`
    - `.ExtNet()` - для работы с `ExtNet`
    - `.FLIPGroup()` - для работы с `FLIPGroup`
    - `.Grid()` - для работы с `Grid`
    - `.Group()` - для работы с `Group`
    - `.Image()` - для работы с `Image`
    - `.K8CI()` - для работы с `K8CI`
    - `.K8S()` - для работы с `K8S`
    - `.KVMx86()` - для работы с `KVMX86`
    - `.LB()` - для работы с `LB`
    - `.Node()` - для работы с `Node`
    - `.PCIDevice()` - для работы с `PCIDevice`
    - `.Prometheus()` - для работы с `Prometheus`
    - `.Resmon()` - для работы с `Resmon`
    - `.RG()` - для работы с `RG`
    - `.SecurityGroup()` - для работы с `Security Group`
    - `.SEP()` - для работы с `SEP`
    - `.StPolicy()` - для работы с `Storage Policy`
    - `.Tasks()` - для работы с `Tasks`
    - `.Trunk()` - для работы с `Trunk`
    - `.User()` - для работы с `User`
    - `.VGPU()` - для работы с `VGPU`
    - `.VFPool()` - для работы с `VFPool`
    - `.VINS()` - для работы с `VINS`
    - `.Zone()` - для работы с `Zone`

   Доступные методы для `.SDN()`:

    - `.AccessGroup()` - для работы с `Access group`
    - `.AddressPool()` - для работы с `Addres pool`
    - `.DefaultSecurityPolicies()` - для работы с `DefaultSecurityPolicies`
    - `.ExtNet()` - для работы с `ExtNet`
    - `.FloatingIPs()` - для работы с `FloatingIPs`
    - `.LogicalPorts()` - для работы с `Logical ports`
    - `.NetworkObjectGroups()` - для работы с `NetworkObjectGroups`
    - `.Routers()` - для работы с `Routers`
    - `.SecurityPolicies()` - для работы с `SecurityPolicies`
    - `.Segments()` - для работы с `Segments`

3. Вызвать метод, отвечающий за выполнение запроса и передать в него:

- контекст;
- структуру запроса.
  У каждой группы ручек API имеются свои доступные методы, которые определяются платформой.

4. Обработать результат и ошибки.

Т.к. все вызовы методов идут последовательно, можно их объеденить в конвейер:
Общий вид конвейера будет выглядеть так:

```go
  client.<API>.<группа>.<метод>
```

#### Пример выполнения запроса

```go
package main

import (
    "log"
    "fmt"

    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/pkg/cloudapi/kvmx86"
)

func main() {
    // Настройка конфигурации
    cfg := config.Config{
        AppID:     "<APPID>",
        AppSecret: "<APPSECRET>",
        SSOURL:    "https://sso.digitalenergy.online",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    // Создание клиента
    client := decort.New(cfg)

    // Создание структуры запроса
    // CreateRequest - реквест на создание виртуальной машины
    req := kvmx86.CreateRequest{
        RGID:    123,
        Name:    "compute",
        CPU:     4,
        RAM:     4096,
        ImageID: 321,
    }

    //Выполнение запроса с помощью конвейера
    res, err := client.CloudAPI().KVMX86().Create(context.Background(), req)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(res)
}
```

Для запросов Get и List реализованы запросы GetRaw и ListRaw, которые возвращают ответ не в виде соответствующей структуры, а в виде массива байт (JSON).
Выполнение таких запросов происходит аналогично.

#### Пример выполнения GetRaw и ListRaw запросов

```go
package main

import (
    "log"
    "fmt"

    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/pkg/cloudapi/account"
)

func main() {
    // Настройка конфигурации
    cfg := config.Config{
        AppID:     "<APPID>",
        AppSecret: "<APPSECRET>",
        SSOURL:    "https://sso.digitalenergy.online",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    // Создание клиента
    client := decort.New(cfg)

    // 1. Создание структуры запроса GetRequest на получение информации об аккаунте и выполнение GetRaw запроса с помощью конвейера
    req1 := account.GetRequest{
        AccountID:    123,
    }
    res1, err := client.CloudAPI().Account().GetRaw(context.Background(), req1)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(res1))

    // 2. Создание структуры запроса ListRequest на получение информации об аккаунтах и выполнение ListRaw запроса с помощью конвейера
    req2 := account.ListRequest{}
    res2, err := client.CloudAPI().Account().ListRaw(context.Background(), req2)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(res2))
}
```

### Фильтрация

Для каждого `ListRequest` в SDK есть группа функций для фильтрации ответа платформы. Для того чтобы произвести фильтрацию по заданным полям, достаточно описать анонимную функцию (предикат) в `.FilterFunc()`, например:

```go
// Создание запроса account/list
req := account.ListRequest{}

resp, err := client.CloudAPI().Account().List(context.Background(), req)
if err != nil {
	log.Fatal(err)
}

// Тип filtered - ListAccount, тот же, что и у ответа платформы.
filtered := resp.
	FilterFunc(func(ia account.ItemAccount) bool {
	// ItemAccount открывает доступ к полям модели ответа платформы.
		for _, itemAcl := range ia.ACL {
			if itemAcl.UgroupID == "<UserGroupID>" { // Фильтр по ACL/UgroupID
				return true
			}
		}
		return false
	})
```

Для удобства пользователей, особенно важные фильтры вынесены в отдельные функции, что облегчает фильтрацию сразу по нескольким полям:

```go
// Создание запроса account/list
req := account.ListRequest{}

resp, err := client.CloudAPI().Account().List(context.Background(), req)
if err != nil {
	log.Fatal(err)
}

// Несколько фильтров объединены в конвейер
filtered := resp.
	FilterByName("<NAME>").
	FilterByStatus("<STATUS>")
	// ....
```

Также у `compute`, `disks`, и `lb` присутствуют специфические функции фильтрации, отправляющие дополнительные запросы. В качестве параметров принимают:
- context.Context - контекст для доп. запроса
- id (или другое поле, по которому производится фильтрация)
- interfaces.Caller - DECORT-клиент для запроса

Так как эти функции возвращают не только результирующий слайс, но и возможную ошибку - конвейер придется прервать для обработки ошибки.


#### Использование на примере `compute.FilterByK8SID`:

```go
func main() {
    // Чтение конфигурации из файла
    cfg, _ :=  config.ParseConfigJSON("<PATH>")

    // Создание клиента
    client := decort.New(cfg)

    // Создание структуры запроса compute/list
    req := compute.ListRequest{}

    // Запрос
    resp, err := client.CloudAPI().Compute().List(context.Background(), req)
    if err != nil {
        log.Fatal(err)
    }

    // Фильтрация по id кластера.
    // Первый аргумент - контекст
    // Второй - ID кластера
    // Третий - DECORT-клиент
    filtered, err := resp.FilterByK8SID(context.Background(), <k8sID>, client)
    if err != nil {
        log.Fatal(err) // Возможная ошибка запроса
    }

    // Доп. фильтрация и сортировка результата - worker ноды кластера
    workers := filtered.FilterByK8SWorkers().SortByCreatedTime(false)

    // Доп. фильтрация и сортировка результата - master ноды кластера
    masters := filtered.FilterByK8SMasters().SortByCreatedTime(true)

    // ....
}
```

### Сортировка

Функции сортировки так же могут быть объединены в конвейер:

```go
// Создание запроса compute/list
req := compute.ListRequest{}

resp, err := client.CloudAPI().Compute().List(context.Background(), req)
if err != nil {
	log.Fatal(err)
}

// Функции сортировки имеют параметр inverse (bool):
// При значении false -> сортировка по возрастанию
// При true -> сортировка по убыванию
sorted := resp.
	SortByCPU(false).
	SortByRAM(false).
	SortByCreatedTime(true)
	// ....
```

### Сериализация

Результат преобразований легко сериализовать в JSON при помощи функции `.Serialize()`. Она принимает в себя 2 необязательных аргумента: префикс (prefix) и отступ (Indent).

В случае если функция вызывается без аргументов, то маршализация пройдет успешно, но без отступов и префиксов.

```go
// Сериализация данных с префиксом "" и отступом "\t"
serialized, err := filtered.Serialize("", "\t")
if err != nil {
	log.Fatal(err)
}

// Запись сериализованных данных в файл
err = serialized.WriteToFile("<PATH>")
if err != nil {
	log.Fatal(err)
}
```

#### Комплексный пример

```go
package main

import (
	"context"
	"log"

	decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/pkg/cloudbroker/compute"
)

func main() {
	cfg := config.Config{
		AppID:         "<APP_ID>",
		AppSecret:     "<APP_SECRET>",
		SSOURL:        "<SSO_URL>",
		DecortURL:     "<DECORT_URL>",
		Retries:       5,
	}

	cfg.SetTimeout(5 * time.Minute)
	
	// Создание клиента
	client := decort.New(cfg)

	// Создание запроса compute/list
	req := compute.ListRequest{}

	resp, err := client.CloudBroker().Compute().List(context.Background(), req)
	if err != nil {
		log.Fatal(err)
	}

	// Цепь преобразований.
	filtered, _ := resp.
        FilterFunc(func(ic compute.ItemCompute) bool {
            return ic.GUID == 123 // Фильтр по GUID
        }).
        FilterByName("<NAME>"). // Фильтр по имени
        SortByCPU(false). // Сортировка по кол-ву ядер CPU по возрастанию
        SortByCreatedTime(true). // Сортировка по времени создания по убыванию
        Serialize("", "\t") // Сериализация с префиксом "" и отступом "\t"
        // Serialize - терминальная функция, возвращает Serialized (обертку над []byte)

	// Запись данных в файл
    err = filtered.WriteToFile("<PATH>")
	if err != nil {
		log.Fatal(err)
	}
}

```

### Получение списка уникальных идентификаторов ID объекта

Для всех структур, имеющих поля со списками объектов с уникальными числовыми идентификаторами (ID), добавлены методы IDs(), возвращающие массивы уникальных идентификаторов объектов в этих списках.

```go
package main

import (
    "log"
    "fmt"

    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/pkg/cloudapi/bservice"
)

func main() {
    // Настройка конфигурации
    cfg := config.Config{
        AppID:     "<APPID>",
        AppSecret: "<APPSECRET>",
        SSOURL:    "https://sso.digitalenergy.online",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    // Создание клиента
    client := decort.New(cfg)

    // Создание структуры запроса GetRequest на получение информации о сервисе и выполнение запроса с помощью конвейера
    req := bservice.GetRequest{
        ServiceID:    123,
    }
    res, err := client.CloudAPI().BService().Get(context.Background(), req)
    if err != nil {
        log.Fatal(err)
    }
	
    // Получение списков ID ComputeIDs и GroupIDs экземпляра res типа RecordBasicService по полям Computes и Groups, соответственно
    computeIDs := res.Computes.IDs()
    groupIDs := res.Groups.IDs()
    fmt.Println(computeIDs)
    fmt.Println(groupIDs)
}
```

### Методы поля Result для группы tasks

Поле Result внутри структур группы tasks имеет тип интерфейс и может содержать:
- строку о результате выполнения задачи, например `true`
- массив, содержащий ID и имя созданного ресурса, например `[12345, "resource_name"]`
- массив, содержащий информацию о восстновленных дисках, например `[{"computeId": 123, "diskId": 456}, {"computeId": 789, "diskId": 10}]`

Соответственно, для получения информации из поля Result доступны следующие методы:
- ToString(): строковое представление результата выполнения задачи
- ID() и Name(): получение ID и имени созданного в результате выполнения задачи ресурса
- ToMaps(): получение списка карт, содержащих информацию о дисках, восстановленных в результате выполнения задачи.
  Все методы оборудованы возвратом ошибок. Непустая ошибка означает, что из поля Result нельзя получить информацию, которую предоставляет метод.

```go
package main

import (
    "log"
    "fmt"

    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/pkg/cloudapi/tasks"
	tasks_cb "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/pkg/cloudbroker/tasks"
)

func main() {
    // Настройка конфигурации
    cfg := config.Config{
        AppID:     "<APPID>",
        AppSecret: "<APPSECRET>",
        SSOURL:    "https://sso.digitalenergy.online",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    // Создание клиента
    client := decort.New(cfg)

    // Создание структуры запроса GetRequest на получение информации о конкретной задаче и выполнение запроса с помощью конвейера
    getReq := tasks.GetRequest{
		AuditID: "b6316",
    }
    task, err := client.CloudAPI().Tasks().Get(context.Background(), getReq)
    if err != nil {
        log.Fatal(err)
    }

	// Получение списка карт с информацией о восстановленных дисках
	maps, err := task.Result.ToMaps()
	if err != nil {
		log.Fatal(err)
    }
	fmt.Println(maps)
	
	// Получение строкового результата выполнения задачи task
	res, _ := task.Result.ToString()
	fmt.Println(res)

	// Создание структуры запроса ListRequest на получение информации о всех задачах и выполнение запроса с помощью конвейера
	listReq := tasks_cb.ListRequest{}
	tasks, err := client.CloudBroker().Tasks().List(context.Background(), listReq)
	if err != nil {
		log.Fatal(err)
	}
	
	for _, t := range tasks {
		// Получение id ресурса, созданного в результате выполнения задачи t
		id, err := task.Result.ID()
		if err != nil {
			log.Fatal(err)
        }
		fmt.Println(id)

		// Получение имени ресурса, созданного в результате выполнения задачи t
		name, _ := task.Result.Name()
		fmt.Println(name)
    }
}
```

## Работа с legacy клиентом

Работа с legacy клиентом применяется для пользователей, которые не используют для авторизации decs3o.

### Настройка конфигурации legacy клиента

Сначала, необходимо создать переменную конфигурации клиента. Конфигурация состоит как из обязательных, так и необязательных полей.

| Поле          | Тип    | Обязательный | Описание                                                           |
| ------------- | ------ | ------------ | ------------------------------------------------------------------ |
| Username      | string | Да           | username legacy пользователя                                       |
| Password      | string | Да           | пароль legacy пользователя                                         |
| DecortURL     | string | Да           | URL адрес платформы, с которой будет осуществляться взаимодействие |
| Retries       | uint   | Нет          | Кол-во неудачных попыток выполнения запроса, по умолчанию - 5      |
| Timeout       | config.Duration | Нет | Таймаут HTTP клиента, по умолчанию - без ограничений               |
| SSLSkipVerify | bool   | Нет          | Пропуск проверки подлинности сертификата     |
| Token         | string | Нет          | JWT токен                                                          |

#### Пример конфигурации legacy клиента

```go
import (
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
)

func main(){
    // Настройка конфигурации
    legacyCfg := config.LegacyConfig{
        Username:  "<USERNAME>",
        Password:  "<PASSWORD>",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    legacyCfg.SetTimeout(5 * time.Minute)
}
```

#### Парсинг legacy конфигурации из файла

Также возможно создать переменную конфигурации из JSON или YAML файла, используя функцию `ParseLegacyConfigJSON` (или `ParseLegacyConfigYAML`) из пакета config.
<br>
*См. пример файлов конфигурации ниже и в директории `samples/`.*

```go
import (
	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
)

func main() {
	// Парсинг конфигурации из YAML-файла
	legacyCfg, _ := config.ParseLegacyConfigYAML("<PATH>")
}
```

#### Пример legacy JSON конфигурации

```json
{
    "username": "<USERNAME>",
    "password": "<PASSWORD>",
    "decortUrl": "https://mr4.digitalenergy.online",
    "retries": 5,
    "timeout": "5m",
    "sslSkipVerify": true
}
```

#### Пример legacy YAML конфигурации
```yaml
username: <USERNAME>
password: <PASSWORD>
decortUrl: https://mr4.digitalenergy.online
retries: 5
timeout: 5m
sslSkipVerify: true
```
### Создание legacy клиента

Создание клиента происходит с помощью функции-строителя `NewLegacy` из основного пакета `decort-sdk`, для избежания проблем с именами, пакету можно присвоить алиас `decort`. Функция принимает конфигурацию, возвращает структуру `DecortClient`, с помощью которой можно взаимодействовать с платформой.

#### Пример создания legacy клиента

```go
package main

import (
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
)

func main() {
    // Настройка конфигурации
    legacyCfg := config.LegacyConfig{
        Username:  "<USERNAME>",
        Password:  "<PASSWORD>",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    legacyCfg.SetTimeout(5 * time.Minute)

    // Создание клиента
    legacyClient := decort.NewLegacy(legacyCfg)
}
```

#### Пример выполнения запроса

```go
package main

import (
	"fmt"

    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
)

func main() {
    // Настройка конфигурации
    legacyCfg := config.LegacyConfig{
        Username:  "<USERNAME>",
        Password:  "<PASSWORD>",
        Domain:    "dynamix",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    // Создание клиента
    legacyClient := decort.NewLegacy(legacyCfg)
    
    // Создание структуры запроса
    // CreateRequest - реквест на создание виртуальной машины
    req := kvmx86.CreateRequest{
        RGID:    123,
        Name:    "compute",
        CPU:     4,
        RAM:     4096,
        ImageID: 321,
    }

    // Выполнение запроса
    res, err := legacyClient.CloudAPI().KVMX86().Create(context.Background(), req)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(res)
}
```

## Работа с BVS клиентом

Работа с BVS клиентом применяется для пользователей, которые используют для авторизации BVS.

### Настройка параметров BVS в кабинете администратора

Для корректной работы функции обновления токена необходимо соблюдать следующие условия:

на странице администратора по следующему пути: домены-<имя вашего домена>-(символ i)-токены
- параметр "Время жизни токена доступа" - устанавливается для всего домена. Не применяется есть по следующему пути: безопасность-клиентские_системы-(символ i)-токены-"Время жизни токена доступа" не выставлено иное время, которое имеет больший приоритет для конкретной клиентской системы
- параметр "Время простоя сессии" - время жизни токена обновления. В случае указания количества минут меньше, чем время жизни токена, то обновление токена будет работать некорректно. Редомендуется указывать время или равное или больше времени жизни токена
- параметр "Максимальное время жизни сессии" - время в течение которого возможно производить обновление токена. Если данный параметр будет равен времени жизни токена, то обновление токена будет работать некорректно. Редомендуется указывать время больше времени жизни токена

### Настройка конфигурации BVS клиента

Сначала, необходимо создать переменную конфигурации клиента. Конфигурация состоит как из обязательных, так и необязательных полей.

| Поле          | Тип                                           | Обязательный | Описание                                                           |
| ------------- | --------------------------------------------- | ------------ | ------------------------------------------------------------------ |
| Username      | string                                        | Да           | username пользователя                                              |
| Password      | string                                        | Да           | пароль пользователя                                                |
| AppID         | string                                        | Да           | app_id ключа для выполнения запросов                               |
| AppSecret     | string                                        | Да           | app_secret ключ для выполнения запроса                             |
| DecortURL     | string                                        | Да           | URL адрес платформы, с которой будет осуществляться взаимодействие |
| SSOURL        | string                                        | Да           | URL адрес сервиса аутентификации и авторизации                     |
| Domain        | string                                        | Да           | Имя домена                                                         |
| Retries       | uint                                          | Нет          | Кол-во неудачных попыток выполнения запроса, по умолчанию - 5      |
| Timeout       | config.Duration                               | Нет          | Таймаут HTTP клиента, по умолчанию - без ограничений               |
| SSLSkipVerify | bool                                          | Нет          | Пропуск проверки подлинности сертификата                           |
| Token         | struct{} [см. ниже](#описание-структуры-token)| Нет          | JWT токен                                                          |
| PathCfg       | string                                        | Нет          | Путь записи конфигурации в файл                                    |
| PathToken     | string                                        | Нет          | Путь записи токена в файл                                          |
| TimeToRefresh | uint                                          | Нет          | Количество минут, за сколько до истечения срока действия токена выполнится его обновление, по умолчанию - 1 минута |

### Описание структуры token
| Параметр | Тип | Описание |
| ------------ | ------ | ------------------------------- |
| AccessToken  | string | Токен                           |
| TokenType    | string | Тип токена                      |
| RefreshToken | string | Токен для запроса на обновление |
| Expiry       | time   | Время жизни токена              |

#### Пример конфигурации BVS клиента

```go
import (
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
)

func main(){
    // Настройка конфигурации
    BvsCfg := config.BVSConfig{
        AppID:     "<APP_ID>",
        AppSecret: "<APP_SECRET>",
        Username:  "<USERNAME>",
        Password:  "<PASSWORD>",
        SSOURL:    "https://bvs-delta.qa.loc:8443",
        DecortURL: "https://delta.qa.loc",
        Domain:    "dynamix",
        Retries:   5,
    }

    BvsCfg.SetTimeout(5 * time.Minute)
}
```

#### Парсинг BVS конфигурации из файла

Также возможно создать переменную конфигурации из JSON или YAML файла, используя функцию `ParseConfigBVSJSON` (или `ParseConfigBVSYAML`) из пакета config.
<br>
*См. пример файлов конфигурации ниже и в директории `samples/`.*

```go
import (
	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
)

func main() {
	// Парсинг конфигурации из YAML-файла
	BVSCfg, _ := config.ParseConfigBVSYAML("<PATH>")
}
```

#### Парсинг BVS токена из файла

Также возможно создать переменную токена из JSON или YAML файла, используя функцию `ParseTokenBVSJSON` (или `ParseTokenBVSYAML`) из пакета config.
<br>
*См. пример файлов конфигурации ниже и в директории `samples/`.*

```go
import (
	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
)

func main() {
	// Парсинг токена из json-файла
	BVSToken, _ := config.ParseTokenBVSJSON("<PATH>")
}
```

#### Пример BVS JSON конфигурации

```json
{
    "username": "<USERNAME>",
    "password": "<PASSWORD>",
    "appId": "<APP_ID>",
    "appSecret": "<APP_SECRET>",
    "ssoUrl": "https://bvs-delta.qa.loc:8443",
    "decortUrl": "https://delta.qa.loc",
    "domain":    "dynamix",
    "token": {
        "access_token": "string_token",
        "token_type": "bearer",
        "refresh_token": "string_refresh_token",
        "expiry": "2023-11-24T12:40:27.954150524+03:00"
    },
    "retries": 5,
    "sslSkipVerify": true,
    "timeout": "5m",
    "path_cfg": "config",
    "path_token": "token",
    "timeToRefresh": 5
}
```

#### Пример BVS YAML конфигурации
```yaml
    username: <USERNAME>
    password: <PASSWORD>
    appId: <APP_ID>
    appSecret: <APP_SECRET>
    ssoUrl: https://bvs-delta.qa.loc:8443
    decortUrl: https://delta.qa.loc
    domain:    dynamix
    token": 
    access_token: string_token
    token_type: bearer
    refresh_token: string_refresh_token
    expiry: 2023-11-24T12:40:27.954150524+03:00
    retries: 5
    sslSkipVerify: true
    timeout: 5m
    path_cfg: config
    path_token: token
    timeToRefresh: 5
```
### Создание BVS клиента

Создание клиента происходит с помощью функции-строителя `NewBVS` из основного пакета `decort-sdk`, для избежания проблем с именами, пакету можно присвоить алиас `decort`. Функция принимает конфигурацию, возвращает структуру `DecortClient`, с помощью которой можно взаимодействовать с платформой.

#### Пример создания BVS клиента

```go
package main

import (
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
)

func main() {
    // Настройка конфигурации
    BVSCfg := config.BVSConfig{
        Username:  "<USERNAME>",
        Password:  "<PASSWORD>",
        AppID:     "<APPID>",
        AppSecret: "<APPSECRET>",
        SSOURL:    "https://bvs-delta.qa.loc:8443",
        DecortURL: "https://mr4.digitalenergy.online",
        Domain:    "dynamix",
        Retries:   5,
    }

    BVSCfg.SetTimeout(5 * time.Minute)

    // Создание клиента
    BVSClient := decort.NewBVS(BVSCfg)
}
```

#### Пример получения BVS токена

В случае указания значения в переменной конфигурации `PathCfg` токен и конфигурация будут записаны в файл в формате `json`, переменная `PathToken` служит для записи токена в файл в формате `json`

```go
package main

import (
	"fmt"

    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
)

func main() {
    // Настройка конфигурации
    BVSCfg := config.BVSConfig{
        Username:  "<USERNAME>",
        Password:  "<PASSWORD>",
        AppID:     "<APPID>",
        AppSecret: "<APPSECRET>",
        SSOURL:    "https://bvs-delta.qa.loc:8443",
        DecortURL: "https://mr4.digitalenergy.online",
        Domain:    "dynamix",
        PathCfg:   "config",
        Retries:   5,
    }

    // Создание клиента
    BVSClient := decort.NewBVS(BVSCfg)
    
    // Выполнение запроса на получение токена
    token, err := BVSClient.GetToken(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(token)
}
```

#### Пример обновления BVS токена

В случае указания значения в переменной конфигурации `PathCfg` обновленный токен и конфигурация будут записаны в файл в формате `json`, переменная `PathToken` служит для записи токена в файл в формате `json`

```go
package main

import (
	"fmt"

    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
)

func main() {
    // Настройка конфигурации
    BVSCfg := config.BVSConfig{
        Username:  "<USERNAME>",
        Password:  "<PASSWORD>",
        AppID:     "<APPID>",
        AppSecret: "<APPSECRET>",
        SSOURL:    "https://bvs-delta.qa.loc:8443",
        DecortURL: "https://mr4.digitalenergy.online",
        Domain:    "dynamix",
        PathToken: "token",
        Retries:   5,
    }

    // Создание клиента
    BVSClient := decort.NewBVS(BVSCfg)
    
    // Выполнение запроса на обновление токена
    token, err := BVSClient.RefreshToken(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(token)
}
```

#### Пример выполнения запроса

```go
package main

import (
	"fmt"

    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
)

func main() {
    // Настройка конфигурации
    BVSCfg := config.BVSConfig{
        Username:  "<USERNAME>",
        Password:  "<PASSWORD>",
        AppID:     "<APPID>",
        AppSecret: "<APPSECRET>",
        SSOURL:    "https://bvs-delta.qa.loc:8443",
        DecortURL: "https://mr4.digitalenergy.online",
        Domain:    "dynamix",
        Retries:   5,
    }

    // Создание клиента
    BVSClient := decort.NewBVS(BVSCfg)
    
    // Создание структуры запроса
    // CreateRequest - реквест на создание виртуальной машины
    req := kvmx86.CreateRequest{
        RGID:    123,
        Name:    "compute",
        CPU:     4,
        RAM:     4096,
        ImageID: 321,
    }

    // Выполнение запроса
    res, err := BVSClient.CloudAPI().KVMX86().Create(context.Background(), req)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(res)
}
```
#### Пример валидации запросов, имеющих в своей структуре поле RAM (или MasterRam/WorkerRAM)

Если структура запроса содержит поле RAM (или MasterRam/WorkerRAM), то он может быть проверен на валидность. Для этого запрос должен быть передан в функцию ValidateRAM. Вторым аргументом ValidateRAM ожидает число uint64. Рекомендуется использовать константу constants.RAM_DIVISIBILITY. Функция проверит кратно ли значение поля RAM (или MasterRam/WorkerRAM) этому числу.

#### Пример выполнения запроса

```go
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/internal/constants"
	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/internal/validators"
	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/pkg/cloudbroker/kvmx86"
)

func main() {
	// Настройка конфигурации
	cfg := config.Config{
		AppID:         "<APPID>",
		AppSecret:     "<APPSECRET>",
		SSOURL:        "https://sso-delta.qa.loc:8443",
		DecortURL:     "https://delta.qa.loc",
		Retries:       5,
		SSLSkipVerify: true,
	}

	// Создание клиента
	client := decort.New(cfg)

	// Создание структуры запроса
	// CreateRequest - реквест на создание виртуальной машины
	req := kvmx86.CreateRequest{
		Name:    "kvmx86",
		RGID:    907,
		CPU:     2048,
		RAM:     1024,
		ImageID: 161,
	}

    // Валидация запроса
	err := validators.ValidateRAM(req, constants.RAM_DIVISIBILITY)
	if err != nil {
		log.Fatalf("unable to validate request: %v", err)
	}
	//Выполнение запроса с помощью конвейера
	res, err := client.CloudBroker().KVMX86().Create(context.Background(), req)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	log.Println(res)

}
```

## Работа с универсальным клиентом

Работа с универсальным клиентом позволяет использовать любой тип авторизации

### Настройка конфигурации универсального клиента

| Параметр | Тип | Обязательный | Описание |
| --- | --- | --- | --- |
| Decs3oConfig | *Config | Нет | Конфигурация Decs3o |
| BVSConfig | *BVSConfig  | Нет | Конфигурация BVS |
| LegacyConfig | string | Нет | Конфигурация Legacy |

В универсальном клиенте можно использовать только один тип конфигурации одновременно.

#### Пример конфигурации универсального клиента

```go
import (
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
)

func main(){
    // Настройка конфигурации
    BVSConfig := config.BVSConfig{
        AppID:     "<APP_ID>",
        AppSecret: "<APP_SECRET>",
        SSOURL:    "https://sso.digitalenergy.online",
        DecortURL: "https://mr4.digitalenergy.online",
        Username:  "<Username>",
        Password:  "<Password>",
        Retries:   5,
    }

    BVSConfig.SetTimeout(5 * time.Minute)

    cfg := config.UniversalConfig{
		BVSConfig: &BVScfg,
	}
}
```

#### Создание универсального клиента

Создание клиента происходит с помощью функции-строителя `NewUniversal` из основного пакета `decort-sdk`, для избежания проблем с именами, пакету можно присвоить алиас `decort`. Функция принимает конфигурацию, возвращает структуру `ClientInterface`, с помощью которой можно взаимодействовать с платформой.

#### Пример создания универсального клиента

```go
package main

import (
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
    decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
)

func main() {
    // Настройка конфигурации
    legacyCfg := config.LegacyConfig{
        Username:  "<USERNAME>",
        Password:  "<PASSWORD>",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
    }

    legacyCfg.SetTimeout(5 * time.Minute)

    cfg := config.UniversalConfig{
        LegacyConfig: &legacyCfg,
	}

    // Создание клиента
    universalClient := decort.NewUniversal(cfg)
}
```

#### Пример выполнения запроса

```go
package main

import (
	"fmt"

	"repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
	decort "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
)

func main() {
	// Настройка конфигурации
	legacyCfg := config.LegacyConfig{
		Username:  "<USERNAME>",
		Password:  "<PASSWORD>",
		Domain:    "dynamix",
		DecortURL: "https://mr4.digitalenergy.online",
		Retries:   5,
	}

	legacyCfg.SetTimeout(5 * time.Minute)

	cfg := config.UniversalConfig{
		LegacyConfig: &legacyCfg,
	}

	// Создание клиента
	universalClient := decort.NewUniversal(cfg)

	// Создание структуры запроса
	// CreateRequest - реквест на создание виртуальной машины
	req := kvmx86.CreateRequest{
		RGID:    123,
		Name:    "compute",
		CPU:     4,
		RAM:     4096,
		ImageID: 321,
	}

	// Выполнение запроса
	res, err := universalClient.CloudAPI().KVMX86().Create(context.Background(), req)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(res)
}
```


## Проверка соответствия версии платформы и версии dynamix

С версии v1.11.0 для каждого клиента добавлен метод `Check` для проверки соответствия decort-sdk и платформы dynamix.
В случае соответсвия decort-sdk и платформы dynamix возвращается структура, содержащая информацию о версии и актуальном билде платформы.

#### Пример выполнения запроса

```go
import (
    "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13/config"
)

func main(){
    // Настройка конфигурации
    config := config.Config{
        AppID:     "<APP_ID>",
        AppSecret: "<APP_SECRET>",
        SSOURL:    "https://sso.digitalenergy.online",
        DecortURL: "https://mr4.digitalenergy.online",
        Retries:   5,
        SSLSkipVerify: true,
    }

    // Создание клиента
    client := decort.New(config)
	
    // Проверка соответствия версии
    checkInfo, err := client.Check()
}
```

# Создание mock клиента

Создание клиента происходит с помощью функции-строителя `NewMockDecortClient` из основного пакета `decort-sdk`. Функция принимает mock реализацию интерфейса interfaces.Calller, возвращает структуру `MockDecortClient`, с помощью которой можно производить unit тестирование API Decort SDK без подключения к серверу

#### Пример создания mock клиента
```go
package unit_test

import (
	"testing"
	"go.uber.org/mock/gomock"
	decortsdk "repository.basistech.ru/BASIS/dynamix-golang-sdk/v13"
)

// Пример юнит тестирования на моках
func TestClient(t *testing.T) {
	ctrl := gomock.NewController(t)
	// Создаем mock интерфейса Caller
	mockCaller := decortsdk.NewMockCaller(ctrl)
	// Создаем mock интерфейса DecortClient
	mockClient := decortsdk.NewMockDecortClient(mockCaller)
    // ....
}
```
Пример юнит теста можно посмотреть в файле [samples/client/client_test.go](samples/client/client_test.go)

При редактировании интерфеса interface.Caller необходимо перегенерировать Mock :
``` shell
make gen-mock
```