diff --git a/CHANGELOG.md b/CHANGELOG.md index 908ea69..adecfc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,4 @@ -## Version 1.7.6 +## Version 1.6.13 ### Bugfix - -- Fix allowed network plugin value from "weawenet" to "weavenet" in validators for cloudapi/k8s, cloudbroker/k8s and cloudbroker/k8ci -- Delete omitempty from json, url tags in field Permanently in model DeleteRequest in cloudbroker/k8ci -- Delete ItemAffinityGroup and ListAffinityGroup models and change Data field type in ListAffinityGroups model in order to fix panic for AffinityGroupsList method in cloudapi/rg -- Fix ListAffinityGroups.IDs method accordingly \ No newline at end of file +- Fix url for Disable method in cloudapi/bservice \ No newline at end of file diff --git a/README.md b/README.md index bbba2f2..9ce9989 100644 --- a/README.md +++ b/README.md @@ -11,50 +11,34 @@ Decort SDK - это библиотека, написанная на языке G - Версия 1.4.x Decort-SDK соответствует 3.8.6 версии платформы - Версия 1.5.x Decort-SDK соответствует 3.8.7 версии платформы - Версия 1.6.x Decort-SDK соответствует 3.8.8 версии платформы - - Версия 1.7.х Decort-SDK соответствует 3.8.9 версии платформы ## Оглавление - [Установка](#установка) - [Список API](#список-api) - - [Cloudapi](#cloudapi) - - [Cloudbroker](#cloudbroker) + - [Cloudapi](#cloudapi) + - [Cloudbroker](#cloudbroker) - [Работа с библиотекой](#работа-с-библиотекой) - - [Настройка конфигурации клиента](#настройка-конфигурации-клиента) - - [Пример конфигурации клиента](#пример-конфигурации-клиента) - - [Парсинг конфигурации из файла](#парсинг-конфигурации-из-файла) - - [Пример JSON конфигурации](#пример-json-конфигурации) - - [Пример YAML конфигурации](#пример-yaml-конфигурации) - - [Создание клиента](#создание-клиента) - - [Создание структуры запроса](#cоздание-структуры-запроса) - - [Выполнение запроса](#выполнение-запроса) - - [Фильтрация](#фильтрация) - - [Сортировка](#сортировка) - - [Сериализация](#сериализация) - - [Получение списка уникальных идентификаторов (ID) объекта](#получение-списка-уникальных-идентификаторов-id-объекта) + - [Настройка конфигурации клиента](#настройка-конфигурации-клиента) + - [Пример конфигурации клиента](#пример-конфигурации-клиента) + - [Парсинг конфигурации из файла](#парсинг-конфигурации-из-файла) + - [Пример JSON конфигурации](#пример-json-конфигурации) + - [Пример YAML конфигурации](#пример-yaml-конфигурации) + - [Создание клиента](#создание-клиента) + - [Создание структуры запроса](#cоздание-структуры-запроса) + - [Выполнение запроса](#выполнение-запроса) + - [Фильтрация](#фильтрация) + - [Сортировка](#сортировка) + - [Сериализация](#сериализация) - [Работа с legacy клиентом](#работа-с-legacy-клиентом) - - [Настройка конфигурации legacy клиента](#настройка-конфигурации-legacy-клиента) - - [Пример конфигурации legacy клиента](#пример-конфигурации-legacy-клиента) - - [Парсинг legacy конфигурации из файла](#парсинг-legacy-конфигурации-из-файла) - - [Пример legacy JSON конфигурации](#пример-legacy-json-конфигурации) - - [Пример legacy YAML конфигурации](#пример-legacy-yaml-конфигурации) - - [Создание legacy клиента](#создание-legacy-клиента) - - [Создание структуры запроса](#cоздание-структуры-запроса) - - [Выполнение запроса](#выполнение-запроса) -- [Работа с 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-токена) - - [Пример выполнения запроса](#пример-выполнения-запроса) + - [Настройка конфигурации legacy клиента](#настройка-конфигурации-legacy-клиента) + - [Пример конфигурации legacy клиента](#пример-конфигурации-legacy-клиента) + - [Парсинг legacy конфигурации из файла](#парсинг-legacy-конфигурации-из-файла) + - [Пример legacy JSON конфигурации](#пример-legacy-json-конфигурации) + - [Пример legacy YAML конфигурации](#пример-legacy-yaml-конфигурации) + - [Создание legacy клиента](#создание-legacy-клиента) + - [Создание структуры запроса](#cоздание-структуры-запроса) + - [Выполнение запроса](#выполнение-запроса) ## Установка @@ -129,8 +113,8 @@ go get -u repository.basistech.ru/BASIS/decort-golang-sdk Алгоритм работы с библиотекой выглядит следующим образом: 1. Выполнение одного из действий: -- настройка конфигурации клиента; -- парсинг конфигурации из файла. + - настройка конфигурации клиента; + - парсинг конфигурации из файла. 2. Создание клиента. 3. Создание структуры запроса. 4. Выполнение запроса. @@ -172,7 +156,7 @@ func main(){ #### Парсинг конфигурации из файла -Также возможно создать переменную конфигурации из JSON или YAML файла, используя функцию `ParseConfigJSON` (или `ParseConfigYAML`) из пакета config. +Также возможно создать переменную конфигурации из JSON или YAML файла, используя функцию `ParseConfigJSON` (или `ParseConfigYAML`) из пакета config.
*См. пример файлов конфигурации ниже и в директории `samples/`.* @@ -183,7 +167,7 @@ import ( func main() { // Парсинг конфигурации из JSON-файла - cfg, _ := config.ParseConfigJSON("") + cfg := config.ParseConfigJSON("") } ``` @@ -254,48 +238,48 @@ func main() { В каждом пакете находятся пакеты групп API: - **cloudapi**: - - `pkg/cloudapi/account` - для `Account` - - `pkg/cloudapi/bservice` - для `Basic Service` - - `pkg/cloudapi/compute` - для `Compute` - - `pkg/cloudapi/disks` - для `Disks` - - `pkg/cloudapi/extnet` - для `ExtNet` - - `pkg/cloudapi/flipgroup` - для `FLIPGroup` - - `pkg/cloudapi/image` - для `Image` - - `pkg/cloudapi/k8ci` - для `K8CI` - - `pkg/cloudapi/k8s` - для `K8S` - - `pkg/cloudapi/kvmppc` - для `KVMPPC` - - `pkg/cloudapi/kvmx86` - для `KVMX86` - - `pkg/cloudapi/lb` - для `LB` - - `pkg/cloudapi/locations` - для `Locations` - - `pkg/cloudapi/rg` - для `RG` - - `pkg/cloudapi/sizes` - для `Sizes` - - `pkg/cloudapi/stack` - для `Stack` - - `pkg/cloudapi/tasks` - для `Tasks` - - `pkg/cloudapi/vins` - для `VINS` + - `pkg/cloudapi/account` - для `Account` + - `pkg/cloudapi/bservice` - для `Basic Service` + - `pkg/cloudapi/compute` - для `Compute` + - `pkg/cloudapi/disks` - для `Disks` + - `pkg/cloudapi/extnet` - для `ExtNet` + - `pkg/cloudapi/flipgroup` - для `FLIPGroup` + - `pkg/cloudapi/image` - для `Image` + - `pkg/cloudapi/k8ci` - для `K8CI` + - `pkg/cloudapi/k8s` - для `K8S` + - `pkg/cloudapi/kvmppc` - для `KVMPPC` + - `pkg/cloudapi/kvmx86` - для `KVMX86` + - `pkg/cloudapi/lb` - для `LB` + - `pkg/cloudapi/locations` - для `Locations` + - `pkg/cloudapi/rg` - для `RG` + - `pkg/cloudapi/sizes` - для `Sizes` + - `pkg/cloudapi/stack` - для `Stack` + - `pkg/cloudapi/tasks` - для `Tasks` + - `pkg/cloudapi/vins` - для `VINS` - **cloudbroker**: - - `pkg/cloudbroker/account` - для `Account` - - `pkg/cloudbroker/apiaccess` - для `APIAccess` - - `pkg/cloudbroker/backup` - для `Backup` - - `pkg/cloudbroker/compute` - для `Compute` - - `pkg/cloudbroker/disks` - для `Disks` - - `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/kvmppc` - для `KVMPPC` - - `pkg/cloudbroker/kvmx86` - для `KVMX86` - - `pkg/cloudbroker/lb` - для `LB` - - `pkg/cloudbroker/pcidevice` - для `PCIDevice` - - `pkg/cloudbroker/rg` - для `RG` - - `pkg/cloudbroker/sep` - для `SEP` - - `pkg/cloudbroker/stack` - для `Stack` - - `pkg/cloudbroker/tasks` - для `Tasks` - - `pkg/cloudbroker/user` - для `User` - - `pkg/cloudbroker/vgpu` - для `VGPU` - - `pkg/cloudbroker/vins` - для `VINS` + - `pkg/cloudbroker/account` - для `Account` + - `pkg/cloudbroker/apiaccess` - для `APIAccess` + - `pkg/cloudbroker/backup` - для `Backup` + - `pkg/cloudbroker/compute` - для `Compute` + - `pkg/cloudbroker/disks` - для `Disks` + - `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/kvmppc` - для `KVMPPC` + - `pkg/cloudbroker/kvmx86` - для `KVMX86` + - `pkg/cloudbroker/lb` - для `LB` + - `pkg/cloudbroker/pcidevice` - для `PCIDevice` + - `pkg/cloudbroker/rg` - для `RG` + - `pkg/cloudbroker/sep` - для `SEP` + - `pkg/cloudbroker/stack` - для `Stack` + - `pkg/cloudbroker/tasks` - для `Tasks` + - `pkg/cloudbroker/user` - для `User` + - `pkg/cloudbroker/vgpu` - для `VGPU` + - `pkg/cloudbroker/vins` - для `VINS` Все поля структуры имеют описание, в которых содержится: @@ -436,50 +420,50 @@ func main() { Доступные методы для `.CloudAPI()`: - - `.Account()` - для работы с `Account` - - `.BService()` - для работы с `BService` - - `.Compute()` - для работы с `Compute` - - `.Disks()` - для работы с `Disks` - - `.ExtNet()` - для работы с `ExtNet` - - `.FLIPgroup()` - для работы с `FLIPGroup` - - `.Image()` - для работы с `Image` - - `.K8CI()` - для работы с `K8CI` - - `.K8S()` - для работы с `K8S` - - `.KVMPPC()` - для работы с `KVMPPC` - - `.KVMx86()` - для работы с `KVMX86` - - `.LB()` - для работы с `LB` - - `.Locations()` - для работы с `Locations` - - `.RG()` - для работы с `RG` - - `.Sizes()` - для работы с `Sizes` - - `.Stack()` - для работы с `Stack` - - `.Tasks()` - для работы с `Tasks` - - `.VINS()` - для работы с `VINS` + - `.Account()` - для работы с `Account` + - `.BService()` - для работы с `BService` + - `.Compute()` - для работы с `Compute` + - `.Disks()` - для работы с `Disks` + - `.ExtNet()` - для работы с `ExtNet` + - `.FLIPgroup()` - для работы с `FLIPGroup` + - `.Image()` - для работы с `Image` + - `.K8CI()` - для работы с `K8CI` + - `.K8S()` - для работы с `K8S` + - `.KVMPPC()` - для работы с `KVMPPC` + - `.KVMx86()` - для работы с `KVMX86` + - `.LB()` - для работы с `LB` + - `.Locations()` - для работы с `Locations` + - `.RG()` - для работы с `RG` + - `.Sizes()` - для работы с `Sizes` + - `.Stack()` - для работы с `Stack` + - `.Tasks()` - для работы с `Tasks` + - `.VINS()` - для работы с `VINS` Доступные методы для `.CloudBroker()`: - - `.Account()` - для работы с `Account` - - `.APIAccess()` - для работы с `APIAccess` - - `.Backup()` - для работы с `Backup` - - `.Compute()` - для работы с `Compute` - - `.Disks()` - для работы с `Disks` - - `.ExtNet()` - для работы с `ExtNet` - - `.FLIPGroup()` - для работы с `FLIPGroup` - - `.Grid()` - для работы с `Grid` - - `.Group()` - для работы с `Group` - - `.Image()` - для работы с `Image` - - `.K8CI()` - для работы с `K8CI` - - `.K8S()` - для работы с `K8S` - - `.KVMPPC()` - для работы с `KVMPPC` - - `.KVMx86()` - для работы с `KVMX86` - - `.LB()` - для работы с `LB` - - `.PCIDevice()` - для работы с `PCIDevice` - - `.RG()` - для работы с `RG` - - `.SEP()` - для работы с `SEP` - - `.Stack()` - для работы с `Stack` - - `.Tasks()` - для работы с `Tasks` - - `.User()` - для работы с `User` - - `.VGPU()` - для работы с `VGPU` - - `.VINS()` - для работы с `VINS` + - `.Account()` - для работы с `Account` + - `.APIAccess()` - для работы с `APIAccess` + - `.Backup()` - для работы с `Backup` + - `.Compute()` - для работы с `Compute` + - `.Disks()` - для работы с `Disks` + - `.ExtNet()` - для работы с `ExtNet` + - `.FLIPGroup()` - для работы с `FLIPGroup` + - `.Grid()` - для работы с `Grid` + - `.Group()` - для работы с `Group` + - `.Image()` - для работы с `Image` + - `.K8CI()` - для работы с `K8CI` + - `.K8S()` - для работы с `K8S` + - `.KVMPPC()` - для работы с `KVMPPC` + - `.KVMx86()` - для работы с `KVMX86` + - `.LB()` - для работы с `LB` + - `.PCIDevice()` - для работы с `PCIDevice` + - `.RG()` - для работы с `RG` + - `.SEP()` - для работы с `SEP` + - `.Stack()` - для работы с `Stack` + - `.Tasks()` - для работы с `Tasks` + - `.User()` - для работы с `User` + - `.VGPU()` - для работы с `VGPU` + - `.VINS()` - для работы с `VINS` 3. Вызвать метод, отвечающий за выполнение запроса и передать в него: @@ -650,7 +634,7 @@ filtered := resp. ```go func main() { // Чтение конфигурации из файла - cfg, _ := config.ParseConfigJSON("") + cfg := config.ParseConfigJSON("") // Создание клиента client := decort.New(cfg) @@ -782,7 +766,7 @@ func main() { ``` -### Получение списка уникальных идентификаторов ID объекта +### Получение списка уникальных идентификаторов (ID) объекта Для всех структур, имеющих поля со списками объектов с уникальными числовыми идентификаторами (ID), добавлены методы IDs(), возвращающие массивы уникальных идентификаторов объектов в этих списках. @@ -879,7 +863,7 @@ import ( func main() { // Парсинг конфигурации из YAML-файла - legacyCfg, _ := config.ParseLegacyConfigYAML("") + legacyCfg := config.ParseLegacyConfigYAML("") } ``` @@ -931,7 +915,7 @@ func main() { legacyCfg.SetTimeout(5 * time.Minute) // Создание клиента - legacyClient := decort.NewLegacy(legacyCfg) + legacyClient := decort.NewLegacy(cfg) } ``` @@ -952,13 +936,12 @@ func main() { legacyCfg := config.LegacyConfig{ Username: "", Password: "", - Domain: "dynamix", DecortURL: "https://mr4.digitalenergy.online", Retries: 5, } // Создание клиента - legacyClient := decort.NewLegacy(legacyCfg) + legacyClient := decort.NewLegacy(cfg) // Создание структуры запроса // CreateRequest - реквест на создание виртуальной машины @@ -971,322 +954,10 @@ func main() { } // Выполнение запроса - 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/decort-golang-sdk/config" -) - -func main(){ - // Настройка конфигурации - BvsCfg := config.BVSConfig{ - AppID: "", - AppSecret: "", - Username: "", - 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. -
-*См. пример файлов конфигурации ниже и в директории `samples/`.* - -```go -import ( - "repository.basistech.ru/BASIS/decort-golang-sdk/config" -) - -func main() { - // Парсинг конфигурации из YAML-файла - BVSCfg, _ := config.ParseConfigBVSYAML("") -} -``` - -#### Парсинг BVS токена из файла - -Также возможно создать переменную токена из JSON или YAML файла, используя функцию `ParseTokenBVSJSON` (или `ParseTokenBVSYAML`) из пакета config. -
-*См. пример файлов конфигурации ниже и в директории `samples/`.* - -```go -import ( - "repository.basistech.ru/BASIS/decort-golang-sdk/config" -) - -func main() { - // Парсинг токена из json-файла - BVSToken, _ := config.ParseTokenBVSJSON("") -} -``` - -#### Пример BVS JSON конфигурации - -```json -{ - "username": "", - "password": "", - "appId": "", - "appSecret": "", - "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: - password: - appId: - appSecret: - 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/decort-golang-sdk/config" - decort "repository.basistech.ru/BASIS/decort-golang-sdk" -) - -func main() { - // Настройка конфигурации - BVSCfg := config.BVSConfig{ - Username: "", - Password: "", - AppID: "", - 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/decort-golang-sdk/config" - decort "repository.basistech.ru/BASIS/decort-golang-sdk" -) - -func main() { - // Настройка конфигурации - BVSCfg := config.BVSConfig{ - Username: "", - Password: "", - AppID: "", - 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/decort-golang-sdk/config" - decort "repository.basistech.ru/BASIS/decort-golang-sdk" -) - -func main() { - // Настройка конфигурации - BVSCfg := config.BVSConfig{ - Username: "", - Password: "", - AppID: "", - 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/decort-golang-sdk/config" - decort "repository.basistech.ru/BASIS/decort-golang-sdk" -) - -func main() { - // Настройка конфигурации - BVSCfg := config.BVSConfig{ - Username: "", - Password: "", - AppID: "", - 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) + res, err := client.CloudAPI().KVMX86().Create(context.Background(), req) if err != nil { log.Fatal(err) } fmt.Println(res) } -``` diff --git a/client.go b/client.go index 730d923..5e4a66a 100644 --- a/client.go +++ b/client.go @@ -8,7 +8,6 @@ import ( "io" "mime/multipart" "net/http" - "reflect" "strconv" "strings" "sync" @@ -16,12 +15,13 @@ import ( "github.com/google/go-querystring/query" "repository.basistech.ru/BASIS/decort-golang-sdk/config" - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi" + k8s_ca "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8s" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker" + k8s_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8s" ) -// DecortClient is HTTP-client for platform +// HTTP-client for platform type DecortClient struct { decortURL string client *http.Client @@ -70,54 +70,35 @@ func (dc *DecortClient) CloudBroker() *cloudbroker.CloudBroker { // DecortApiCall method for sending requests to the platform func (dc *DecortClient) DecortApiCall(ctx context.Context, method, url string, params interface{}) ([]byte, error) { - values, err := query.Values(params) - if err != nil { - return nil, err - } - - body := bytes.NewBufferString(values.Encode()) - - req, err := http.NewRequestWithContext(ctx, method, dc.decortURL+constants.Restmachine+url, body) - if err != nil { - return nil, err - } - - // get token - if err = dc.getToken(ctx); err != nil { - return nil, err - } - - // perform request - respBytes, err := dc.do(req, "") - if err != nil { - return nil, err - } - - return respBytes, err -} - -// DecortApiCallMP method for sending requests to the platform -func (dc *DecortClient) DecortApiCallMP(ctx context.Context, method, url string, params interface{}) ([]byte, error) { - body, ctype, err := multiPartReq(params) - if err != nil { - return nil, err + k8sCaCreateReq, okCa := params.(k8s_ca.CreateRequest) + k8sCbCreateReq, okCb := params.(k8s_cb.CreateRequest) + var body *bytes.Buffer + var ctype string + + if okCa { + body, ctype = createK8sCloudApi(k8sCaCreateReq) + } else if okCb { + body, ctype = createK8sCloudBroker(k8sCbCreateReq) + } else { + values, err := query.Values(params) + if err != nil { + return nil, err + } + body = bytes.NewBufferString(values.Encode()) } - req, err := http.NewRequestWithContext(ctx, method, dc.decortURL+constants.Restmachine+url, body) + req, err := http.NewRequestWithContext(ctx, method, dc.decortURL+"/restmachine"+url, body) if err != nil { return nil, err } - // get token if err = dc.getToken(ctx); err != nil { return nil, err } // perform request - respBytes, err := dc.do(req, ctype) - if err != nil { - return nil, err - } + var respBytes []byte + respBytes, err = dc.do(req, ctype) return respBytes, err } @@ -126,53 +107,41 @@ func (dc *DecortClient) getToken(ctx context.Context) error { dc.mutex.Lock() defer dc.mutex.Unlock() - // new token is not needed - if dc.cfg.Token != "" && !time.Now().After(dc.expiryTime) { - return nil - } + if dc.cfg.Token == "" || time.Now().After(dc.expiryTime) { + body := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s&response_type=id_token", dc.cfg.AppID, dc.cfg.AppSecret) + bodyReader := strings.NewReader(body) + + dc.cfg.SSOURL = strings.TrimSuffix(dc.cfg.SSOURL, "/") - // set up request headers and body - body := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s&response_type=id_token", dc.cfg.AppID, dc.cfg.AppSecret) - bodyReader := strings.NewReader(body) + req, _ := http.NewRequestWithContext(ctx, "POST", dc.cfg.SSOURL+"/v1/oauth/access_token", bodyReader) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - dc.cfg.SSOURL = strings.TrimSuffix(dc.cfg.SSOURL, "/") + resp, err := dc.client.Do(req) + if err != nil { + return fmt.Errorf("cannot get token: %w", err) + } - req, _ := http.NewRequestWithContext(ctx, "POST", dc.cfg.SSOURL+"/v1/oauth/access_token", bodyReader) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + tokenBytes, _ := io.ReadAll(resp.Body) + resp.Body.Close() - // request token - resp, err := dc.client.Do(req) - if err != nil || resp == nil { - return fmt.Errorf("cannot get token: %w", err) - } - defer resp.Body.Close() + if resp.StatusCode != 200 { + return fmt.Errorf("cannot get token: %s", tokenBytes) + } - var tokenBytes []byte - tokenBytes, err = io.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("cannot get token: %w", err) - } + token := string(tokenBytes) - if resp.StatusCode != 200 { - return fmt.Errorf("cannot get token: %s", tokenBytes) + dc.cfg.Token = token + dc.expiryTime = time.Now().AddDate(0, 0, 1) } - // save token in config - token := string(tokenBytes) - dc.cfg.Token = token - dc.expiryTime = time.Now().AddDate(0, 0, 1) - return nil } -// do method performs request and returns response as an array of bytes and nil error in case of response status code 200. -// In any other cases do returns nil response and error. -// Retries are implemented in case of connection reset errors. func (dc *DecortClient) do(req *http.Request, ctype string) ([]byte, error) { - // set up request headers and body - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") if ctype != "" { - req.Header.Set("Content-Type", ctype) + req.Header.Add("Content-Type", ctype) + } else { + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") } req.Header.Add("Authorization", "bearer "+dc.cfg.Token) @@ -183,51 +152,13 @@ func (dc *DecortClient) do(req *http.Request, ctype string) ([]byte, error) { return nil, err } - req.Body.Close() req.Body = io.NopCloser(bytes.NewBuffer(buf)) resp, err := dc.client.Do(req) - if resp != nil { - defer resp.Body.Close() - } - - // retries logic GOES HERE - // get http response - //var resp *http.Response - //for i := uint64(0); i < dc.cfg.Retries; i++ { - // req := req.Clone(req.Context()) - // req.Body = io.NopCloser(bytes.NewBuffer(buf)) - // - // if i > 0 { - // time.Sleep(5 * time.Second) // no time sleep for the first request - // } - // - // resp, err = dc.client.Do(req) - // - // // stop retries on success and close response body - // if resp != nil { - // defer resp.Body.Close() - // } - // if err == nil { - // break - // } - // - // // retries in case of connection errors with time sleep - // if isConnectionError(err) { - // continue - // } - // - // // return error in case of non-connection error - // return nil, err - //} - - // handle http request errors - if err != nil { + if err != nil || resp == nil { return nil, err } - if resp == nil { - return nil, fmt.Errorf("got empty response without error") - } + defer resp.Body.Close() // handle successful request respBytes, _ := io.ReadAll(resp.Body) @@ -240,100 +171,230 @@ func (dc *DecortClient) do(req *http.Request, ctype string) ([]byte, error) { return nil, fmt.Errorf("could not execute request: %w", err) } -// isConnectionError checks if given error falls within specific and associated connection errors -//func isConnectionError(err error) bool { -// if strings.Contains(err.Error(), "connection reset by peer") { -// return true -// } -// if errors.Is(err, io.EOF) { -// return true -// } -// -// return false -//} - -// multiPartReq writes the request structure to the request body, and also returns string of the content-type -func multiPartReq(params interface{}) (*bytes.Buffer, string, error) { +func createK8sCloudApi(req k8s_ca.CreateRequest) (*bytes.Buffer, string) { reqBody := &bytes.Buffer{} writer := multipart.NewWriter(reqBody) - values := reflect.ValueOf(params) - types := values.Type() - defer writer.Close() - for i := 0; i < values.NumField(); i++ { - if !values.Field(i).IsValid() { - continue - } + if req.OidcCertificate != "" { + part, _ := writer.CreateFormFile("oidcCertificate", "ca.crt") + _, _ = io.Copy(part, strings.NewReader(req.OidcCertificate)) + } - if values.Field(i).IsZero() { - continue - } + _ = writer.WriteField("name", req.Name) + _ = writer.WriteField("rgId", strconv.FormatUint(req.RGID, 10)) + _ = writer.WriteField("k8ciId", strconv.FormatUint(req.K8SCIID, 10)) + _ = writer.WriteField("workerGroupName", req.WorkerGroupName) + _ = writer.WriteField("networkPlugin", req.NetworkPlugin) - if file, ok := constants.FileName[types.Field(i).Name]; ok { - part, err := writer.CreateFormFile(trimString(types.Field(i)), file) - if err != nil { - return &bytes.Buffer{}, "", err - } - _, err = io.Copy(part, strings.NewReader(valueToString(values.Field(i).Interface()))) - if err != nil { - return &bytes.Buffer{}, "", err - } - continue - } + if req.MasterSEPID != 0 { + _ = writer.WriteField("masterSepId", strconv.FormatUint(req.MasterSEPID, 10)) + } + if req.MasterSEPPool != "" { + _ = writer.WriteField("masterSepPool", req.MasterSEPPool) + } + if req.WorkerSEPID != 0 { + _ = writer.WriteField("workerSepId", strconv.FormatUint(req.WorkerSEPID, 10)) + } + if req.WorkerSEPPool != "" { + _ = writer.WriteField("workerSepPool", req.WorkerSEPPool) + } - if values.Field(i).Type().Kind() == reflect.Slice { - switch slice := values.Field(i).Interface().(type) { - case []string: - for _, val := range slice { - err := writer.WriteField(trimString(types.Field(i)), val) - if err != nil { - return &bytes.Buffer{}, "", err - } - } - case []uint: - for _, val := range slice { - err := writer.WriteField(trimString(types.Field(i)), strconv.FormatUint(uint64(val), 10)) - if err != nil { - return &bytes.Buffer{}, "", err - } - } - case []uint64: - for _, val := range slice { - err := writer.WriteField(trimString(types.Field(i)), strconv.FormatUint(val, 10)) - if err != nil { - return &bytes.Buffer{}, "", err - } - } - default: - return &bytes.Buffer{}, "", fmt.Errorf("unsupported slice type:%T", slice) - } - - continue + if req.Labels != nil { + for _, v := range req.Labels { + _ = writer.WriteField("labels", v) + } + } + if req.Taints != nil { + for _, v := range req.Taints { + _ = writer.WriteField("taints", v) } + } + if req.Annotations != nil { + for _, v := range req.Annotations { + _ = writer.WriteField("annotations", v) + } + } - err := writer.WriteField(trimString(types.Field(i)), valueToString(values.Field(i).Interface())) - if err != nil { - return &bytes.Buffer{}, "", err + if req.MasterCPU != 0 { + _ = writer.WriteField("masterCpu", strconv.FormatUint(uint64(req.MasterCPU), 10)) + } + if req.MasterNum != 0 { + _ = writer.WriteField("masterNum", strconv.FormatUint(uint64(req.MasterNum), 10)) + } + if req.MasterRAM != 0 { + _ = writer.WriteField("masterRam", strconv.FormatUint(uint64(req.MasterRAM), 10)) + } + if req.MasterDisk != 0 { + _ = writer.WriteField("masterDisk", strconv.FormatUint(uint64(req.MasterDisk), 10)) + } + if req.WorkerCPU != 0 { + _ = writer.WriteField("workerCpu", strconv.FormatUint(uint64(req.WorkerCPU), 10)) + } + if req.WorkerNum != 0 { + _ = writer.WriteField("workerNum", strconv.FormatUint(uint64(req.WorkerNum), 10)) + } + if req.WorkerRAM != 0 { + _ = writer.WriteField("workerRam", strconv.FormatUint(uint64(req.WorkerRAM), 10)) + } + if req.WorkerDisk != 0 { + _ = writer.WriteField("workerDisk", strconv.FormatUint(uint64(req.WorkerDisk), 10)) + } + if req.ExtNetID != 0 { + _ = writer.WriteField("extnetId", strconv.FormatUint(req.ExtNetID, 10)) + } + if req.VinsId != 0 { + _ = writer.WriteField("vinsId", strconv.FormatUint(req.VinsId, 10)) + } + if !req.WithLB { + _ = writer.WriteField("withLB", strconv.FormatBool(req.WithLB)) + } + + _ = writer.WriteField("highlyAvailableLB", strconv.FormatBool(req.HighlyAvailable)) + + if req.AdditionalSANs != nil { + for _, v := range req.AdditionalSANs { + _ = writer.WriteField("additionalSANs", v) } } + if req.InitConfiguration != "" { + _ = writer.WriteField("initConfiguration", req.InitConfiguration) + } + if req.ClusterConfiguration != "" { + _ = writer.WriteField("clusterConfiguration", req.ClusterConfiguration) + } + if req.KubeletConfiguration != "" { + _ = writer.WriteField("kubeletConfiguration", req.KubeletConfiguration) + } + if req.KubeProxyConfiguration != "" { + _ = writer.WriteField("kubeProxyConfiguration", req.KubeProxyConfiguration) + } + if req.JoinConfiguration != "" { + _ = writer.WriteField("joinConfiguration", req.JoinConfiguration) + } + if req.Description != "" { + _ = writer.WriteField("desc", req.Description) + } + if req.UserData != "" { + _ = writer.WriteField("userData", req.UserData) + } + + _ = writer.WriteField("extnetOnly", strconv.FormatBool(req.ExtNetOnly)) + ct := writer.FormDataContentType() - return reqBody, ct, nil + writer.Close() + + return reqBody, ct } -func valueToString(a any) string { - switch str := a.(type) { - case string: - return str - case uint: - return strconv.FormatUint(uint64(str), 10) - case uint64: - return strconv.FormatUint(str, 10) - case bool: - return strconv.FormatBool(str) - default: - return "" +func createK8sCloudBroker(req k8s_cb.CreateRequest) (*bytes.Buffer, string) { + reqBody := &bytes.Buffer{} + writer := multipart.NewWriter(reqBody) + if req.OidcCertificate != "" { + part, _ := writer.CreateFormFile("oidcCertificate", "ca.crt") + _, _ = io.Copy(part, strings.NewReader(req.OidcCertificate)) } -} -func trimString(el reflect.StructField) string { - return strings.TrimSuffix(el.Tag.Get("url"), ",omitempty") + _ = writer.WriteField("name", req.Name) + _ = writer.WriteField("rgId", strconv.FormatUint(req.RGID, 10)) + _ = writer.WriteField("k8ciId", strconv.FormatUint(req.K8CIID, 10)) + _ = writer.WriteField("workerGroupName", req.WorkerGroupName) + _ = writer.WriteField("networkPlugin", req.NetworkPlugin) + + if req.MasterSEPID != 0 { + _ = writer.WriteField("masterSepId", strconv.FormatUint(req.MasterSEPID, 10)) + } + if req.MasterSEPPool != "" { + _ = writer.WriteField("masterSepPool", req.MasterSEPPool) + } + if req.WorkerSEPID != 0 { + _ = writer.WriteField("workerSepId", strconv.FormatUint(req.WorkerSEPID, 10)) + } + if req.WorkerSEPPool != "" { + _ = writer.WriteField("workerSepPool", req.WorkerSEPPool) + } + + if req.Labels != nil { + for _, v := range req.Labels { + _ = writer.WriteField("labels", v) + } + } + if req.Taints != nil { + for _, v := range req.Taints { + _ = writer.WriteField("taints", v) + } + } + if req.Annotations != nil { + for _, v := range req.Annotations { + _ = writer.WriteField("annotations", v) + } + } + + if req.MasterCPU != 0 { + _ = writer.WriteField("masterCpu", strconv.FormatUint(req.MasterCPU, 10)) + } + if req.MasterNum != 0 { + _ = writer.WriteField("masterNum", strconv.FormatUint(req.MasterNum, 10)) + } + if req.MasterRAM != 0 { + _ = writer.WriteField("masterRam", strconv.FormatUint(req.MasterRAM, 10)) + } + if req.MasterDisk != 0 { + _ = writer.WriteField("masterDisk", strconv.FormatUint(req.MasterDisk, 10)) + } + if req.WorkerCPU != 0 { + _ = writer.WriteField("workerCpu", strconv.FormatUint(req.WorkerCPU, 10)) + } + if req.WorkerNum != 0 { + _ = writer.WriteField("workerNum", strconv.FormatUint(req.WorkerNum, 10)) + } + if req.WorkerRAM != 0 { + _ = writer.WriteField("workerRam", strconv.FormatUint(req.WorkerRAM, 10)) + } + if req.WorkerDisk != 0 { + _ = writer.WriteField("workerDisk", strconv.FormatUint(req.WorkerDisk, 10)) + } + if req.ExtNetID != 0 { + _ = writer.WriteField("extnetId", strconv.FormatUint(req.ExtNetID, 10)) + } + if req.VinsId != 0 { + _ = writer.WriteField("vinsId", strconv.FormatUint(req.VinsId, 10)) + } + if !req.WithLB { + _ = writer.WriteField("withLB", strconv.FormatBool(req.WithLB)) + } + + _ = writer.WriteField("highlyAvailableLB", strconv.FormatBool(req.HighlyAvailable)) + + if req.AdditionalSANs != nil { + for _, v := range req.AdditionalSANs { + _ = writer.WriteField("additionalSANs", v) + } + } + if req.InitConfiguration != "" { + _ = writer.WriteField("initConfiguration", req.InitConfiguration) + } + if req.ClusterConfiguration != "" { + _ = writer.WriteField("clusterConfiguration", req.ClusterConfiguration) + } + if req.KubeletConfiguration != "" { + _ = writer.WriteField("kubeletConfiguration", req.KubeletConfiguration) + } + if req.KubeProxyConfiguration != "" { + _ = writer.WriteField("kubeProxyConfiguration", req.KubeProxyConfiguration) + } + if req.JoinConfiguration != "" { + _ = writer.WriteField("joinConfiguration", req.JoinConfiguration) + } + if req.Description != "" { + _ = writer.WriteField("desc", req.Description) + } + if req.UserData != "" { + _ = writer.WriteField("userData", req.UserData) + } + + _ = writer.WriteField("extnetOnly", strconv.FormatBool(req.ExtNetOnly)) + + ct := writer.FormDataContentType() + + writer.Close() + return reqBody, ct } diff --git a/client_bvs.go b/client_bvs.go deleted file mode 100644 index 80c449c..0000000 --- a/client_bvs.go +++ /dev/null @@ -1,380 +0,0 @@ -package decortsdk - -import ( - "bytes" - "context" - "crypto/tls" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "strings" - "sync" - "time" - - "github.com/google/go-querystring/query" - "repository.basistech.ru/BASIS/decort-golang-sdk/config" - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" - "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi" - "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker" -) - -// BVSDecortClient is HTTP-client for platform -type BVSDecortClient struct { - client *http.Client - cfg config.BVSConfig - mutex *sync.Mutex - decortURL string -} - -type tokenJSON struct { - AccessToken string `json:"access_token"` - TokenType string `json:"token_type"` - RefreshToken string `json:"refresh_token"` - ExpiresIn uint64 `json:"expires_in"` -} - -// Сlient builder -func NewBVS(cfg config.BVSConfig) *BVSDecortClient { - if cfg.Retries == 0 { - cfg.Retries = 5 - } - if cfg.TimeToRefresh == 0 { - cfg.TimeToRefresh = 1 - } - - return &BVSDecortClient{ - decortURL: cfg.DecortURL, - client: &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - //nolint:gosec - InsecureSkipVerify: cfg.SSLSkipVerify, - }, - }, - }, - cfg: cfg, - mutex: &sync.Mutex{}, - } -} - -// CloudAPI builder -func (bdc *BVSDecortClient) CloudAPI() *cloudapi.CloudAPI { - return cloudapi.New(bdc) -} - -// CloudBroker builder -func (bdc *BVSDecortClient) CloudBroker() *cloudbroker.CloudBroker { - return cloudbroker.New(bdc) -} - -// DecortApiCall method for sending requests to the platform -func (bdc *BVSDecortClient) DecortApiCall(ctx context.Context, method, url string, params interface{}) ([]byte, error) { - values, err := query.Values(params) - if err != nil { - return nil, err - } - - body := bytes.NewBufferString(values.Encode()) - - req, err := http.NewRequestWithContext(ctx, method, bdc.decortURL+constants.Restmachine+url, body) - if err != nil { - return nil, err - } - - // get token - if bdc.cfg.Token.AccessToken == "" { - if _, err = bdc.GetToken(ctx); err != nil { - return nil, err - } - } - - // refresh token - if bdc.cfg.Token.RefreshToken != "" && bdc.cfg.Token.Expiry.Add(-time.Duration(bdc.cfg.TimeToRefresh)*time.Minute).Before(time.Now()) { - if _, err := bdc.RefreshToken(ctx); err != nil { - if _, err = bdc.GetToken(ctx); err != nil { - return nil, err - } - } - } - - // perform request - reqCopy := req.Clone(ctx) - respBytes, err := bdc.do(req, "") - if err == nil { - return respBytes, nil - } - - // get token and retry in case of access denied - if err.Error() == "access is denied" { - _, err = bdc.GetToken(ctx) - if err != nil { - return nil, err - } - - respBytes, err = bdc.do(reqCopy, "") - if err != nil { - return nil, err - } - } - - return respBytes, err -} - -func (bdc *BVSDecortClient) DecortApiCallMP(ctx context.Context, method, url string, params interface{}) ([]byte, error) { - body, ctype, err := multiPartReq(params) - if err != nil { - return nil, err - } - - req, err := http.NewRequestWithContext(ctx, method, bdc.decortURL+constants.Restmachine+url, body) - if err != nil { - return nil, err - } - - // get token - if bdc.cfg.Token.AccessToken == "" { - if _, err = bdc.GetToken(ctx); err != nil { - return nil, err - } - } - - // refresh token - if bdc.cfg.Token.RefreshToken != "" && bdc.cfg.Token.Expiry.Add(-time.Duration(bdc.cfg.TimeToRefresh)*time.Minute).Before(time.Now()) { - if _, err := bdc.RefreshToken(ctx); err != nil { - if _, err = bdc.GetToken(ctx); err != nil { - return nil, err - } - } - } - - // perform request - reqCopy := req.Clone(ctx) - respBytes, err := bdc.do(req, ctype) - if err == nil { - return respBytes, nil - } - - // get token and retry in case of access denied - if err.Error() == "access is denied" { - _, err = bdc.GetToken(ctx) - if err != nil { - return nil, err - } - - respBytes, err = bdc.do(reqCopy, ctype) - if err != nil { - return nil, err - } - } - return respBytes, err -} - -// GetToken allows you to get a token and returns the token structure. When specifying the PathCfg variable, -// the token and configuration will be written to a file. -// When specifying the PathToken variable, the token will be written to a file. -func (bdc *BVSDecortClient) GetToken(ctx context.Context) (config.Token, error) { - bdc.mutex.Lock() - defer bdc.mutex.Unlock() - - // set up request headers and body - body := fmt.Sprintf("grant_type=password&client_id=%s&client_secret=%s&username=%s&password=%s&response_type=token&scope=openid", bdc.cfg.AppID, bdc.cfg.AppSecret, bdc.cfg.Username, bdc.cfg.Password) - bodyReader := strings.NewReader(body) - - bdc.cfg.SSOURL = strings.TrimSuffix(bdc.cfg.SSOURL, "/") - - req, _ := http.NewRequestWithContext(ctx, "POST", bdc.cfg.SSOURL+"/realms/"+bdc.cfg.Domain+"/protocol/openid-connect/token", bodyReader) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - - // request token - resp, err := bdc.client.Do(req) - if err != nil || resp == nil { - return config.Token{}, fmt.Errorf("cannot get token: %w", err) - } - defer resp.Body.Close() - - var tokenBytes []byte - tokenBytes, err = io.ReadAll(resp.Body) - if err != nil { - return config.Token{}, fmt.Errorf("cannot get token: %w", err) - } - - if resp.StatusCode != 200 { - return config.Token{}, fmt.Errorf("cannot get token: %s", tokenBytes) - } - - // save token in config - var tj tokenJSON - if err = json.Unmarshal(tokenBytes, &tj); err != nil { - return config.Token{}, fmt.Errorf("cannot unmarshal token: %w", err) - } - - bdc.cfg.Token = config.Token{ - AccessToken: tj.AccessToken, - TokenType: tj.TokenType, - RefreshToken: tj.RefreshToken, - Expiry: tj.expiry(), - } - - if bdc.cfg.PathCfg != "" { - ser, _ := bdc.cfg.Serialize("", " ") - _ = ser.WriteToFile(bdc.cfg.PathCfg) - } - - if bdc.cfg.PathToken != "" { - ser, _ := bdc.cfg.Token.Serialize("", " ") - _ = ser.WriteToFile(bdc.cfg.PathToken) - } - - return bdc.cfg.Token, nil -} - -// RefreshToken allows you to refresh a token and returns the token structure. When specifying the PathCfg variable, -// the token and configuration will be written to a file. -// When specifying the PathToken variable, the token will be written to a file -func (bdc *BVSDecortClient) RefreshToken(ctx context.Context) (config.Token, error) { - bdc.mutex.Lock() - defer bdc.mutex.Unlock() - - // set up request headers and body - body := fmt.Sprintf("grant_type=refresh_token&client_id=%s&client_secret=%s&refresh_token=%s&scope=openid", bdc.cfg.AppID, bdc.cfg.AppSecret, bdc.cfg.Token.RefreshToken) - bodyReader := strings.NewReader(body) - - bdc.cfg.SSOURL = strings.TrimSuffix(bdc.cfg.SSOURL, "/") - - req, _ := http.NewRequestWithContext(ctx, "POST", bdc.cfg.SSOURL+"/realms/"+bdc.cfg.Domain+"/protocol/openid-connect/token", bodyReader) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - - // refresh token - resp, err := bdc.client.Do(req) - if err != nil || resp == nil { - return config.Token{}, fmt.Errorf("cannot refresh token: %w", err) - } - defer resp.Body.Close() - - var tokenBytes []byte - tokenBytes, err = io.ReadAll(resp.Body) - if err != nil { - return config.Token{}, fmt.Errorf("cannot refresh token: %w", err) - } - - if resp.StatusCode != 200 { - return config.Token{}, fmt.Errorf("cannot refresh token: %s", tokenBytes) - } - - // save token in config - var tj tokenJSON - if err = json.Unmarshal(tokenBytes, &tj); err != nil { - return config.Token{}, fmt.Errorf("cannot unmarshal after refresh token: %w", err) - } - - bdc.cfg.Token = config.Token{ - AccessToken: tj.AccessToken, - TokenType: tj.TokenType, - RefreshToken: tj.RefreshToken, - Expiry: tj.expiry(), - } - - if bdc.cfg.PathCfg != "" { - ser, _ := bdc.cfg.Serialize("", " ") - _ = ser.WriteToFile(bdc.cfg.PathCfg) - } - - if bdc.cfg.PathToken != "" { - ser, _ := bdc.cfg.Token.Serialize("", " ") - _ = ser.WriteToFile(bdc.cfg.PathToken) - } - - return bdc.cfg.Token, nil -} - -func (e *tokenJSON) expiry() (t time.Time) { - if v := e.ExpiresIn; v != 0 { - return time.Now().Add(time.Duration(v) * time.Second) - } - return -} - -// do method performs request and returns response as an array of bytes and nil error in case of response status code 200. -// In any other cases do returns nil response and error. -// Retries are implemented in case of connection reset errors. -func (bdc *BVSDecortClient) do(req *http.Request, ctype string) ([]byte, error) { - // set up request headers and body - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - if ctype != "" { - req.Header.Set("Content-Type", ctype) - } - - req.Header.Add("Authorization", "bearer "+bdc.cfg.Token.AccessToken) - req.Header.Set("Accept", "application/json") - - buf, err := io.ReadAll(req.Body) - if err != nil { - return nil, err - } - - req.Body.Close() - req.Body = io.NopCloser(bytes.NewBuffer(buf)) - - resp, err := bdc.client.Do(req) - if resp != nil { - defer resp.Body.Close() - } - - // retries logic GOES HERE - // get http response - //var resp *http.Response - //for i := uint64(0); i < bdc.cfg.Retries; i++ { - // req := req.Clone(req.Context()) - // req.Body = io.NopCloser(bytes.NewBuffer(buf)) - // - // if i > 0 { - // time.Sleep(5 * time.Second) // no time sleep for the first request - // } - // - // resp, err = bdc.client.Do(req) - // - // // stop retries on success and close response body - // if resp != nil { - // defer resp.Body.Close() - // } - // if err == nil { - // break - // } - // - // // retries in case of connection errors with time sleep - // if isConnectionError(err) { - // continue - // } - // - // // return error in case of non-connection error - // return nil, err - //} - - // handle http request errors - if err != nil { - return nil, err - } - if resp == nil { - return nil, fmt.Errorf("got empty response without error") - } - - var respBytes []byte - respBytes, err = io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - // handle access denied and successful request - if resp.StatusCode == 401 { - return respBytes, errors.New("access is denied") - } - if resp.StatusCode == 200 { - return respBytes, nil - } - - // handle errors with other status codes - err = fmt.Errorf("%s", respBytes) - return nil, fmt.Errorf("could not execute request: %w", err) -} diff --git a/config/config_bvs.go b/config/config_bvs.go deleted file mode 100644 index 9182fcb..0000000 --- a/config/config_bvs.go +++ /dev/null @@ -1,216 +0,0 @@ -package config - -import ( - "encoding/json" - "os" - "time" - - "gopkg.in/yaml.v3" - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/serialization" - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" -) - -type BVSConfig struct { - // ServiceAccount username - // Required: true - // Example : "osh_mikoev" - Username string `json:"username" yaml:"username" validate:"required"` - - // ServiceAccount password - // Required: true - // Example: "[1o>hYkjnJr)HI78q7t&#%8Lm" - Password string `json:"password" yaml:"password" validate:"required"` - - // Domain name - // Required: true - // Example: "dynamix" - Domain string `json:"domain" yaml:"domain" validate:"required"` - - // Application (client) identifier for authorization - // in the cloud platform controller in oauth2 mode. - // Required: true - // Example: "ewqfrvea7s890avw804389qwguf234h0otfi3w4eiu" - 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 `json:"appSecret" yaml:"appSecret" validate:"required"` - - // Platform authentication service address - // Required: true - // Example: "https://sso.digitalenergy.online" - 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 `json:"decortUrl" yaml:"decortUrl" validate:"url"` - - // JWT platform token - // Required: false - // Example: "qwqwdfwv68979we0q9bfv7e9sbvd89798qrwv97ff" - Token Token `json:"token" yaml:"token"` - - // Amount platform request attempts - // Default value: 5 - // Required: false - Retries uint64 `json:"retries" yaml:"retries"` - - // Skip verify - // Required: false - SSLSkipVerify bool `json:"sslSkipVerify" yaml:"sslSkipVerify"` - - // HTTP client timeout, unlimited if left empty - // Required: false - Timeout Duration `json:"timeout" yaml:"timeout"` - - // The path of the configuration file entry - // Required: false - PathCfg string `json:"path_cfg" yaml:"path_cfg"` - - // The path of the token file entry - // Required: false - PathToken string `json:"path_token" yaml:"path_token"` - - // The number of minutes before the expiration of the token, a refresh will be made - // Required: false - TimeToRefresh int64 `json:"timeToRefresh" yaml:"timeToRefresh"` -} - -type Token struct { - // AccessToken is the token that authorizes and authenticates - // the requests. - // Required: false - AccessToken string `json:"access_token" yaml:"access_token"` - - // TokenType is the type of token. - // The Type method returns either this or "Bearer", the default. - // Required: false - TokenType string `json:"token_type" yaml:"token_type"` - - // RefreshToken is a token that's used by the application - // (as opposed to the user) to refresh the access token - // if it expires. - // Required: false - RefreshToken string `json:"refresh_token" yaml:"refresh_token"` - - // Expiry is the optional expiration time of the access token. - // Required: false - Expiry time.Time `json:"expiry" yaml:"expiry"` -} - -// SetTimeout is used to set HTTP client timeout. -func (c *BVSConfig) SetTimeout(dur time.Duration) { - c.Timeout = Duration(dur) -} - -// ParseConfigJSON parses Config from specified JSON-formatted file. -func ParseConfigBVSJSON(path string) (BVSConfig, error) { - file, err := os.ReadFile(path) - if err != nil { - return BVSConfig{}, err - } - - var config BVSConfig - - err = json.Unmarshal(file, &config) - if err != nil { - return BVSConfig{}, err - } - - err = validators.ValidateConfig(config) - if err != nil { - return BVSConfig{}, validators.ValidationErrors(validators.GetErrors(err)) - } - - return config, nil -} - -// ParseConfigJSON parses Token from specified JSON-formatted file. -func ParseTokenBVSJSON(path string) (Token, error) { - file, err := os.ReadFile(path) - if err != nil { - return Token{}, err - } - - var token Token - - err = json.Unmarshal(file, &token) - if err != nil { - return Token{}, err - } - - err = validators.ValidateConfig(token) - if err != nil { - return Token{}, validators.ValidationErrors(validators.GetErrors(err)) - } - - return token, nil -} - -// ParseTokenBVSYAML parses Token from specified YAML-formatted file. -func ParseTokenBVSYAML(path string) (Token, error) { - file, err := os.ReadFile(path) - if err != nil { - return Token{}, err - } - - var token Token - - err = yaml.Unmarshal(file, &token) - if err != nil { - return Token{}, err - } - - err = validators.ValidateConfig(token) - if err != nil { - return Token{}, validators.ValidationErrors(validators.GetErrors(err)) - } - - return token, nil -} - -// ParseConfigYAML parses Config from specified YAML-formatted file. -func ParseConfigBVSYAML(path string) (BVSConfig, error) { - file, err := os.ReadFile(path) - if err != nil { - return BVSConfig{}, err - } - - var config BVSConfig - - err = yaml.Unmarshal(file, &config) - if err != nil { - return BVSConfig{}, err - } - - err = validators.ValidateConfig(config) - if err != nil { - return BVSConfig{}, validators.ValidationErrors(validators.GetErrors(err)) - } - - return config, nil -} - -func (t Token) Serialize(params ...string) (serialization.Serialized, error) { - if len(params) > 1 { - prefix := params[0] - indent := params[1] - - return json.MarshalIndent(t, prefix, indent) - } - - return json.Marshal(t) -} - -func (c BVSConfig) Serialize(params ...string) (serialization.Serialized, error) { - if len(params) > 1 { - prefix := params[0] - indent := params[1] - - return json.MarshalIndent(c, prefix, indent) - } - - return json.Marshal(c) -} diff --git a/config/timeouts.go b/config/timeouts.go index 924158a..89a12eb 100644 --- a/config/timeouts.go +++ b/config/timeouts.go @@ -22,8 +22,6 @@ func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { } *d = Duration(tmp) return nil - case float64: - return nil default: return fmt.Errorf("invalid duration %v", value) } @@ -42,8 +40,6 @@ func (d *Duration) UnmarshalJSON(b []byte) error { } *d = Duration(tmp) return nil - case float64: - return nil default: return fmt.Errorf("invalid duration %v", value) } diff --git a/go.mod b/go.mod index 18fb1e0..beb7e0e 100644 --- a/go.mod +++ b/go.mod @@ -11,10 +11,9 @@ require ( require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/google/go-cmp v0.5.9 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.2.1 // indirect - golang.org/x/crypto v0.15.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/crypto v0.5.0 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect ) diff --git a/go.sum b/go.sum index 52f813c..a641cd7 100644 --- a/go.sum +++ b/go.sum @@ -8,9 +8,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= @@ -24,12 +23,12 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= diff --git a/interfaces/caller.go b/interfaces/caller.go index c40b0ba..82e4307 100644 --- a/interfaces/caller.go +++ b/interfaces/caller.go @@ -6,7 +6,4 @@ import "context" type Caller interface { // DecortApiCall method for sending requests to the platform DecortApiCall(ctx context.Context, method, url string, params interface{}) ([]byte, error) - - // DecortApiCallMP method for sending requests to the platform - DecortApiCallMP(ctx context.Context, method, url string, params interface{}) ([]byte, error) } diff --git a/internal/constants/constants.go b/internal/constants/constants.go deleted file mode 100644 index b48202e..0000000 --- a/internal/constants/constants.go +++ /dev/null @@ -1,7 +0,0 @@ -package constants - -const Restmachine = "/restmachine" - -var FileName = map[string]string{ - "OidcCertificate": "ca.crt", -} diff --git a/legacy-client.go b/legacy-client.go index 01293cd..07b07e4 100644 --- a/legacy-client.go +++ b/legacy-client.go @@ -6,20 +6,23 @@ import ( "crypto/tls" "fmt" "io" + "mime/multipart" "net/http" "net/url" + "strconv" "strings" "sync" "time" "github.com/google/go-querystring/query" "repository.basistech.ru/BASIS/decort-golang-sdk/config" - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi" + k8s_ca "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8s" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker" + k8s_cb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8s" ) -// LegacyDecortClient is Legacy HTTP-client for platform +// Legacy HTTP-client for platform type LegacyDecortClient struct { decortURL string client *http.Client @@ -68,168 +71,334 @@ func (ldc *LegacyDecortClient) CloudBroker() *cloudbroker.CloudBroker { // DecortApiCall method for sending requests to the platform func (ldc *LegacyDecortClient) DecortApiCall(ctx context.Context, method, url string, params interface{}) ([]byte, error) { - // get token if err := ldc.getToken(ctx); err != nil { return nil, err } - values, err := query.Values(params) - if err != nil { - return nil, err + k8sCaCreateReq, okCa := params.(k8s_ca.CreateRequest) + k8sCbCreateReq, okCb := params.(k8s_cb.CreateRequest) + + var body *bytes.Buffer + var ctype string + + if okCa { + body, ctype = createK8sCloudApiLegacy(k8sCaCreateReq, ldc.cfg.Token) + } else if okCb { + body, ctype = createK8sCloudBrokerLegacy(k8sCbCreateReq, ldc.cfg.Token) + } else { + values, err := query.Values(params) + if err != nil { + return nil, err + } + body = bytes.NewBufferString(values.Encode() + fmt.Sprintf("&authkey=%s", ldc.cfg.Token)) } - body := bytes.NewBufferString(values.Encode() + fmt.Sprintf("&authkey=%s", ldc.cfg.Token)) - - req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+constants.Restmachine+url, body) + req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+"/restmachine"+url, body) if err != nil { return nil, err } // perform request - respBytes, err := ldc.do(req, "") - if err != nil { - return nil, err - } + var respBytes []byte + respBytes, err = ldc.do(req, ctype) return respBytes, err } -func (ldc *LegacyDecortClient) DecortApiCallMP(ctx context.Context, method, url string, params interface{}) ([]byte, error) { - body, ctype, err := multiPartReq(params) - if err != nil { - return nil, err +func (ldc *LegacyDecortClient) getToken(ctx context.Context) error { + ldc.mutex.Lock() + defer ldc.mutex.Unlock() + + if ldc.cfg.Token == "" || time.Now().After(ldc.expiryTime) { + body := fmt.Sprintf("username=%s&password=%s", url.QueryEscape(ldc.cfg.Username), url.QueryEscape(ldc.cfg.Password)) + bodyReader := strings.NewReader(body) + + req, _ := http.NewRequestWithContext(ctx, "POST", ldc.cfg.DecortURL+"/restmachine/cloudapi/user/authenticate", bodyReader) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + resp, err := ldc.client.Do(req) + if err != nil { + return fmt.Errorf("unable to get token: %w", err) + } + + tokenBytes, _ := io.ReadAll(resp.Body) + resp.Body.Close() + + if resp.StatusCode != 200 { + return fmt.Errorf("unable to get token: %s", tokenBytes) + } + + token := string(tokenBytes) + ldc.cfg.Token = token + ldc.expiryTime = time.Now().AddDate(0, 0, 1) } - req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+constants.Restmachine+url, body) + return nil +} + +func (ldc *LegacyDecortClient) do(req *http.Request, ctype string) ([]byte, error) { + if ctype != "" { + req.Header.Add("Content-Type", ctype) + } else { + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + } + req.Header.Set("Accept", "application/json") + + buf, err := io.ReadAll(req.Body) if err != nil { return nil, err } + req.Body.Close() + req.Body = io.NopCloser(bytes.NewBuffer(buf)) - // get token - if err = ldc.getToken(ctx); err != nil { + resp, err := ldc.client.Do(req) + if err != nil || resp == nil { return nil, err } + defer resp.Body.Close() - // perform request - respBytes, err := ldc.do(req, ctype) + // handle successful request + respBytes, err := io.ReadAll(resp.Body) if err != nil { return nil, err } + if resp.StatusCode == 200 { + return respBytes, nil + } - return respBytes, err + // handle errors with status code other than 200 + err = fmt.Errorf("%s", respBytes) + return nil, fmt.Errorf("could not execute request: %w", err) } -func (ldc *LegacyDecortClient) getToken(ctx context.Context) error { - ldc.mutex.Lock() - defer ldc.mutex.Unlock() - - // new token is not needed - if ldc.cfg.Token != "" && !time.Now().After(ldc.expiryTime) { - return nil +func createK8sCloudApiLegacy(req k8s_ca.CreateRequest, token string) (*bytes.Buffer, string) { + reqBody := &bytes.Buffer{} + writer := multipart.NewWriter(reqBody) + if req.OidcCertificate != "" { + part, _ := writer.CreateFormFile("oidcCertificate", "ca.crt") + _, _ = io.Copy(part, strings.NewReader(req.OidcCertificate)) } - // set up request headers and body - body := fmt.Sprintf("username=%s&password=%s", url.QueryEscape(ldc.cfg.Username), url.QueryEscape(ldc.cfg.Password)) - bodyReader := strings.NewReader(body) + _ = writer.WriteField("name", req.Name) + _ = writer.WriteField("rgId", strconv.FormatUint(req.RGID, 10)) + _ = writer.WriteField("k8ciId", strconv.FormatUint(req.K8SCIID, 10)) + _ = writer.WriteField("workerGroupName", req.WorkerGroupName) + _ = writer.WriteField("networkPlugin", req.NetworkPlugin) - req, _ := http.NewRequestWithContext(ctx, "POST", ldc.cfg.DecortURL+"/restmachine/cloudapi/user/authenticate", bodyReader) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + if req.MasterSEPID != 0 { + _ = writer.WriteField("masterSepId", strconv.FormatUint(req.MasterSEPID, 10)) + } + if req.MasterSEPPool != "" { + _ = writer.WriteField("masterSepPool", req.MasterSEPPool) + } + if req.WorkerSEPID != 0 { + _ = writer.WriteField("workerSepId", strconv.FormatUint(req.WorkerSEPID, 10)) + } + if req.WorkerSEPPool != "" { + _ = writer.WriteField("workerSepPool", req.WorkerSEPPool) + } - // request token - resp, err := ldc.client.Do(req) - if err != nil || resp == nil { - return fmt.Errorf("cannot get token: %w", err) + if req.Labels != nil { + for _, v := range req.Labels { + _ = writer.WriteField("labels", v) + } + } + if req.Taints != nil { + for _, v := range req.Taints { + _ = writer.WriteField("taints", v) + } + } + if req.Annotations != nil { + for _, v := range req.Annotations { + _ = writer.WriteField("annotations", v) + } } - defer resp.Body.Close() - var tokenBytes []byte - tokenBytes, err = io.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("cannot get token: %w", err) + if req.MasterCPU != 0 { + _ = writer.WriteField("masterCpu", strconv.FormatUint(uint64(req.MasterCPU), 10)) + } + if req.MasterNum != 0 { + _ = writer.WriteField("masterNum", strconv.FormatUint(uint64(req.MasterNum), 10)) + } + if req.MasterRAM != 0 { + _ = writer.WriteField("masterRam", strconv.FormatUint(uint64(req.MasterRAM), 10)) + } + if req.MasterDisk != 0 { + _ = writer.WriteField("masterDisk", strconv.FormatUint(uint64(req.MasterDisk), 10)) + } + if req.WorkerCPU != 0 { + _ = writer.WriteField("workerCpu", strconv.FormatUint(uint64(req.WorkerCPU), 10)) + } + if req.WorkerNum != 0 { + _ = writer.WriteField("workerNum", strconv.FormatUint(uint64(req.WorkerNum), 10)) } + if req.WorkerRAM != 0 { + _ = writer.WriteField("workerRam", strconv.FormatUint(uint64(req.WorkerRAM), 10)) + } + if req.WorkerDisk != 0 { + _ = writer.WriteField("workerDisk", strconv.FormatUint(uint64(req.WorkerDisk), 10)) + } + if req.ExtNetID != 0 { + _ = writer.WriteField("extnetId", strconv.FormatUint(req.ExtNetID, 10)) + } + if req.VinsId != 0 { + _ = writer.WriteField("vinsId", strconv.FormatUint(req.VinsId, 10)) + } + if !req.WithLB { + _ = writer.WriteField("withLB", strconv.FormatBool(req.WithLB)) + } + + _ = writer.WriteField("highlyAvailableLB", strconv.FormatBool(req.HighlyAvailable)) - if resp.StatusCode != 200 { - return fmt.Errorf("cannot get token: %s", tokenBytes) + if req.AdditionalSANs != nil { + for _, v := range req.AdditionalSANs { + _ = writer.WriteField("additionalSANs", v) + } + } + if req.InitConfiguration != "" { + _ = writer.WriteField("initConfiguration", req.InitConfiguration) + } + if req.ClusterConfiguration != "" { + _ = writer.WriteField("clusterConfiguration", req.ClusterConfiguration) + } + if req.KubeletConfiguration != "" { + _ = writer.WriteField("kubeletConfiguration", req.KubeletConfiguration) + } + if req.KubeProxyConfiguration != "" { + _ = writer.WriteField("kubeProxyConfiguration", req.KubeProxyConfiguration) + } + if req.JoinConfiguration != "" { + _ = writer.WriteField("joinConfiguration", req.JoinConfiguration) + } + if req.Description != "" { + _ = writer.WriteField("desc", req.Description) + } + if req.UserData != "" { + _ = writer.WriteField("userData", req.UserData) } - // save token in config - token := string(tokenBytes) - ldc.cfg.Token = token - ldc.expiryTime = time.Now().AddDate(0, 0, 1) + _ = writer.WriteField("extnetOnly", strconv.FormatBool(req.ExtNetOnly)) - return nil + _ = writer.WriteField("authkey", token) + + ct := writer.FormDataContentType() + writer.Close() + + return reqBody, ct } -// do method performs request and returns response as an array of bytes and nil error in case of response status code 200. -// In any other cases do returns nil response and error. -// Retries are implemented in case of connection reset errors. -func (ldc *LegacyDecortClient) do(req *http.Request, ctype string) ([]byte, error) { - // set up request headers and body - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - if ctype != "" { - req.Header.Set("Content-Type", ctype) +func createK8sCloudBrokerLegacy(req k8s_cb.CreateRequest, token string) (*bytes.Buffer, string) { + reqBody := &bytes.Buffer{} + writer := multipart.NewWriter(reqBody) + if req.OidcCertificate != "" { + part, _ := writer.CreateFormFile("oidcCertificate", "ca.crt") + _, _ = io.Copy(part, strings.NewReader(req.OidcCertificate)) } - req.Header.Set("Accept", "application/json") + _ = writer.WriteField("name", req.Name) + _ = writer.WriteField("rgId", strconv.FormatUint(req.RGID, 10)) + _ = writer.WriteField("k8ciId", strconv.FormatUint(req.K8CIID, 10)) + _ = writer.WriteField("workerGroupName", req.WorkerGroupName) + _ = writer.WriteField("networkPlugin", req.NetworkPlugin) - buf, err := io.ReadAll(req.Body) - if err != nil { - return nil, err + if req.MasterSEPID != 0 { + _ = writer.WriteField("masterSepId", strconv.FormatUint(req.MasterSEPID, 10)) + } + if req.MasterSEPPool != "" { + _ = writer.WriteField("masterSepPool", req.MasterSEPPool) + } + if req.WorkerSEPID != 0 { + _ = writer.WriteField("workerSepId", strconv.FormatUint(req.WorkerSEPID, 10)) + } + if req.WorkerSEPPool != "" { + _ = writer.WriteField("workerSepPool", req.WorkerSEPPool) } - req.Body.Close() - req.Body = io.NopCloser(bytes.NewBuffer(buf)) + if req.Labels != nil { + for _, v := range req.Labels { + _ = writer.WriteField("labels", v) + } + } + if req.Taints != nil { + for _, v := range req.Taints { + _ = writer.WriteField("taints", v) + } + } + if req.Annotations != nil { + for _, v := range req.Annotations { + _ = writer.WriteField("annotations", v) + } + } - resp, err := ldc.client.Do(req) - if resp != nil { - defer resp.Body.Close() - } - - // retries logic GOES HERE - // get http response - //var resp *http.Response - //for i := uint64(0); i < ldc.cfg.Retries; i++ { - // req := req.Clone(req.Context()) - // req.Body = io.NopCloser(bytes.NewBuffer(buf)) - // - // if i > 0 { - // time.Sleep(5 * time.Second) // no time sleep for the first request - // } - // - // resp, err = ldc.client.Do(req) - // - // // stop retries on success and close response body - // if resp != nil { - // defer resp.Body.Close() - // } - // if err == nil { - // break - // } - // - // // retries in case of connection errors with time sleep - // if isConnectionError(err) { - // continue - // } - // - // // return error in case of non-connection error - // return nil, err - //} - - // handle http request errors - if err != nil { - return nil, err + if req.MasterCPU != 0 { + _ = writer.WriteField("masterCpu", strconv.FormatUint(req.MasterCPU, 10)) + } + if req.MasterNum != 0 { + _ = writer.WriteField("masterNum", strconv.FormatUint(req.MasterNum, 10)) + } + if req.MasterRAM != 0 { + _ = writer.WriteField("masterRam", strconv.FormatUint(req.MasterRAM, 10)) + } + if req.MasterDisk != 0 { + _ = writer.WriteField("masterDisk", strconv.FormatUint(req.MasterDisk, 10)) + } + if req.WorkerCPU != 0 { + _ = writer.WriteField("workerCpu", strconv.FormatUint(req.WorkerCPU, 10)) + } + if req.WorkerNum != 0 { + _ = writer.WriteField("workerNum", strconv.FormatUint(req.WorkerNum, 10)) } - if resp == nil { - return nil, fmt.Errorf("got empty response without error") + if req.WorkerRAM != 0 { + _ = writer.WriteField("workerRam", strconv.FormatUint(req.WorkerRAM, 10)) + } + if req.WorkerDisk != 0 { + _ = writer.WriteField("workerDisk", strconv.FormatUint(req.WorkerDisk, 10)) + } + if req.ExtNetID != 0 { + _ = writer.WriteField("extnetId", strconv.FormatUint(req.ExtNetID, 10)) + } + if req.VinsId != 0 { + _ = writer.WriteField("vinsId", strconv.FormatUint(req.VinsId, 10)) + } + if !req.WithLB { + _ = writer.WriteField("withLB", strconv.FormatBool(req.WithLB)) } - // handle successful request - respBytes, _ := io.ReadAll(resp.Body) - if resp.StatusCode == 200 { - return respBytes, nil + _ = writer.WriteField("highlyAvailableLB", strconv.FormatBool(req.HighlyAvailable)) + + if req.AdditionalSANs != nil { + for _, v := range req.AdditionalSANs { + _ = writer.WriteField("additionalSANs", v) + } + } + if req.InitConfiguration != "" { + _ = writer.WriteField("initConfiguration", req.InitConfiguration) + } + if req.ClusterConfiguration != "" { + _ = writer.WriteField("clusterConfiguration", req.ClusterConfiguration) + } + if req.KubeletConfiguration != "" { + _ = writer.WriteField("kubeletConfiguration", req.KubeletConfiguration) + } + if req.KubeProxyConfiguration != "" { + _ = writer.WriteField("kubeProxyConfiguration", req.KubeProxyConfiguration) + } + if req.JoinConfiguration != "" { + _ = writer.WriteField("joinConfiguration", req.JoinConfiguration) + } + if req.Description != "" { + _ = writer.WriteField("desc", req.Description) + } + if req.UserData != "" { + _ = writer.WriteField("userData", req.UserData) } - // handle errors with status code other than 200 - err = fmt.Errorf("%s", respBytes) - return nil, fmt.Errorf("could not execute request: %w", err) + _ = writer.WriteField("extnetOnly", strconv.FormatBool(req.ExtNetOnly)) + + _ = writer.WriteField("authkey", token) + + ct := writer.FormDataContentType() + + writer.Close() + return reqBody, ct } diff --git a/pkg/cloudapi/bservice/disable.go b/pkg/cloudapi/bservice/disable.go index f19faf0..a17eb32 100644 --- a/pkg/cloudapi/bservice/disable.go +++ b/pkg/cloudapi/bservice/disable.go @@ -24,7 +24,7 @@ func (b BService) Disable(ctx context.Context, req DisableRequest) (bool, error) return false, validators.ValidationErrors(validators.GetErrors(err)) } - url := "/cloudapi/bservice/delete" + url := "/cloudapi/bservice/disable" res, err := b.client.DecortApiCall(ctx, http.MethodPost, url, req) if err != nil { diff --git a/pkg/cloudapi/bservice/models.go b/pkg/cloudapi/bservice/models.go index ab50f75..7d6c0a6 100644 --- a/pkg/cloudapi/bservice/models.go +++ b/pkg/cloudapi/bservice/models.go @@ -93,7 +93,7 @@ type RecordBasicService struct { // Main information about Compute type ItemCompute struct { // Account ID - AccountID uint64 `json:"accountId"` + AccountID uint64 // Architecture Architecture string `json:"arch"` @@ -168,9 +168,6 @@ type ItemSnapshot struct { Valid bool `json:"valid"` } -// List of Snapshot -type ListSnapshots []ItemSnapshot - // List of Snapshots type ListInfoSnapshots struct { // Data @@ -180,6 +177,9 @@ type ListInfoSnapshots struct { EntryCount uint64 `json:"entryCount"` } +// List of Snapshots inside RecordBasicService +type ListSnapshots []ItemSnapshot + // Main information about Group type RecordGroup struct { // Account ID diff --git a/pkg/cloudapi/compute/models.go b/pkg/cloudapi/compute/models.go index 39ea486..e7000bb 100644 --- a/pkg/cloudapi/compute/models.go +++ b/pkg/cloudapi/compute/models.go @@ -380,9 +380,6 @@ type RecordCompute struct { // Name Name string `json:"name"` - // NeedReboot - NeedReboot bool `json:"needReboot"` - // Natable VINS ID NatableVINSID uint64 `json:"natableVinsId"` @@ -860,9 +857,6 @@ type ItemCompute struct { // Name Name string `json:"name"` - // NeedReboot - NeedReboot bool `json:"needReboot"` - // Pinned or not Pinned bool `json:"pinned"` diff --git a/pkg/cloudapi/image/get.go b/pkg/cloudapi/image/get.go index 1b86fce..c530ee4 100644 --- a/pkg/cloudapi/image/get.go +++ b/pkg/cloudapi/image/get.go @@ -16,7 +16,7 @@ type GetRequest struct { // If set to False returns only images in status CREATED // Required: false - ShowAll bool `url:"showAll,omitempty" json:"showAll,omitempty"` + ShowAll bool `url:"show_all,omitempty" json:"show_all,omitempty"` } // Get gets image by ID. diff --git a/pkg/cloudapi/k8ci/list.go b/pkg/cloudapi/k8ci/list.go index 09013d8..e437fe8 100644 --- a/pkg/cloudapi/k8ci/list.go +++ b/pkg/cloudapi/k8ci/list.go @@ -10,7 +10,7 @@ import ( type ListRequest struct { // Find by ID // Required: false - ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + ByID uint64 `url:"id,omitempty" json:"id,omitempty"` // Find by name // Required: false diff --git a/pkg/cloudapi/k8s/create.go b/pkg/cloudapi/k8s/create.go index 932cfdd..6c65d97 100644 --- a/pkg/cloudapi/k8s/create.go +++ b/pkg/cloudapi/k8s/create.go @@ -202,7 +202,7 @@ func (k8s K8S) Create(ctx context.Context, req CreateRequest) (string, error) { url := "/cloudapi/k8s/create" - res, err := k8s.client.DecortApiCallMP(ctx, http.MethodPost, url, req) + res, err := k8s.client.DecortApiCall(ctx, http.MethodPost, url, req) if err != nil { return "", err } diff --git a/pkg/cloudapi/k8s/delete.go b/pkg/cloudapi/k8s/delete.go index 03176c0..7f9fdfe 100644 --- a/pkg/cloudapi/k8s/delete.go +++ b/pkg/cloudapi/k8s/delete.go @@ -17,7 +17,7 @@ type DeleteRequest struct { // True if cluster is destroyed permanently. // Otherwise it can be restored from Recycle Bin // Required: true - Permanently bool `url:"permanently" json:"permanently"` + Permanently bool `url:"permanently" json:"permanently" validate:"required"` } // Delete deletes kubernetes cluster diff --git a/pkg/cloudapi/lb/list.go b/pkg/cloudapi/lb/list.go index 9c3daea..b897cf3 100644 --- a/pkg/cloudapi/lb/list.go +++ b/pkg/cloudapi/lb/list.go @@ -18,7 +18,7 @@ type ListRequest struct { // Find by account ID // Required: false - AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + AccountID uint64 `url:"accountID,omitempty" json:"accountID,omitempty"` // Find by resource group ID // Required: false diff --git a/pkg/cloudapi/lb/restart.go b/pkg/cloudapi/lb/restart.go index eb25cb2..67e148e 100644 --- a/pkg/cloudapi/lb/restart.go +++ b/pkg/cloudapi/lb/restart.go @@ -13,11 +13,6 @@ type RestartRequest struct { // ID of the load balancer instance to restart // Required: true LBID uint64 `url:"lbId" json:"lbId" validate:"required"` - - // restart secondary and primary nodes sequentially in HA mode - // Default is true - // Required: false - Safe bool `url:"safe" json:"safe"` } // Restart restarts specified load balancer instance diff --git a/pkg/cloudapi/locations/models.go b/pkg/cloudapi/locations/models.go index 87f7b3c..2077d0a 100644 --- a/pkg/cloudapi/locations/models.go +++ b/pkg/cloudapi/locations/models.go @@ -2,9 +2,6 @@ package locations // Main information about locations type ItemLocation struct { - // AuthBroker - AuthBroker []string `json:"authBroker"` - // Grid ID GID uint64 `json:"gid"` diff --git a/pkg/cloudapi/rg/ids.go b/pkg/cloudapi/rg/ids.go index 83da393..3a875af 100644 --- a/pkg/cloudapi/rg/ids.go +++ b/pkg/cloudapi/rg/ids.go @@ -53,14 +53,3 @@ func (lrc ListResourceConsumption) IDs() []uint64 { } return res } - -// IDs gets array of ResourceGroupIDs from ListAffinityGroup struct -func (lag ListAffinityGroups) IDs() []uint64 { - res := make([]uint64, 0, len(lag.Data)) - for _, ag := range lag.Data { - for _, v := range ag { - res = append(res, v...) - } - } - return res -} diff --git a/pkg/cloudapi/rg/models.go b/pkg/cloudapi/rg/models.go index 22dc36b..887504d 100644 --- a/pkg/cloudapi/rg/models.go +++ b/pkg/cloudapi/rg/models.go @@ -331,10 +331,18 @@ type ItemAffinityGroupComputes struct { // List of affinity groups type ListAffinityGroupsComputes []ItemAffinityGroupComputes -// List of affinity groups +// Main information about +type ItemAffinityGroup struct { + ID uint64 `json:"id"` + NodeID uint64 `json:"node_id"` +} + +// List of affinity group +type ListAffinityGroup []ItemAffinityGroup + type ListAffinityGroups struct { // Data - Data []map[string][]uint64 `json:"data"` + Data []map[string]ListAffinityGroup `json:"data"` // Entry count EntryCount uint64 `json:"entryCount"` @@ -477,9 +485,6 @@ type RecordLoadBalancer struct { // Access Control List ACL interface{} `json:"acl"` - // BackendHAIP - BackendHAIP string `json:"backendHAIP"` - // List of Backends Backends ListBackends `json:"backends"` @@ -504,9 +509,6 @@ type RecordLoadBalancer struct { // External network ID ExtNetID uint64 `json:"extnetId"` - // FrontendHAIP - FrontendHAIP string `json:"frontendHAIP"` - // List of frontends Frontends ListFrontends `json:"frontends"` diff --git a/pkg/cloudapi/vins/create_in_rg.go b/pkg/cloudapi/vins/create_in_rg.go index 8d89fa5..e24f7d4 100644 --- a/pkg/cloudapi/vins/create_in_rg.go +++ b/pkg/cloudapi/vins/create_in_rg.go @@ -25,8 +25,7 @@ type CreateInRGRequest struct { // External network ID // Required: false - // -1 - not connect to extnet, 0 - auto select, 1+ - extnet ID - ExtNetID int64 `url:"extNetId" json:"extNetId"` + ExtNetID uint64 `url:"extNetId,omitempty" json:"extNetId,omitempty"` // External IP, related only for extNetId >= 0 // Required: false diff --git a/pkg/cloudbroker/audit.go b/pkg/cloudbroker/audit.go deleted file mode 100644 index cec4931..0000000 --- a/pkg/cloudbroker/audit.go +++ /dev/null @@ -1,10 +0,0 @@ -package cloudbroker - -import ( - "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/audit" -) - -// Accessing the Stack method group -func (cb *CloudBroker) Audit() *audit.Audit { - return audit.New(cb.client) -} diff --git a/pkg/cloudbroker/audit/audit.go b/pkg/cloudbroker/audit/audit.go deleted file mode 100644 index 17904f3..0000000 --- a/pkg/cloudbroker/audit/audit.go +++ /dev/null @@ -1,15 +0,0 @@ -package audit - -import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" - -// Structure for creating request to audit -type Audit struct { - client interfaces.Caller -} - -// Builder for audit endpoint -func New(client interfaces.Caller) *Audit { - return &Audit{ - client: client, - } -} diff --git a/pkg/cloudbroker/audit/get.go b/pkg/cloudbroker/audit/get.go deleted file mode 100644 index 1894f85..0000000 --- a/pkg/cloudbroker/audit/get.go +++ /dev/null @@ -1,46 +0,0 @@ -package audit - -import ( - "context" - "encoding/json" - "net/http" - - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" -) - -// GetRequest struct to get information about account -type GetRequest struct { - // Audit GUID - // Required: true - AuditGuid string `url:"auditGuid" json:"auditGuid" validate:"required"` -} - -// Get gets information about audit as a RecordAudit struct -func (a Audit) Get(ctx context.Context, req GetRequest) (*RecordAudit, error) { - res, err := a.GetRaw(ctx, req) - if err != nil { - return nil, err - } - - info := RecordAudit{} - - err = json.Unmarshal(res, &info) - if err != nil { - return nil, err - } - - return &info, nil -} - -// GetRaw gets information about audit as an array of bytes -func (a Audit) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) { - err := validators.ValidateRequest(req) - if err != nil { - return nil, validators.ValidationErrors(validators.GetErrors(err)) - } - - url := "/cloudbroker/audit/get" - - res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) - return res, err -} diff --git a/pkg/cloudbroker/audit/linked_jobs.go b/pkg/cloudbroker/audit/linked_jobs.go deleted file mode 100644 index cfe17ba..0000000 --- a/pkg/cloudbroker/audit/linked_jobs.go +++ /dev/null @@ -1,46 +0,0 @@ -package audit - -import ( - "context" - "encoding/json" - "net/http" - - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" -) - -// LinkedJobsRequest struct to get information about jobs linked with Audit -type LinkedJobsRequest struct { - // Audit GUID - // Required: true - AuditGuid string `url:"auditGuid" json:"auditGuid" validate:"required"` -} - -// LinkedJobs gets information about Linked Jobs as a ListLinkedJobs struct -func (a Audit) LinkedJobs(ctx context.Context, req LinkedJobsRequest) (*ListLinkedJobs, error) { - res, err := a.GetRawLinkedJobs(ctx, req) - if err != nil { - return nil, err - } - - info := ListLinkedJobs{} - - err = json.Unmarshal(res, &info) - if err != nil { - return nil, err - } - - return &info, nil -} - -// GetRawLinkedJobs gets information about Linked Jobs as an array of bytes -func (a Audit) GetRawLinkedJobs(ctx context.Context, req LinkedJobsRequest) ([]byte, error) { - err := validators.ValidateRequest(req) - if err != nil { - return nil, validators.ValidationErrors(validators.GetErrors(err)) - } - - url := "/cloudbroker/audit/linkedJobs" - - res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) - return res, err -} diff --git a/pkg/cloudbroker/audit/list.go b/pkg/cloudbroker/audit/list.go deleted file mode 100644 index e7a7cc6..0000000 --- a/pkg/cloudbroker/audit/list.go +++ /dev/null @@ -1,64 +0,0 @@ -package audit - -import ( - "context" - "encoding/json" - "net/http" -) - -// ListRequest struct to give list of account audits -type ListRequest struct { - - // Find all audits after point in time (unixtime) - // Required: false - TimestampAt uint64 `url:"timestampAt,omitempty" json:"timestampAt,omitempty"` - - // Find all audits before point in time (unixtime) - // Required: false - TimestampTo uint64 `url:"timestampTo,omitempty" json:"timestampTo,omitempty"` - - // Find by user (Mongo RegExp supported) - // Required: false - User string `url:"user,omitempty" json:"user,omitempty"` - - // Find by api endpoint (Mongo RegExp supported) - // Required: false - Call string `url:"call,omitempty" json:"call,omitempty"` - - // Find by HTTP status code - // Required: false - StatusCode uint64 `url:"statusCode,omitempty" json:"statusCode,omitempty"` - - // Page number - // Required: false - Page uint64 `url:"page,omitempty" json:"page,omitempty"` - - // Page size - // Required: false - Size uint64 `url:"size,omitempty" json:"size,omitempty"` -} - -// List gets audit records for the specified account object -func (a Audit) List(ctx context.Context, req ListRequest) (*ListAudits, error) { - res, err := a.ListRaw(ctx, req) - if err != nil { - return nil, err - } - - list := ListAudits{} - - err = json.Unmarshal(res, &list) - if err != nil { - return nil, err - } - - return &list, nil -} - -// ListRaw gets list of audit records an array of bytes -func (a Audit) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) { - url := "/cloudbroker/audit/list" - - res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) - return res, err -} diff --git a/pkg/cloudbroker/audit/models.go b/pkg/cloudbroker/audit/models.go deleted file mode 100644 index 73588f9..0000000 --- a/pkg/cloudbroker/audit/models.go +++ /dev/null @@ -1,102 +0,0 @@ -package audit - -// Main info about audit -type ItemAudit struct { - // Call - Call string `json:"call"` - - // GUID - GUID string `json:"guid"` - - // Response time - ResponseTime float64 `json:"responsetime"` - - // Status code - StatusCode uint64 `json:"statuscode"` - - // Timestamp - Timestamp float64 `json:"timestamp"` - - // User - User string `json:"user"` -} - -// List of audits -type ListAudits struct { - // Data - Data []ItemAudit `json:"data"` - - // EntryCount - EntryCount uint64 `json:"entryCount"` -} - -// Main info about audit -type RecordAudit struct { - - // Apitask - Apitask string `json:"apitask"` - - // Arguments - Arguments string `json:"args"` - - // Call - Call string `json:"call"` - - // GUID - GUID string `json:"guid"` - - // Kwargs - Kwargs string `json:"kwargs"` - - // RemoteAddr - RemoteAddr string `json:"remote_addr"` - - // Response time - ResponseTime float64 `json:"responsetime"` - - // Result - Result string `json:"result"` - - // Status code - StatusCode uint64 `json:"statuscode"` - - // Tags - Tags string `json:"tags"` - - // Timestamp - Timestamp float64 `json:"timestamp"` - - // TimestampEnd - TimestampEnd float64 `json:"timestampEnd"` - - // User - User string `json:"user"` -} - -// List of Linked Jobs -type ListLinkedJobs []ItemLinkedJobs - -// Main info about Linked Jobs -type ItemLinkedJobs struct { - - // CMD - CMD string `json:"cmd"` - - // NID - NID uint64 `json:"nid"` - - // state - State string `json:"state"` - - // TimeCreate - TimeCreate uint64 `json:"timeCreate"` - - // TimeStart - TimeStart uint64 `json:"timeStart"` - - // TimeStop - TimeStop uint64 `json:"timeStop"` - - // Timeout - Timeout uint64 `json:"timeout"` -} diff --git a/pkg/cloudbroker/compute/delete_custom_fields.go b/pkg/cloudbroker/compute/delete_custom_fields.go deleted file mode 100644 index 33b3d71..0000000 --- a/pkg/cloudbroker/compute/delete_custom_fields.go +++ /dev/null @@ -1,38 +0,0 @@ -package compute - -import ( - "context" - "net/http" - "strconv" - - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" -) - -// DeleteCustomFieldsRequest struct to delete compute's custom fields -type DeleteCustomFieldsRequest struct { - // ID of the compute - // Required: true - ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"` -} - -// DeleteCustomFields deletes computes custom fields -func (c Compute) DeleteCustomFields(ctx context.Context, req DeleteCustomFieldsRequest) (bool, error) { - err := validators.ValidateRequest(req) - if err != nil { - return false, validators.ValidationErrors(validators.GetErrors(err)) - } - - url := "/cloudbroker/compute/deleteCustomFields" - - res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) - if err != nil { - return false, err - } - - result, err := strconv.ParseBool(string(res)) - if err != nil { - return false, err - } - - return result, nil -} diff --git a/pkg/cloudbroker/compute/ids.go b/pkg/cloudbroker/compute/ids.go index 3a6b978..f1a7656 100644 --- a/pkg/cloudbroker/compute/ids.go +++ b/pkg/cloudbroker/compute/ids.go @@ -20,8 +20,8 @@ func (lid ListInfoDisks) IDs() []uint64 { // IDs gets array of PFWsIDs from ListPFW struct func (lp ListPFW) IDs() []uint64 { - res := make([]uint64, 0, len(lp.Data)) - for _, p := range lp.Data { + res := make([]uint64, 0, len(lp)) + for _, p := range lp { res = append(res, p.ID) } return res diff --git a/pkg/cloudbroker/compute/models.go b/pkg/cloudbroker/compute/models.go index 4b39686..c48a639 100644 --- a/pkg/cloudbroker/compute/models.go +++ b/pkg/cloudbroker/compute/models.go @@ -12,14 +12,6 @@ type RecordACL struct { RGACL ListACL `json:"rgACL"` } -type ListUsers struct { - // Data - Data RecordACL `json:"data"` - - // Entry count - EntryCount uint64 `json:"entryCount"` -} - // ACL information type ItemACL struct { // Explicit @@ -83,15 +75,6 @@ type ItemSnapshot struct { // List of snapshots type ListSnapshots []ItemSnapshot -// List of snapshots -type ListSnapShot struct { - // Data - Data []ItemSnapshot `json:"data"` - - // Entry count - EntryCount uint64 `json:"entryCount"` -} - // Main information about snapshot usage type ItemSnapshotUsage struct { // Count @@ -249,13 +232,7 @@ type ItemPFW struct { } // List port forwards -type ListPFW struct { - // Data - Data []ItemPFW `json:"data"` - - // Entry count - EntryCount uint64 `json:"entryCount"` -} +type ListPFW []ItemPFW // Main information about rule type ItemRule struct { @@ -592,9 +569,6 @@ type InfoCompute struct { // Boot disk size BootDiskSize uint64 `json:"bootdiskSize"` - // cd Image Id - CdImageId uint64 `json:"cdImageId"` - // Clone reference CloneReference uint64 `json:"cloneReference"` @@ -664,9 +638,6 @@ type InfoCompute struct { // Name Name string `json:"name"` - // Need reboot - NeedReboot bool `json:"needReboot"` - // List OS users OSUsers ListOSUsers `json:"osUsers"` @@ -761,7 +732,7 @@ type ItemCompute struct { InfoCompute // Total disk size - TotalDiskSize uint64 `json:"totalDisksSize"` + TotalDiskSize uint64 `json:"totalDiskSize"` // VINS connected VINSConnected uint64 `json:"vinsConnected"` diff --git a/pkg/cloudbroker/compute/pfw_list.go b/pkg/cloudbroker/compute/pfw_list.go index b6fcd6c..7d1751e 100644 --- a/pkg/cloudbroker/compute/pfw_list.go +++ b/pkg/cloudbroker/compute/pfw_list.go @@ -20,7 +20,7 @@ type PFWListRequest struct { } // PFWList gets compute port forwards list -func (c Compute) PFWList(ctx context.Context, req PFWListRequest) (*ListPFW, error) { +func (c Compute) PFWList(ctx context.Context, req PFWListRequest) (ListPFW, error) { err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) @@ -40,5 +40,5 @@ func (c Compute) PFWList(ctx context.Context, req PFWListRequest) (*ListPFW, err return nil, err } - return &list, nil + return list, nil } diff --git a/pkg/cloudbroker/compute/snapshot_list.go b/pkg/cloudbroker/compute/snapshot_list.go index 453242a..02e78f1 100644 --- a/pkg/cloudbroker/compute/snapshot_list.go +++ b/pkg/cloudbroker/compute/snapshot_list.go @@ -16,7 +16,7 @@ type SnapshotListRequest struct { } // SnapshotList gets list of compute snapshots -func (c Compute) SnapshotList(ctx context.Context, req SnapshotListRequest) (*ListSnapShot, error) { +func (c Compute) SnapshotList(ctx context.Context, req SnapshotListRequest) (ListSnapshots, error) { err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) @@ -29,12 +29,12 @@ func (c Compute) SnapshotList(ctx context.Context, req SnapshotListRequest) (*Li return nil, err } - list := ListSnapShot{} + list := ListSnapshots{} err = json.Unmarshal(res, &list) if err != nil { return nil, err } - return &list, nil + return list, nil } diff --git a/pkg/cloudbroker/compute/user_list.go b/pkg/cloudbroker/compute/user_list.go index 384bae4..586d9e9 100644 --- a/pkg/cloudbroker/compute/user_list.go +++ b/pkg/cloudbroker/compute/user_list.go @@ -16,7 +16,7 @@ type UserListRequest struct { } // UserList gets users list for compute -func (c Compute) UserList(ctx context.Context, req UserListRequest) (*ListUsers, error) { +func (c Compute) UserList(ctx context.Context, req UserListRequest) (*RecordACL, error) { err := validators.ValidateRequest(req) if err != nil { return nil, validators.ValidationErrors(validators.GetErrors(err)) @@ -29,7 +29,7 @@ func (c Compute) UserList(ctx context.Context, req UserListRequest) (*ListUsers, return nil, err } - list := ListUsers{} + list := RecordACL{} err = json.Unmarshal(res, &list) if err != nil { diff --git a/pkg/cloudbroker/grid/get_diagnosis.go b/pkg/cloudbroker/grid/get_diagnosis.go index 540f2dd..f37f1a8 100644 --- a/pkg/cloudbroker/grid/get_diagnosis.go +++ b/pkg/cloudbroker/grid/get_diagnosis.go @@ -2,7 +2,6 @@ package grid import ( "context" - "fmt" "net/http" "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" @@ -39,7 +38,7 @@ func (g Grid) GetDiagnosisGET(ctx context.Context, req GetDiagnosisRequest) (str return "", validators.ValidationErrors(validators.GetErrors(err)) } - url := fmt.Sprintf("/cloudbroker/grid/getDiagnosis/?gid=%d", req.GID) + url := "/cloudbroker/grid/getDiagnosis" res, err := g.client.DecortApiCall(ctx, http.MethodGet, url, req) if err != nil { diff --git a/pkg/cloudbroker/grid/models.go b/pkg/cloudbroker/grid/models.go index 731b971..0a6f7c1 100644 --- a/pkg/cloudbroker/grid/models.go +++ b/pkg/cloudbroker/grid/models.go @@ -67,9 +67,6 @@ type DiskUsage struct { // Detailed information about grid type RecordGrid struct { - // AuthBroker - AuthBroker []interface{} `json:"authBroker"` - // Flag Flag string `json:"flag"` @@ -94,9 +91,6 @@ type ItemGridList struct { // Resource information Resources Resources `json:"Resources"` - // AuthBroker - AuthBroker []interface{} `json:"authBroker"` - // Flag Flag string `json:"flag"` diff --git a/pkg/cloudbroker/k8ci/access_add.go b/pkg/cloudbroker/k8ci/access_add.go deleted file mode 100644 index 499895a..0000000 --- a/pkg/cloudbroker/k8ci/access_add.go +++ /dev/null @@ -1,36 +0,0 @@ -package k8ci - -import ( - "context" - "net/http" - - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" -) - -// AccessAddRequest struct for adding permission to access to account for a k8ci -type AccessAddRequest struct { - // ID of the K8 catalog item to add access for - // Required: true - K8CIID uint64 `url:"k8ciId" json:"k8ciId" validate:"required"` - - // Account ID to add to the sharedWith access list - // Required: true - AccountId uint64 `url:"accountId" json:"accountId" validate:"required"` -} - -// Add accountId to sharedWith access list for k8ci. -func (k K8CI) AccessAdd(ctx context.Context, req AccessAddRequest) (string, error) { - err := validators.ValidateRequest(req) - if err != nil { - return "", validators.ValidationErrors(validators.GetErrors(err)) - } - - url := "/cloudbroker/k8ci/accessAdd" - - res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) - if err != nil { - return "", err - } - - return string(res), nil -} diff --git a/pkg/cloudbroker/k8ci/access_remove.go b/pkg/cloudbroker/k8ci/access_remove.go deleted file mode 100644 index 8b2c2c9..0000000 --- a/pkg/cloudbroker/k8ci/access_remove.go +++ /dev/null @@ -1,36 +0,0 @@ -package k8ci - -import ( - "context" - "net/http" - - "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" -) - -// AccessRemoveRequest struct for removing permission to access to account for a k8ci -type AccessRemoveRequest struct { - // ID of the K8 catalog item to remove access for - // Required: true - K8CIID uint64 `url:"k8ciId" json:"k8ciId" validate:"required"` - - // Account ID to be removed from the sharedWith access list - // Required: true - AccountId uint64 `url:"accountId" json:"accountId" validate:"required"` -} - -// Remove accountId from sharedWith access list for k8ci. -func (k K8CI) AccessRemove(ctx context.Context, req AccessRemoveRequest) (string, error) { - err := validators.ValidateRequest(req) - if err != nil { - return "", validators.ValidationErrors(validators.GetErrors(err)) - } - - url := "/cloudbroker/k8ci/accessRemove" - - res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) - if err != nil { - return "", err - } - - return string(res), nil -} diff --git a/pkg/cloudbroker/k8s/create.go b/pkg/cloudbroker/k8s/create.go index c3adb83..55b417b 100644 --- a/pkg/cloudbroker/k8s/create.go +++ b/pkg/cloudbroker/k8s/create.go @@ -204,7 +204,7 @@ func (k K8S) Create(ctx context.Context, req CreateRequest) (string, error) { url := "/cloudbroker/k8s/create" - res, err := k.client.DecortApiCallMP(ctx, http.MethodPost, url, req) + res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) if err != nil { return "", err } diff --git a/pkg/cloudbroker/lb/make_highly_available.go b/pkg/cloudbroker/lb/make_highly_available.go index c034115..e10463b 100644 --- a/pkg/cloudbroker/lb/make_highly_available.go +++ b/pkg/cloudbroker/lb/make_highly_available.go @@ -29,10 +29,10 @@ func (l LB) HighlyAvailable(ctx context.Context, req HighlyAvailableRequest) (bo return false, err } - result, err := strconv.ParseUint(string(res), 10, 64) - if err != nil || result != req.LBID { + result, err := strconv.ParseBool(string(res)) + if err != nil { return false, err } - return true, nil + return result, nil } diff --git a/pkg/cloudbroker/rg/affinity_groups_list.go b/pkg/cloudbroker/rg/affinity_groups_list.go index ac6e862..a2e2555 100644 --- a/pkg/cloudbroker/rg/affinity_groups_list.go +++ b/pkg/cloudbroker/rg/affinity_groups_list.go @@ -13,14 +13,6 @@ type AffinityGroupsListRequest struct { // Resource group ID // Required: true RGID uint64 `url:"rgId" json:"rgId" validate:"required"` - - // Page number - // Required: false - Page uint64 `url:"page,omitempty" json:"page,omitempty"` - - // Page size - // Required: false - Size uint64 `url:"size,omitempty" json:"size,omitempty"` } // AffinityGroupsList gets all currently defined affinity groups in this resource group with compute IDs diff --git a/pkg/cloudbroker/rg/ids.go b/pkg/cloudbroker/rg/ids.go index 272570c..1aa2d69 100644 --- a/pkg/cloudbroker/rg/ids.go +++ b/pkg/cloudbroker/rg/ids.go @@ -53,12 +53,3 @@ func (lpfw ListPFW) IDs() []uint64 { } return res } - -// IDs gets array of ComputeIDs from ListAffinityGroupItems struct -func (lag ListAffinityGroupItems) IDs() []uint64 { - res := make([]uint64, 0, len(lag)) - for _, ag := range lag { - res = append(res, ag.ID) - } - return res -} diff --git a/pkg/cloudbroker/rg/list.go b/pkg/cloudbroker/rg/list.go index 46162af..6d6d3f6 100644 --- a/pkg/cloudbroker/rg/list.go +++ b/pkg/cloudbroker/rg/list.go @@ -36,10 +36,6 @@ type ListRequest struct { // Required: false Status string `url:"status,omitempty" json:"status,omitempty"` - // Find by status lock - // Required: false - LockStatus string `url:"lockStatus,omitempty" json:"lockStatus,omitempty"` - // Included deleted resource groups // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` diff --git a/pkg/cloudbroker/rg/models.go b/pkg/cloudbroker/rg/models.go index 26d7a9a..e8628ba 100644 --- a/pkg/cloudbroker/rg/models.go +++ b/pkg/cloudbroker/rg/models.go @@ -65,10 +65,6 @@ type ItemResourceConsumption struct { // Reserved information Reserved Reservation `json:"Reserved"` - // Resource limits - ResourceLimits ResourceLimits `json:"resourceLimits"` - - // Resource group ID RGID uint64 `json:"rgid"` } @@ -607,9 +603,6 @@ type ItemLB struct { // List ACL ACL ListACL `json:"acl"` - // BackendHAIP - BackendHAIP string `json:"backendHAIP"` - // List backends Backends ListBackends `json:"backends"` @@ -634,9 +627,6 @@ type ItemLB struct { // External network ID ExtNetID uint64 `json:"extnetId"` - // FrontendHAIP - FrontendHAIP string `json:"frontendHAIP"` - // List of frontends Frontends ListFrontends `json:"frontends"` @@ -697,15 +687,8 @@ type ListLB struct { type ListAffinityGroup struct { // Data - Data []map[string]ListAffinityGroupItems `json:"data"` + Data map[string][]uint64 `json:"data"` // Entry count EntryCount uint64 `json:"entryCount"` } - -type ListAffinityGroupItems []ItemAffinityGroup - -type ItemAffinityGroup struct { - ID uint64 `json:"id"` - NodeID uint64 `json:"node_id"` -} diff --git a/pkg/cloudbroker/stack/stack.go b/pkg/cloudbroker/stack/stack.go index a330f68..94c5d89 100644 --- a/pkg/cloudbroker/stack/stack.go +++ b/pkg/cloudbroker/stack/stack.go @@ -1,3 +1,4 @@ +// Lists all the stack. package stack import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces" diff --git a/pkg/cloudbroker/vins/create_in_rg.go b/pkg/cloudbroker/vins/create_in_rg.go index 90084e3..7b90b59 100644 --- a/pkg/cloudbroker/vins/create_in_rg.go +++ b/pkg/cloudbroker/vins/create_in_rg.go @@ -25,8 +25,7 @@ type CreateInRGRequest struct { // External network ID // Required: false - // -1 - not connect to extnet, 0 - auto select, 1+ - extnet ID - ExtNetID int64 `url:"extNetId" json:"extNetId"` + ExtNetID uint64 `url:"extNetId,omitempty" json:"extNetId,omitempty"` // External IP, related only for extNetId >= 0 // Required: false diff --git a/samples/config/bvs-config.json b/samples/config/bvs-config.json deleted file mode 100644 index 7df369b..0000000 --- a/samples/config/bvs-config.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "username": "", - "password": "", - "appId": "", - "appSecret": "", - "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 -} diff --git a/samples/config/bvs-config.yml b/samples/config/bvs-config.yml deleted file mode 100644 index a49b8d5..0000000 --- a/samples/config/bvs-config.yml +++ /dev/null @@ -1,18 +0,0 @@ -username: -password: -appId: -appSecret: -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