Compare commits

...

14 Commits

Author SHA1 Message Date
1972956aeb v1.6.0-gamma 2023-09-15 12:41:04 +03:00
afcbc7e749 1.6.0-beta 2023-09-14 15:05:38 +03:00
0b3de4df7f 1.6.0-alfa 2023-09-11 13:11:33 +03:00
c0608d08b9 1.5.8-gostech 2023-09-07 18:11:25 +03:00
4d9b8fc9d8 v1.5.7 2023-09-04 18:48:22 +03:00
e8270453cc 1.5.6 2023-08-30 13:54:30 +03:00
7de095302b v1.5.5 2023-08-25 13:53:43 +03:00
a3711057ba v1.5.4 2023-08-22 15:28:39 +03:00
1c59ca338a v1.5.3 2023-08-15 11:42:30 +03:00
f1529c9aac v1.5.2 2023-08-09 19:33:50 +03:00
040235f92f v1.5.1 2023-07-24 18:13:52 +03:00
4a152cb44c v1.5.0 2023-07-24 16:43:10 +03:00
c78b1348e3 v1.5.0 2023-07-24 15:13:04 +03:00
8f152a2f63 v1.5.0 2023-07-21 15:14:10 +03:00
98 changed files with 1861 additions and 872 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
cmd/
.idea/
.vscode/
.fleet/
.DS_Store

View File

@@ -1,143 +1,4 @@
## Version 1.5.0
### Feature
- Updated lists responses models in:
- - cloudapi/account/list
- - cloudbroker/account/list
- - cloudapi/bservice/list
- - cloudapi/compute/list
- - cloudbroker/compute/list
- - cloudapi/computeci/list
- - cloudapi/disks/list
- - cloudbroker/disks/list
- - cloudapi/extnet/list
- - cloudbroker/extnet/list
- - cloudapi/flipgroup/list
- - cloudapi/image/list
- - cloudbroker/image/list
- - cloudapi/k8ci/list
- - cloudbroker/k8ci/list
- - cloudapi/k8s/list
- - cloudapi/k8s/listDeleted
- - cloudbroker/k8s/list
- - cloudbroker/k8s/listDeleted
- - cloudapi/tasks/list
- - cloudbroker/tasks/list
- - cloudapi/rg/list
- - cloudbroker/rg/list
- - cloudapi/vins/list
- - cloudbroker/vins/list
- - cloudapi/account/listDeleted
- - cloudapi/account/listCompute
- - cloudapi/account/listDisks
- - cloudapi/account/listFlipGroups
- - cloudapi/account/listRG
- - cloudapi/account/listVINS
- - cloudapi/compute/listDeleted
- - cloudapi/disks/listDeleted
- - cloudapi/disks/listTypes
- - cloudapi/k8ci/listDeleted
- - cloudapi/lb/list
- - cloudapi/lb/listDeleted
- - cloudbroker/lb/list
- - cloudbroker/lb/listDeleted
- - cloudapi/rg/listComputes
- - cloudapi/rg/listDeleted
- - cloudapi/rg/listLb
- - cloudapi/rg/listPFW
- - cloudapi/rg/listVins
- - cloudapi/vins/listDeleted
- - cloudbroker/account/listComputes
- - cloudbroker/account/listDeleted
- - cloudbroker/account/listDisks
- - cloudbroker/account/listFlipGroups
- - cloudbroker/account/listRG
- - cloudbroker/account/listVINS
- - cloudbroker/compute/listDeleted
- - cloudapi/compute/listPciDevice
- - cloudbroker/compute/listPciDevice
- - cloudapi/compute/listVGpu
- - cloudbroker/compute/listVGpu
- - cloudbroker/disks/listTypes
- - cloudbroker/grid/list
- - cloudbroker/grid/listEmails
- - cloudbroker/k8ci/listDeleted
- - cloudbroker/pcidevice/list
- - cloudbroker/rg/affinityGroupsList
- - cloudbroker/rg/listDeleted
- - cloudbroker/rg/listComputes
- - cloudbroker/rg/listLB
- - cloudbroker/rg/listPfw
- - cloudbroker/rg/listResourceConsumption
- - cloudbroker/rg/listVins
- - cloudbroker/sep/list
- - cloudbroker/vgpu/list
- - cloudbroker/vins/extnetList
- - cloudbroker/vins/IpList
- - cloudbroker/vins/natRuleList
- Added new endpoints:
- - cloudapi/rg/getResourceConsumption
- - cloudapi/rg/listResourceConsumption
- - cloudbroker/rg/getResourceConsumption
- - cloudbroker/rg/listResourceConsumption
- - cloudapi/account/getResourceConsumption
- - cloudapi/account/listResourceConsumption
- - cloudbroker/account/getResourceConsumption
- - cloudbroker/account/listResourceConsumption
- - cloudbroker/grid/getResourceConsumption
- - cloudbroker/grid/listResourceConsumption
- Added field CU_DM to ResourceLimits model (account, rg)
- Added field ReferenceID to SnapshotExtended model in cloudapi/compute/get
- Added field Interfaces in requests:
- - cloudapi/kvmppc/create
- - cloudapi/kvmppc/createBlank
- - cloudapi/kvmx86/create
- - cloudapi/kvmx86/createBlank
- - cloudbroker/kvmppc/create
- - cloudbroker/kvmppc/createBlank
- - cloudbroker/kvmx86/create
- - cloudbroker/kvmx86/createBlank
- Added UpdatedBy field to task model in cloudbroker/task/get
- Made optional fields in requests:
- - Reason (cloudbroker/account/delete)
- - Reason (cloudbroker/account/restore)
- - Gateway (cloudbroker/extnet/create)
- - Reason (cloudbroker/image/delete)
- - Num (cloudapi/k8s/workerAdd)
- - NetID (cloudbroker/vins/extnetConnect)
- Updated cloudapi/rg/get model
- Deleted field Username from cloudbroker/account/update request
- Deleted field EmailAddress from cloudbroker/account/update request
- Added field DiskType to cloudbroker/compute/diskAttach request
- Added field Reason to cloudbroker/compute/diskQos request
- Added field Enabled to cloudbroker/compute/netAttach response model
- Added field CPUAllocationRatio to cloudbroker/image/listStacks response model
- Added field Descr to cloudbroker/image/listStacks response model
- Added field MemAllocationRatio to cloudbroker/image/listStacks response model
- Updated cloudapi/k8s/workersGroupByName response model
- Deleted field LBImageID from cloudbroker/k8ci/create request
- Deleted field ImageID from cloudbroker/lb/create request
- Deleted field Reason from cloudbroker/vins/extnetList request
## Version 1.6.0-beta
### Bugfix
- Changed the Excluded field type in cloudbroker/extnet/get response model
- Refactored client, made it concurrent safe

View File

@@ -1,24 +1,31 @@
package decortsdk
import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"net/http"
"strings"
"sync"
"time"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker"
"github.com/google/go-querystring/query"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/client"
)
// HTTP-client for platform
type DecortClient struct {
decortURL string
client *http.Client
decortURL string
client *http.Client
cfg config.Config
expiryTime time.Time
mutex *sync.Mutex
}
// Сlient builder
@@ -27,9 +34,25 @@ func New(cfg config.Config) *DecortClient {
cfg.Retries = 5
}
var expiryTime time.Time
if cfg.Token != "" {
expiryTime = time.Now().AddDate(0, 0, 1)
}
return &DecortClient{
decortURL: cfg.DecortURL,
client: client.NewHttpClient(cfg),
client: &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
//nolint:gosec
InsecureSkipVerify: cfg.SSLSkipVerify,
},
},
},
cfg: cfg,
expiryTime: expiryTime,
mutex: &sync.Mutex{},
}
}
@@ -56,7 +79,11 @@ func (dc *DecortClient) DecortApiCall(ctx context.Context, method, url string, p
return nil, err
}
resp, err := dc.client.Do(req)
if err = dc.getToken(ctx); err != nil {
return nil, err
}
resp, err := dc.do(req)
if err != nil {
return nil, err
}
@@ -73,3 +100,64 @@ func (dc *DecortClient) DecortApiCall(ctx context.Context, method, url string, p
return respBytes, nil
}
func (dc *DecortClient) getToken(ctx context.Context) error {
dc.mutex.Lock()
defer dc.mutex.Unlock()
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, "/")
req, _ := http.NewRequestWithContext(ctx, "POST", dc.cfg.SSOURL+"/v1/oauth/access_token", bodyReader)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := dc.client.Do(req)
if err != nil {
return fmt.Errorf("cannot get token: %w", err)
}
tokenBytes, _ := io.ReadAll(resp.Body)
resp.Body.Close()
if resp.StatusCode != 200 {
return fmt.Errorf("cannot get token: %s", tokenBytes)
}
token := string(tokenBytes)
dc.cfg.Token = token
dc.expiryTime = time.Now().AddDate(0, 0, 1)
}
return nil
}
func (dc *DecortClient) do(req *http.Request) (*http.Response, error) {
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Authorization", "bearer "+dc.cfg.Token)
req.Header.Set("Accept", "application/json")
var resp *http.Response
var err error
buf, _ := io.ReadAll(req.Body)
for i := uint64(0); i < dc.cfg.Retries; i++ {
req := req.Clone(req.Context())
req.Body = io.NopCloser(bytes.NewBuffer(buf))
resp, err = dc.client.Do(req)
if err == nil {
if resp.StatusCode == 200 {
return resp, err
}
respBytes, _ := io.ReadAll(resp.Body)
err = fmt.Errorf("%s", respBytes)
resp.Body.Close()
}
}
return nil, fmt.Errorf("could not execute request: %w", err)
}

View File

@@ -1,40 +0,0 @@
package client
import (
"crypto/tls"
"net/http"
"time"
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
)
func NewHttpClient(cfg config.Config) *http.Client {
transCfg := &http.Transport{
TLSClientConfig: &tls.Config{
//nolint:gosec
InsecureSkipVerify: cfg.SSLSkipVerify,
},
}
var expiredTime time.Time
if cfg.Token != "" {
expiredTime = time.Now().AddDate(0, 0, 1)
}
return &http.Client{
Transport: &transport{
base: transCfg,
retries: cfg.Retries,
clientID: cfg.AppID,
clientSecret: cfg.AppSecret,
ssoURL: cfg.SSOURL,
token: cfg.Token,
expiryTime: expiredTime,
//TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
Timeout: cfg.Timeout.Get(),
}
}

View File

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

View File

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

View File

@@ -1,69 +0,0 @@
package client
import (
"fmt"
"io"
"net/http"
"strings"
"time"
)
type transport struct {
base http.RoundTripper
retries uint64
clientID string
clientSecret string
token string
ssoURL string
expiryTime time.Time
}
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
if t.token == "" || time.Now().After(t.expiryTime) {
body := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s&response_type=id_token", t.clientID, t.clientSecret)
bodyReader := strings.NewReader(body)
t.ssoURL = strings.TrimSuffix(t.ssoURL, "/")
req, _ := http.NewRequestWithContext(req.Context(), "POST", t.ssoURL+"/v1/oauth/access_token", bodyReader)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := t.base.RoundTrip(req)
if err != nil {
return nil, fmt.Errorf("cannot get token: %w", err)
}
tokenBytes, _ := io.ReadAll(resp.Body)
resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("cannot get token: %s", tokenBytes)
}
token := string(tokenBytes)
t.token = token
t.expiryTime = time.Now().AddDate(0, 0, 1)
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Authorization", "bearer "+t.token)
req.Header.Set("Accept", "application/json")
var resp *http.Response
var err error
for i := uint64(0); i < t.retries; i++ {
resp, err = t.base.RoundTrip(req)
if err == nil {
if resp.StatusCode == 200 {
return resp, nil
}
respBytes, _ := io.ReadAll(resp.Body)
err = fmt.Errorf("%s", respBytes)
resp.Body.Close()
}
//logrus.Errorf("Could not execute request: %v. Retrying %d/%d", err, i+1, t.retries)
time.Sleep(time.Second * 5)
}
return nil, fmt.Errorf("could not execute request: %w", err)
}

View File

@@ -1,11 +1,19 @@
package validators
import (
"github.com/go-playground/validator/v10"
"regexp"
"strings"
"github.com/go-playground/validator/v10"
)
// computeDriverValidator is used to validate Driver field in kvmx86/kvmppc create.
func computeDriverValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
return StringInSlice(fieldValue, computeDriverValues)
}
// protoValidator is used to validate Proto fields.
func protoValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
@@ -256,3 +264,11 @@ func strictLooseValidator(fe validator.FieldLevel) bool {
return StringInSlice(fieldValue, strictLooseValues)
}
// name workerGroup must be more 3 symbol
func workerGroupNameValidator(fe validator.FieldLevel) bool {
fieldValue := fe.Field().String()
fieldValue = strings.Trim(fieldValue, " ")
return len(fieldValue) >= 3
}

View File

@@ -107,6 +107,12 @@ func errorMessage(fe validator.FieldError) string {
fe.Field(),
joinValues(computeDataDisksValues))
case "computeDriver":
return fmt.Sprintf("%s %s must be one of the following: %s",
prefix,
fe.Field(),
joinValues(computeDriverValues))
// Disk Validators
case "diskType":
return fmt.Sprintf("%s %s must be one of the following: %s",
@@ -121,6 +127,12 @@ func errorMessage(fe validator.FieldError) string {
fe.Field(),
joinValues(flipgroupClientTypeValues))
// k8s Validators
case "workerGroupName":
return fmt.Sprintf("%s %s must be more 3 symbol",
prefix,
fe.Field())
// KVM_X86/KVM_PPC Validators
case "kvmNetType":
return fmt.Sprintf("%s %s must be one of the following: %s",

View File

@@ -30,6 +30,11 @@ func registerAllValidators(validate *validator.Validate) error {
return err
}
err = validate.RegisterValidation("computeDriver", computeDriverValidator)
if err != nil {
return err
}
err = validate.RegisterValidation("accessType", accessTypeValidator)
if err != nil {
return err
@@ -175,5 +180,10 @@ func registerAllValidators(validate *validator.Validate) error {
return err
}
err = validate.RegisterValidation("workerGroupName", workerGroupNameValidator)
if err != nil {
return err
}
return nil
}

View File

@@ -17,6 +17,7 @@ var (
computeNetTypeValues = []string{"EXTNET", "VINS"}
computeOrderValues = []string{"cdrom", "network", "hd"}
computeDataDisksValues = []string{"KEEP", "DETACH", "DESTROY"}
computeDriverValues = []string{"KVM_X86", "SVA_KVM_X86"}
diskTypeValues = []string{"B", "T", "D"}

View File

@@ -1,23 +1,31 @@
package decortsdk
import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"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/client"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker"
)
// Legacy HTTP-client for platform
type LegacyDecortClient struct {
decortURL string
client *http.Client
decortURL string
client *http.Client
cfg config.LegacyConfig
expiryTime time.Time
mutex *sync.Mutex
}
// Legacy client builder
@@ -26,9 +34,25 @@ func NewLegacy(cfg config.LegacyConfig) *LegacyDecortClient {
cfg.Retries = 5
}
var expiryTime time.Time
if cfg.Token != "" {
expiryTime = time.Now().AddDate(0, 0, 1)
}
return &LegacyDecortClient{
decortURL: cfg.DecortURL,
client: client.NewLegacyHttpClient(cfg),
client: &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
//nolint:gosec
InsecureSkipVerify: cfg.SSLSkipVerify,
},
},
},
cfg: cfg,
expiryTime: expiryTime,
mutex: &sync.Mutex{},
}
}
@@ -49,13 +73,18 @@ func (ldc *LegacyDecortClient) DecortApiCall(ctx context.Context, method, url st
return nil, err
}
body := strings.NewReader(values.Encode())
if err = ldc.getToken(ctx); err != nil {
return nil, err
}
body := strings.NewReader(values.Encode() + fmt.Sprintf("&authkey=%s", ldc.cfg.Token))
req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+"/restmachine"+url, body)
if err != nil {
return nil, err
}
resp, err := ldc.client.Do(req)
resp, err := ldc.do(req)
if err != nil {
return nil, err
}
@@ -72,3 +101,60 @@ func (ldc *LegacyDecortClient) DecortApiCall(ctx context.Context, method, url st
return respBytes, nil
}
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)
}
return nil
}
func (ldc *LegacyDecortClient) do(req *http.Request) (*http.Response, error) {
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json")
var resp *http.Response
var err error
buf, _ := io.ReadAll(req.Body)
for i := uint64(0); i < ldc.cfg.Retries; i++ {
req := req.Clone(req.Context())
req.Body = io.NopCloser(bytes.NewBuffer(buf))
resp, err = ldc.client.Do(req)
if err == nil {
if resp.StatusCode == 200 {
return resp, err
}
respBytes, _ := io.ReadAll(resp.Body)
err = fmt.Errorf("%s", respBytes)
resp.Body.Close()
}
}
return nil, fmt.Errorf("could not execute request: %w", err)
}

View File

@@ -16,7 +16,7 @@ type GetResourceConsumptionRequest struct {
}
// GetResourceConsumption show amount of consumed and reserved resources (cpu, ram, disk) by specific account
func (a Account) GetResourceConsumption(ctx context.Context, req GetResourceConsumptionRequest) (*ItemResourceConsumption, error) {
func (a Account) GetResourceConsumption(ctx context.Context, req GetResourceConsumptionRequest) (*RecordResourceConsumption, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -26,7 +26,7 @@ func (a Account) GetResourceConsumption(ctx context.Context, req GetResourceCons
url := "/cloudapi/account/getResourceConsumption"
info := ItemResourceConsumption{}
info := RecordResourceConsumption{}
res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {

View File

@@ -12,15 +12,35 @@ import (
type ListTemplatesRequest struct {
// ID an account
// Required: true
AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// Include deleted images
// Required: false
IncludeDeleted bool `url:"includedeleted" json:"includedeleted"`
IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"`
// Find by image id
// Required: false
ImageID uint64 `url:"imageId,omitempty" json:"imageId,omitempty"`
// Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by type
// Required: false
Type string `url:"type,omitempty" json:"type,omitempty"`
// Page number
// Required: false
Page uint64 `url:"page,omitempty" json:"page,omitempty"`
// Page size
// Required: false
Size uint64 `url:"size,omitempty" json:"size,omitempty"`
}
// ListTemplates gets list templates which can be managed by this account
func (a Account) ListTemplates(ctx context.Context, req ListTemplatesRequest) (ListTemplates, error) {
func (a Account) ListTemplates(ctx context.Context, req ListTemplatesRequest) (*ListTemplates, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -42,5 +62,5 @@ func (a Account) ListTemplates(ctx context.Context, req ListTemplatesRequest) (L
return nil, err
}
return list, nil
return &list, nil
}

View File

@@ -33,7 +33,7 @@ type ResourceLimits struct {
CUD float64 `json:"CU_D"`
// Max disk size, GB
CU_DM float64 `json:"CU_DM"`
CUDM float64 `json:"CU_DM"`
// Number of public IP addresses
CUI float64 `json:"CU_I"`
@@ -115,6 +115,14 @@ type DiskUsage struct {
DiskSizeMax float64 `json:"disksizemax"`
}
// Information about resource consumption
type RecordResourceConsumption struct {
ItemResourceConsumption
// Resource limits
ResourceLimits ResourceLimits `json:"resourceLimits"`
}
// Information about resources
type ItemResourceConsumption struct {
// Current information about resources
@@ -557,7 +565,13 @@ type ItemTemplate struct {
}
// List of templates
type ListTemplates []ItemTemplate
type ListTemplates struct {
// Data
Data []ItemTemplate `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about FLIPGroup
type ItemFLIPGroup struct {

View File

@@ -0,0 +1,40 @@
package compute
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for deleting compute's custome 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 {
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/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
}

View File

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

View File

@@ -20,7 +20,7 @@ type DiskDelRequest struct {
// False if disk is to be deleted to recycle bin
// Required: true
Permanently bool `url:"permanently" json:"permanently" validate:"required"`
Permanently bool `url:"permanently" json:"permanently"`
}
// DiskDel delete disk and detach from compute

View File

@@ -0,0 +1,42 @@
package compute
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for getting Compute's customFields
type GetCustomFieldsRequest struct {
// Compute ID
// Required: true
ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
// GetCustomFields gets Compute's customFields
func (c Compute) GetCustomFields(ctx context.Context, req GetCustomFieldsRequest) (interface{}, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudapi/compute/getCustomFields"
res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
var info interface{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}
return &info, nil
}

View File

@@ -14,6 +14,14 @@ type RecordACL struct {
RGACL ListACL `json:"rgAcl"`
}
type ListUsers struct {
// Data
Data RecordACL `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
type Explicit bool
func (e *Explicit) UnmarshalJSON(b []byte) error {
@@ -89,7 +97,13 @@ type ItemSnapshot struct {
}
// List of snapshots
type ListSnapShots []ItemSnapshot
type ListSnapShots struct {
// Data
Data []ItemSnapshot `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about port forward
type ItemPFW struct {
@@ -116,7 +130,13 @@ type ItemPFW struct {
}
// List port forwards
type ListPFWs []ItemPFW
type ListPFWs struct {
// Data
Data []ItemPFW `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about affinity relations
type RecordAffinityRelations struct {
@@ -403,7 +423,7 @@ type RecordCompute struct {
SnapSets ListSnapSets `json:"snapSets"`
// Stateless SepID
StatelessSepID uint64 `json:"statelessSepId"`
StatelessSepID int64 `json:"statelessSepId"`
// Stateless SepType
StatelessSepType string `json:"statelessSepType"`
@@ -862,7 +882,7 @@ type ItemCompute struct {
SnapSets ListSnapSets `json:"snapSets"`
// Stateless SepID
StatelessSepID uint64 `json:"statelessSepId"`
StatelessSepID int64 `json:"statelessSepId"`
// Stateless SepType
StatelessSepType string `json:"statelessSepType"`

View File

@@ -16,7 +16,7 @@ type PFWListRequest struct {
}
// PFWList gets compute port forwards list
func (c Compute) PFWList(ctx context.Context, req PFWListRequest) (ListPFWs, error) {
func (c Compute) PFWList(ctx context.Context, req PFWListRequest) (*ListPFWs, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -38,5 +38,5 @@ func (c Compute) PFWList(ctx context.Context, req PFWListRequest) (ListPFWs, err
return nil, err
}
return list, nil
return &list, nil
}

View File

@@ -0,0 +1,43 @@
package compute
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for setting customFields values for the Compute
type SetCustomFieldsRequest struct {
// ID of the compute
// Required: true
ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
// Custom fields for Compute. Must be dict.
// Required: true
CustomFields string `url:"customFields" json:"customFields" validate:"required"`
}
// SetCustomFields sets customFields values for the Compute
func (c Compute) SetCustomFields(ctx context.Context, req SetCustomFieldsRequest) (bool, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudapi/compute/setCustomFields"
res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
}

View File

@@ -16,7 +16,7 @@ type SnapshotListRequest struct {
}
// SnapshotList gets list compute snapshots
func (c Compute) SnapshotList(ctx context.Context, req SnapshotListRequest) (ListSnapShots, error) {
func (c Compute) SnapshotList(ctx context.Context, req SnapshotListRequest) (*ListSnapShots, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -38,5 +38,5 @@ func (c Compute) SnapshotList(ctx context.Context, req SnapshotListRequest) (Lis
return nil, err
}
return list, nil
return &list, nil
}

View File

@@ -16,7 +16,7 @@ type UserListRequest struct {
}
// UserList gets users list for compute
func (c Compute) UserList(ctx context.Context, req UserListRequest) (*RecordACL, error) {
func (c Compute) UserList(ctx context.Context, req UserListRequest) (*ListUsers, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -31,7 +31,7 @@ func (c Compute) UserList(ctx context.Context, req UserListRequest) (*RecordACL,
return nil, err
}
list := RecordACL{}
list := ListUsers{}
err = json.Unmarshal(res, &list)
if err != nil {

View File

@@ -1,10 +0,0 @@
package cloudapi
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/computeci"
)
// Accessing the ComputeCI method group
func (ca *CloudAPI) ComputeCI() *computeci.ComputeCI {
return computeci.New(ca.client)
}

View File

@@ -1,18 +0,0 @@
// API Actor for managing ComputeCI. This actor is a final API for admin to manage ComputeCI
package computeci
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
)
// Structure for creating request to computeci
type ComputeCI struct {
client interfaces.Caller
}
// Builder for computeci endpoints
func New(client interfaces.Caller) *ComputeCI {
return &ComputeCI{
client,
}
}

View File

@@ -1,53 +0,0 @@
package computeci
// FilterByID returns ListComputeCI with specified ID.
func (lci ListComputeCI) FilterByID(id uint64) ListComputeCI {
predicate := func(ic ItemComputeCI) bool {
return ic.ID == id
}
return lci.FilterFunc(predicate)
}
// FilterByName returns ListComputeCI with specified Name.
func (lci ListComputeCI) FilterByName(name string) ListComputeCI {
predicate := func(ic ItemComputeCI) bool {
return ic.Name == name
}
return lci.FilterFunc(predicate)
}
// FilterByStatus returns ListComputeCI with specified Status.
func (lci ListComputeCI) FilterByStatus(status string) ListComputeCI {
predicate := func(ic ItemComputeCI) bool {
return ic.Status == status
}
return lci.FilterFunc(predicate)
}
// FilterFunc allows filtering ListComputeCI based on a user-specified predicate.
func (lci ListComputeCI) FilterFunc(predicate func(ItemComputeCI) bool) ListComputeCI {
var result ListComputeCI
for _, item := range lci.Data {
if predicate(item) {
result.Data = append(result.Data, item)
}
}
result.EntryCount = uint64(len(result.Data))
return result
}
// FindOne returns first found ItemComputeCI
// If none was found, returns an empty struct.
func (lci ListComputeCI) FindOne() ItemComputeCI {
if lci.EntryCount == 0 {
return ItemComputeCI{}
}
return lci.Data[0]
}

View File

@@ -1,98 +0,0 @@
package computeci
import "testing"
var computeciItems = ListComputeCI{
Data: []ItemComputeCI{
{
CustomFields: map[string]interface{}{},
Description: "",
Drivers: []string{
"KVM_X86",
},
GUID: 1,
ID: 1,
Name: "computeci_1",
Status: "ENABLED",
Template: "",
},
{
CustomFields: map[string]interface{}{},
Description: "",
Drivers: []string{
"KVM_X86",
},
GUID: 2,
ID: 2,
Name: "computeci_2",
Status: "ENABLED",
Template: "",
},
{
CustomFields: map[string]interface{}{},
Description: "",
Drivers: []string{
"SVA_KVM_X86",
},
GUID: 3,
ID: 3,
Name: "computeci_3",
Status: "DISABLED",
Template: "",
},
},
EntryCount: 3,
}
func TestFilterByID(t *testing.T) {
actual := computeciItems.FilterByID(2).FindOne()
if actual.ID != 2 {
t.Fatal("expected ID 2, found: ", actual.ID)
}
}
func TestFilterByName(t *testing.T) {
actual := computeciItems.FilterByName("computeci_3").FindOne()
if actual.Name != "computeci_3" {
t.Fatal("expected Name 'computeci_2', found: ", actual.Name)
}
}
func TestFilterByStatus(t *testing.T) {
actual := computeciItems.FilterByStatus("ENABLED")
if len(actual.Data) != 2 {
t.Fatal("expected 2 found, actual: ", len(actual.Data))
}
for _, item := range actual.Data {
if item.Status != "ENABLED" {
t.Fatal("expected Status 'ENABLED', found: ", item.Status)
}
}
}
func TestFilterFunc(t *testing.T) {
actual := computeciItems.FilterFunc(func(icc ItemComputeCI) bool {
for _, item := range icc.Drivers {
if item == "KVM_X86" {
return true
}
}
return false
})
if len(actual.Data) != 2 {
t.Fatal("expected 2 found, actual: ", len(actual.Data))
}
for _, item := range actual.Data {
for _, driver := range item.Drivers {
if driver != "KVM_X86" {
t.Fatal("expected 'KVM_X86' Driver, found: ", driver)
}
}
}
}

View File

@@ -1,42 +0,0 @@
package computeci
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for information about computeci
type GetRequest struct {
// ID of the Compute CI
// Required: true
ComputeCIID uint64 `url:"computeciId" json:"computeciId" validate:"required"`
}
// Get gets information about computeci by ID
func (c ComputeCI) Get(ctx context.Context, req GetRequest) (*ItemComputeCI, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validatonError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validatonError)
}
}
url := "/cloudapi/computeci/get"
res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
info := ItemComputeCI{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}
return &info, nil
}

View File

@@ -1,35 +0,0 @@
package computeci
// Main information about computeci
type ItemComputeCI struct {
// Custom fields
CustomFields map[string]interface{} `json:"customFields"`
// Description
Description string `json:"desc"`
// List drivers
Drivers []string `json:"drivers"`
// GUID
GUID uint64 `json:"guid"`
// ID
ID uint64 `json:"id"`
// Name
Name string `json:"name"`
// Status
Status string `json:"status"`
// Template
Template string `json:"template"`
}
// List of computeci instances
type ListComputeCI struct {
Data []ItemComputeCI `json:"data"`
EntryCount uint64 `json:"entryCount"`
}

View File

@@ -40,6 +40,14 @@ type ListRequest struct {
// Required: false
Type string `url:"type,omitempty" json:"type,omitempty"`
// Find by sep ID
// Required: false
SEPID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`
// Find by pool name
// Required: false
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Page number
// Required: false
Page uint64 `url:"page,omitempty" json:"page,omitempty"`

View File

@@ -24,10 +24,6 @@ type ListUnattachedRequest struct {
// Required: false
Status string `url:"status,omitempty" json:"status,omitempty"`
// Find by shared, true or false
// Required: false
Shared bool `url:"shared,omitempty" json:"shared,omitempty"`
// Type of the disks
// Required: false
Type string `url:"type,omitempty" json:"type,omitempty"`
@@ -36,6 +32,14 @@ type ListUnattachedRequest struct {
// Required: false
AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"`
// Find by sep ID
// Required: false
SEPID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`
// Find by pool name
// Required: false
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Page number
// Required: false
Page uint64 `url:"page,omitempty" json:"page,omitempty"`

View File

@@ -13,10 +13,26 @@ type ListComputesRequest struct {
// Filter by account ID
// Required: true
AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// Find by rg ID
// Required: false
RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"`
// Find by compute ID
// Required: false
ComputeID uint64 `url:"computeId,omitempty" json:"computeId,omitempty"`
// Page number
// Required: false
Page uint64 `url:"page,omitempty" json:"page,omitempty"`
// Page size
// Required: false
Size uint64 `url:"size,omitempty" json:"size,omitempty"`
}
// ListComputes gets computes from account with extnets
func (e ExtNet) ListComputes(ctx context.Context, req ListComputesRequest) (ListExtNetComputes, error) {
func (e ExtNet) ListComputes(ctx context.Context, req ListComputesRequest) (*ListExtNetComputes, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -38,5 +54,5 @@ func (e ExtNet) ListComputes(ctx context.Context, req ListComputesRequest) (List
return nil, err
}
return list, nil
return &list, nil
}

View File

@@ -59,7 +59,13 @@ type ItemExtNetCompute struct {
}
// List of information about computes with external network
type ListExtNetComputes []ItemExtNetCompute
type ListExtNetComputes struct {
// Data
Data []ItemExtNetCompute `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// QOS
type QOS struct {
@@ -118,6 +124,12 @@ type Excluded struct {
// ClientType
ClientType string `json:"clientType"`
// Domain name
DomainName string `json:"domainname"`
// Host name
HostName string `json:"hostname"`
// IP
IP string `json:"ip"`

View File

@@ -45,7 +45,7 @@ type CreateRequest struct {
}
// Create method will create a new FLIPGorup in the specified Account
func (f FLIPGroup) Create(ctx context.Context, req CreateRequest) (*RecordFLIPGroup, error) {
func (f FLIPGroup) Create(ctx context.Context, req CreateRequest) (*RecordFLIPGroupCreated, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -60,7 +60,7 @@ func (f FLIPGroup) Create(ctx context.Context, req CreateRequest) (*RecordFLIPGr
return nil, err
}
info := RecordFLIPGroup{}
info := RecordFLIPGroupCreated{}
err = json.Unmarshal(res, &info)
if err != nil {

View File

@@ -16,7 +16,7 @@ type GetRequest struct {
}
// Get gets details of the specified Floating IP group
func (f FLIPGroup) Get(ctx context.Context, req GetRequest) (*ItemFLIPGroup, error) {
func (f FLIPGroup) Get(ctx context.Context, req GetRequest) (*RecordFLIPGroup, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -31,7 +31,7 @@ func (f FLIPGroup) Get(ctx context.Context, req GetRequest) (*ItemFLIPGroup, err
return nil, err
}
info := ItemFLIPGroup{}
info := RecordFLIPGroup{}
err = json.Unmarshal(res, &info)
if err != nil {

View File

@@ -1,7 +1,7 @@
package flipgroup
// Main information about FLIPGroup
type RecordFLIPGroup struct {
type RecordFLIPGroupCreated struct {
// Default GW
DefaultGW string `json:"defaultGW"`
@@ -18,6 +18,89 @@ type RecordFLIPGroup struct {
NetMask uint64 `json:"netmask"`
}
type RecordFLIPGroup struct {
// Account ID
AccountID uint64 `json:"accountId"`
// Account name
AccountName string `json:"accountName"`
// List of client IDs
ClientIDs []uint64 `json:"clientIds"`
// Client names
ClientNames []string `json:"clientNames"`
// Client type
ClientType string `json:"clientType"`
// Connection ID
ConnID uint64 `json:"connId"`
// Connection type
ConnType string `json:"connType"`
// Created by
CreatedBy string `json:"createdBy"`
// Created time
CreatedTime uint64 `json:"createdTime"`
// Default GW
DefaultGW string `json:"defaultGW"`
// Deleted by
DeletedBy string `json:"deletedBy"`
// Deleted time
DeletedTime uint64 `json:"deletedTime"`
// Description
Description string `json:"desc"`
// Grid ID
GID uint64 `json:"gid"`
// GUID
GUID uint64 `json:"guid"`
// ID
ID uint64 `json:"id"`
// IP
IP string `json:"ip"`
// Milestones
Milestones uint64 `json:"milestones"`
// Name
Name string `json:"name"`
// Network ID
NetID uint64 `json:"netId"`
// Network type
NetType string `json:"netType"`
// Network
Network string `json:"network"`
// Resource group ID
RGID uint64 `json:"rgId"`
// Resource group name
RGName string `json:"rgName"`
// Status
Status string `json:"status"`
// Updated by
UpdatedBy string `json:"updatedBy"`
// Updated time
UpdatedTime uint64 `json:"updatedTime"`
}
// Detailed information about FLIPGroup
type ItemFLIPGroup struct {
// CKey

View File

@@ -24,7 +24,7 @@ type CreateRequest struct {
// Name for first worker group created with cluster
// Required: true
WorkerGroupName string `url:"workerGroupName" json:"workerGroupName" validate:"required"`
WorkerGroupName string `url:"workerGroupName" json:"workerGroupName" validate:"required,workerGroupName"`
// Network plugin
// Must be one of these values: flannel, weawenet, calico
@@ -106,6 +106,10 @@ type CreateRequest struct {
// Text description of this Kubernetes cluster
// Required: false
Description string `url:"desc,omitempty" json:"desc,omitempty"`
//Use only selected ExtNet for infrastructure connections
// Required: false
ExtNetOnly bool `url:"extnetOnly,omitempty" json:"extnetOnly,omitempty"`
}
// Create creates a new Kubernetes cluster in the specified Resource Group

View File

@@ -64,8 +64,10 @@ type CreateRequest struct {
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Slice of structs with net interface description.
// If not specified, compute will be created with default interface from RG.
// To create compute without interfaces, pass initialized empty slice .
// Required: false
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"`
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"`
// Input data for cloud-init facility
// Required: false
@@ -102,15 +104,21 @@ func (k KVMPPC) Create(ctx context.Context, req CreateRequest) (uint64, error) {
}
}
interfaces := make([]string, 0, len(req.Interfaces))
var interfaces []string
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
if req.Interfaces != nil && len(req.Interfaces) != 0 {
interfaces = make([]string, 0, len(req.Interfaces))
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
}
interfaces = append(interfaces, string(b))
}
interfaces = append(interfaces, string(b))
} else if req.Interfaces != nil && len(req.Interfaces) == 0 {
interfaces = []string{"[]"}
}
reqWrapped := wrapperCreateRequest{

View File

@@ -41,9 +41,11 @@ type CreateBlankRequest struct {
// Required: true
Pool string `url:"pool" json:"pool" validate:"required"`
// Slice of structs with net interface description
// Slice of structs with net interface description.
// If not specified, compute will be created with default interface from RG.
// To create compute without interfaces, pass initialized empty slice .
// Required: false
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"`
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"`
// Text description of this VM
// Required: false
@@ -64,15 +66,21 @@ func (k KVMPPC) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64
}
}
interfaces := make([]string, 0, len(req.Interfaces))
var interfaces []string
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
if req.Interfaces != nil && len(req.Interfaces) != 0 {
interfaces = make([]string, 0, len(req.Interfaces))
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
}
interfaces = append(interfaces, string(b))
}
interfaces = append(interfaces, string(b))
} else if req.Interfaces != nil && len(req.Interfaces) == 0 {
interfaces = []string{"[]"}
}
reqWrapped := wrapperCreateBlankRequest{

View File

@@ -64,8 +64,10 @@ type CreateRequest struct {
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Slice of structs with net interface description.
// If not specified, compute will be created with default interface from RG.
// To create compute without interfaces, pass initialized empty slice .
// Required: false
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"`
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"`
// Input data for cloud-init facility
// Required: false
@@ -86,6 +88,14 @@ type CreateRequest struct {
// Compute purpose
// Required: false
IPAType string `url:"ipaType,omitempty" json:"ipaType,omitempty"`
// Custom fields for compute. Must be a dict
// Required: false
CustomFields string `url:"customFields,omitempty" json:"customFields,omitempty"`
// Type of compute Stateful (KVM_X86) or Stateless (SVA_KVM_X86)
// Required: false
Driver string `url:"driver,omitempty" json:"driver,omitempty" validate:"omitempty,computeDriver"`
}
type wrapperCreateRequest struct {
@@ -102,15 +112,21 @@ func (k KVMX86) Create(ctx context.Context, req CreateRequest) (uint64, error) {
}
}
interfaces := make([]string, 0, len(req.Interfaces))
var interfaces []string
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
if req.Interfaces != nil && len(req.Interfaces) != 0 {
interfaces = make([]string, 0, len(req.Interfaces))
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
}
interfaces = append(interfaces, string(b))
}
interfaces = append(interfaces, string(b))
} else if req.Interfaces != nil && len(req.Interfaces) == 0 {
interfaces = []string{"[]"}
}
reqWrapped := wrapperCreateRequest{

View File

@@ -42,8 +42,14 @@ type CreateBlankRequest struct {
Pool string `url:"pool" json:"pool" validate:"required"`
// Slice of structs with net interface description.
// If not specified, compute will be created with default interface from RG.
// To create compute without interfaces, pass initialized empty slice .
// Required: false
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"`
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"`
// Type of compute Stateful (KVM_X86) or Stateless (SVA_KVM_X86)
// Required: false
Driver string `url:"driver,omitempty" json:"driver,omitempty" validate:"omitempty,computeDriver"`
// Text description of this VM
// Required: false
@@ -64,15 +70,21 @@ func (k KVMX86) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64
}
}
interfaces := make([]string, 0, len(req.Interfaces))
var interfaces []string
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
if req.Interfaces != nil && len(req.Interfaces) != 0 {
interfaces = make([]string, 0, len(req.Interfaces))
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
}
interfaces = append(interfaces, string(b))
}
interfaces = append(interfaces, string(b))
} else if req.Interfaces != nil && len(req.Interfaces) == 0 {
interfaces = []string{"[]"}
}
reqWrapped := wrapperCreateBlankRequest{

View File

@@ -2,6 +2,7 @@ package lb
import (
"context"
"errors"
"net/http"
"strings"
@@ -20,16 +21,16 @@ type CreateRequest struct {
Name string `url:"name" json:"name" validate:"required"`
// External network to connect this load balancer to
// Required: true
ExtNetID uint64 `url:"extnetId" json:"extnetId" validate:"required"`
// Required: false
ExtNetID uint64 `url:"extnetId" json:"extnetId"`
// Internal network (VINS) to connect this load balancer to
// Required: true
VINSID uint64 `url:"vinsId" json:"vinsId" validate:"required"`
// Required: false
VINSID uint64 `url:"vinsId" json:"vinsId"`
// Start now Load balancer
// Required: true
Start bool `url:"start" json:"start" validate:"required"`
// Required: false
Start bool `url:"start" json:"start"`
// Text description of this load balancer
// Required: false
@@ -45,6 +46,10 @@ func (l LB) Create(ctx context.Context, req CreateRequest) (string, error) {
}
}
if req.ExtNetID == 0 && req.VINSID == 0 {
return "", errors.New ("vinsId and extNetId cannot be both in the value 0")
}
url := "/cloudapi/lb/create"
res, err := l.client.DecortApiCall(ctx, http.MethodPost, url, req)

View File

@@ -20,7 +20,7 @@ type AffinityGroupComputesRequest struct {
}
// AffinityGroupComputes gets list of all computes with their relationships to another computes
func (r RG) AffinityGroupComputes(ctx context.Context, req AffinityGroupComputesRequest) (ListAffinityGroups, error) {
func (r RG) AffinityGroupComputes(ctx context.Context, req AffinityGroupComputesRequest) (ListAffinityGroupsComputes, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -35,7 +35,7 @@ func (r RG) AffinityGroupComputes(ctx context.Context, req AffinityGroupComputes
return nil, err
}
list := ListAffinityGroups{}
list := ListAffinityGroupsComputes{}
err = json.Unmarshal(res, &list)
if err != nil {

View File

@@ -16,7 +16,7 @@ type AffinityGroupsListRequest struct {
}
// AffinityGroupsList gets all currently defined affinity groups in this resource group with compute IDs
func (r RG) AffinityGroupsList(ctx context.Context, req AffinityGroupsListRequest) (map[string][]uint64, error) {
func (r RG) AffinityGroupsList(ctx context.Context, req AffinityGroupsListRequest) (*ListAffinityGroups, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -31,7 +31,7 @@ func (r RG) AffinityGroupsList(ctx context.Context, req AffinityGroupsListReques
return nil, err
}
list := map[string][]uint64{}
list := &ListAffinityGroups{}
err = json.Unmarshal(res, &list)
if err != nil {

View File

@@ -53,6 +53,9 @@ type ItemResourceConsumption struct {
// Reserved information about resources
Reserved Resource `json:"Reserved"`
// Resource limits
ResourceLimits ResourceLimits `json:"resourceLimits"`
// Resource group ID
RGID uint64 `json:"rgid"`
}
@@ -302,7 +305,7 @@ type ResourceLimits struct {
}
// Main information about affinity group
type ItemAffinityGroup struct {
type ItemAffinityGroupComputes struct {
// Compute ID
ComputeID uint64 `json:"computeId"`
@@ -326,7 +329,15 @@ type ItemAffinityGroup struct {
}
// List of affinity groups
type ListAffinityGroups []ItemAffinityGroup
type ListAffinityGroupsComputes []ItemAffinityGroupComputes
type ListAffinityGroups struct {
// Data
Data map[string][]uint64 `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about audit
type ItemAudit struct {

View File

@@ -37,6 +37,7 @@ func (r RG) Usage(ctx context.Context, req UsageRequest) (*RecordResourceUsage,
info := RecordResourceUsage{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}

View File

@@ -22,21 +22,23 @@ func (ls ListSizes) FilterByName(name string) ListSizes {
func (ls ListSizes) FilterFunc(predicate func(ItemSize) bool) ListSizes {
var result ListSizes
for _, item := range ls {
for _, item := range ls.Data {
if predicate(item) {
result = append(result, item)
result.Data = append(result.Data, item)
}
}
result.EntryCount = uint64(len(result.Data))
return result
}
// FindOne returns first found ItemSize
// If none was found, returns an empty struct.
func (ls ListSizes) FindOne() ItemSize {
if len(ls) == 0 {
if len(ls.Data) == 0 {
return ItemSize{}
}
return ls[0]
return ls.Data[0]
}

View File

@@ -3,30 +3,33 @@ package sizes
import "testing"
var sizeItems = ListSizes{
{
Description: "",
Disks: []uint64{},
ID: 1,
Memory: 512,
Name: "size_1",
VCPUs: 2,
},
{
Description: "",
Disks: []uint64{},
ID: 2,
Memory: 1024,
Name: "size_2",
VCPUs: 4,
},
{
Description: "",
Disks: []uint64{},
ID: 2,
Memory: 2048,
Name: "size_3",
VCPUs: 6,
Data: []ItemSize{
{
Description: "",
Disks: []uint64{},
ID: 1,
Memory: 512,
Name: "size_1",
VCPUs: 2,
},
{
Description: "",
Disks: []uint64{},
ID: 2,
Memory: 1024,
Name: "size_2",
VCPUs: 4,
},
{
Description: "",
Disks: []uint64{},
ID: 2,
Memory: 2048,
Name: "size_3",
VCPUs: 6,
},
},
EntryCount: 3,
}
func TestFilterByID(t *testing.T) {
@@ -50,11 +53,11 @@ func TestFilterFunc(t *testing.T) {
return is.Memory > 512
})
if len(actual) != 2 {
t.Fatal("expected 2 found, actual: ", len(actual))
if len(actual.Data) != 2 {
t.Fatal("expected 2 found, actual: ", len(actual.Data))
}
for _, item := range actual {
for _, item := range actual.Data {
if item.Memory <= 512 {
t.Fatal("expected Memory greater than 512, found: ", item.Memory)
}

View File

@@ -26,7 +26,7 @@ type ListRequest struct {
}
// List gets list the available flavors, filtering can be based on the user which is doing the request
func (s Sizes) List(ctx context.Context, req ListRequest) (ListSizes, error) {
func (s Sizes) List(ctx context.Context, req ListRequest) (*ListSizes, error) {
url := "/cloudapi/sizes/list"
res, err := s.client.DecortApiCall(ctx, http.MethodPost, url, req)
@@ -34,7 +34,7 @@ func (s Sizes) List(ctx context.Context, req ListRequest) (ListSizes, error) {
return nil, err
}
list := ListSizes{}
list := &ListSizes{}
err = json.Unmarshal(res, &list)
if err != nil {

View File

@@ -22,4 +22,10 @@ type ItemSize struct {
}
// List of configured available flavors
type ListSizes []ItemSize
type ListSizes struct {
// Data
Data []ItemSize `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}

View File

@@ -12,7 +12,7 @@ import (
// - First argument -> prefix
// - Second argument -> indent
func (ls ListSizes) Serialize(params ...string) (serialization.Serialized, error) {
if len(ls) == 0 {
if len(ls.Data) == 0 {
return []byte{}, nil
}

View File

@@ -16,7 +16,7 @@ type ExtNetListRequest struct {
}
// ExtNetList show list of VINS external network connections
func (v VINS) ExtNetList(ctx context.Context, req ExtNetListRequest) (ListExtNets, error) {
func (v VINS) ExtNetList(ctx context.Context, req ExtNetListRequest) (*ListExtNets, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -31,7 +31,7 @@ func (v VINS) ExtNetList(ctx context.Context, req ExtNetListRequest) (ListExtNet
return nil, err
}
list := ListExtNets{}
list := &ListExtNets{}
err = json.Unmarshal(res, &list)
if err != nil {

View File

@@ -16,7 +16,7 @@ type IPListRequest struct {
}
// IPList show DHCP IP reservations on VINS
func (v VINS) IPList(ctx context.Context, req IPListRequest) (ListIPs, error) {
func (v VINS) IPList(ctx context.Context, req IPListRequest) (*ListIPs, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -31,7 +31,7 @@ func (v VINS) IPList(ctx context.Context, req IPListRequest) (ListIPs, error) {
return nil, err
}
list := ListIPs{}
list := &ListIPs{}
err = json.Unmarshal(res, &list)
if err != nil {

View File

@@ -104,7 +104,13 @@ type ItemExtNet struct {
}
// List of external networks
type ListExtNets []ItemExtNet
type ListExtNets struct {
// Data
Data []ItemExtNet `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about IP
type ItemIP struct {
@@ -131,7 +137,13 @@ type ItemIP struct {
}
// List of IPs
type ListIPs []ItemIP
type ListIPs struct {
// Data
Data []ItemIP `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about VNF device
type RecordVNFDev struct {
@@ -671,7 +683,13 @@ type ItemNATRule struct {
}
// List of NAT rules
type ListNATRules []ItemNATRule
type ListNATRules struct {
// Data
Data []ItemNATRule `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// Main information about reservation
type ItemReservation struct {

View File

@@ -16,7 +16,7 @@ type NATRuleListRequest struct {
}
// NATRuleList gets list of NAT (port forwarding) rules
func (v VINS) NATRuleList(ctx context.Context, req NATRuleListRequest) (ListNATRules, error) {
func (v VINS) NATRuleList(ctx context.Context, req NATRuleListRequest) (*ListNATRules, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -31,7 +31,7 @@ func (v VINS) NATRuleList(ctx context.Context, req NATRuleListRequest) (ListNATR
return nil, err
}
list := ListNATRules{}
list := &ListNATRules{}
err = json.Unmarshal(res, &list)
if err != nil {

View File

@@ -20,7 +20,7 @@ type DeleteUserRequest struct {
// Recursively revoke access rights from owned cloudspaces and vmachines
// Required: false
RecursiveDelete bool `url:"recursivedelete,omitempty" json:"recursivedelete,omitempty"`
RecursiveDelete bool `url:"recursivedelete" json:"recursivedelete" validate:"required"`
}
// DeleteUser revokes user access from the account

View File

@@ -16,7 +16,7 @@ type DisableRequest struct {
// Reason to disable
// Required: true
Reason string `url:"reason" json:"reason" validate:"required"`
Reason string `url:"reason,omitempty" json:"reason,omitempty"`
}
// Disable disables an account

View File

@@ -16,7 +16,7 @@ type EnableRequest struct {
// Reason to enable
// Required: true
Reason string `url:"reason" json:"reason" validate:"required"`
Reason string `url:"reason,omitempty" json:"reason,omitempty"`
}
// Enable enables an account

View File

@@ -16,7 +16,7 @@ type GetResourceConsumptionRequest struct {
}
// GetResourceConsumption show amount of consumed and reserved resources (cpu, ram, disk) by specific account
func (a Account) GetResourceConsumption(ctx context.Context, req GetResourceConsumptionRequest) (*RecordResources, error) {
func (a Account) GetResourceConsumption(ctx context.Context, req GetResourceConsumptionRequest) (*RecordResourceConsumption, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
@@ -26,7 +26,7 @@ func (a Account) GetResourceConsumption(ctx context.Context, req GetResourceCons
url := "/cloudbroker/account/getResourceConsumption"
info := RecordResources{}
info := RecordResourceConsumption{}
res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {

View File

@@ -16,7 +16,7 @@ type ListVINSRequest struct {
// Find by VINS ID
// Required: false
VINSID uint64 `url:"vins,omitempty" json:"vinsId,omitempty"`
VINSID uint64 `url:"vinsId,omitempty" json:"vinsId,omitempty"`
// Find by name
// Required: false

View File

@@ -21,7 +21,13 @@ type ItemAudit struct {
// List of audits
type ListAudits []ItemAudit
type RecordResources struct {
type RecordResourceConsumption struct {
ItemResourceConsumption
ResourceLimits ResourceLimits `json:"resourceLimits"`
}
type ItemResourceConsumption struct {
// Current information about resources
Current Resource `json:"Current"`
@@ -34,7 +40,7 @@ type RecordResources struct {
type ListResources struct {
// Data
Data []RecordResources `json:"data"`
Data []ItemResourceConsumption `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`

View File

@@ -20,7 +20,7 @@ type DiskDelRequest struct {
// False if disk is to be deleted to recycle bin
// Required: true
Permanently bool `url:"permanently" json:"permanently" validate:"required"`
Permanently bool `url:"permanently" json:"permanently"`
// Reason for action
// Required: false

View File

@@ -40,6 +40,14 @@ type ListRequest struct {
// Required: false
Type string `url:"type,omitempty" json:"type,omitempty"`
// Find by sep ID
// Required: false
SEPID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`
// Find by pool name
// Required: false
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Page number
// Required: false
Page uint64 `url:"page,omitempty" json:"page,omitempty"`

View File

@@ -24,10 +24,6 @@ type ListUnattachedRequest struct {
// Required: false
Status string `url:"status,omitempty" json:"status,omitempty"`
// Find by shared, true or false
// Required: false
Shared bool `url:"shared,omitempty" json:"shared,omitempty"`
// Type of the disks
// Required: false
Type string `url:"type,omitempty" json:"type,omitempty"`
@@ -36,6 +32,14 @@ type ListUnattachedRequest struct {
// Required: false
AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"`
// Find by sep ID
// Required: false
SEPID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`
// Find by pool name
// Required: false
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Page number
// Required: false
Page uint64 `url:"page,omitempty" json:"page,omitempty"`

View File

@@ -0,0 +1,10 @@
package cloudbroker
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/flipgroup"
)
// Accessing the FLIPGroup method group
func (cb *CloudBroker) FLIPGroup() *flipgroup.FLIPGroup {
return flipgroup.New(cb.client)
}

View File

@@ -0,0 +1,44 @@
package flipgroup
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for add compute instance
type ComputeAddRequest struct {
// ID of the Floating IP group to add compute instance to
// Required: true
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId" validate:"required"`
// ID of the compute instance to add to this group
// Required: true
ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
// ComputeAdd add compute instance to the Floating IP group
func (f FLIPGroup) ComputeAdd(ctx context.Context, req ComputeAddRequest) (bool, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudbroker/flipgroup/computeAdd"
res, err := f.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
}

View File

@@ -0,0 +1,44 @@
package flipgroup
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for remove compute instance
type ComputeRemoveRequest struct {
// ID of the Floating IP group to remove compute instance from
// Required: true
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId" validate:"required"`
// ID of the compute instance to remove
// Required: true
ComputeID uint64 `url:"computeId" json:"computeId" validate:"required"`
}
// ComputeRemove remove compute instance from the Floating IP group
func (f FLIPGroup) ComputeRemove(ctx context.Context, req ComputeRemoveRequest) (bool, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudbroker/flipgroup/computeRemove"
res, err := f.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
}

View File

@@ -0,0 +1,71 @@
package flipgroup
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for create FLIPGroup
type CreateRequest struct {
// Account ID
// Required: true
AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// FLIPGroup name
// Required: true
Name string `url:"name" json:"name" validate:"required"`
// Network type
// Should be one of:
// - EXTNET
// - VINS
// Required: true
NetType string `url:"netType" json:"netType" validate:"computeNetType"`
// ID of external network or VINS
// Required: true
NetID uint64 `url:"netId" json:"netId" validate:"required"`
// Type of client
// - 'compute'
// - 'vins' (will be later)
// Required: true
ClientType string `url:"clientType" json:"clientType" validate:"flipgroupClientType"`
// IP address to associate with this group. If empty, the platform will autoselect IP address
// Required: false
IP string `url:"ip,omitempty" json:"ip,omitempty"`
// Text description of this FLIPGorup instance
// Required: false
Description string `url:"desc,omitempty" json:"desc,omitempty"`
}
// Create method will create a new FLIPGorup in the specified Account
func (f FLIPGroup) Create(ctx context.Context, req CreateRequest) (*RecordFLIPGroupCreated, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudbroker/flipgroup/create"
res, err := f.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
info := RecordFLIPGroupCreated{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}
return &info, nil
}

View File

@@ -0,0 +1,40 @@
package flipgroup
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for delete FLIPGroup
type DeleteRequest struct {
// FLIPGroup ID
// Required: true
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId" validate:"required"`
}
// Delete method wil delete Floating IP group
func (f FLIPGroup) Delete(ctx context.Context, req DeleteRequest) (bool, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudbroker/flipgroup/delete"
res, err := f.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
}

View File

@@ -0,0 +1,48 @@
package flipgroup
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for edit FLIPGroup
type EditRequest struct {
// FLIPGroup ID
// Required: true
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId" validate:"required"`
// FLIPGroup name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// FLIPGroup description
// Required: false
Description string `url:"desc,omitempty" json:"desc,omitempty"`
}
// Edit edits FLIPGroup fields
func (f FLIPGroup) Edit(ctx context.Context, req EditRequest) (bool, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return false, validators.ValidationError(validationError)
}
}
url := "/cloudbroker/flipgroup/edit"
res, err := f.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
}

View File

@@ -0,0 +1,18 @@
// API to manage FLIPGroup instances
package flipgroup
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
)
// Structure for creating request to FLIPGroup
type FLIPGroup struct {
client interfaces.Caller
}
// Builder for FLIPGroup endpoints
func New(client interfaces.Caller) *FLIPGroup {
return &FLIPGroup{
client: client,
}
}

View File

@@ -0,0 +1,42 @@
package flipgroup
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get information about FLIPGroup
type GetRequest struct {
// FLIPGroup ID
// Required: true
FLIPGroupID uint64 `url:"flipgroupId" json:"flipgroupId" validate:"required"`
}
// Get gets details of the specified Floating IP group
func (f FLIPGroup) Get(ctx context.Context, req GetRequest) (*RecordFLIPGroup, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudbroker/flipgroup/get"
res, err := f.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
info := RecordFLIPGroup{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}
return &info, nil
}

View File

@@ -0,0 +1,65 @@
package flipgroup
import (
"context"
"encoding/json"
"net/http"
)
// Request struct for get list FLIPGroup available to the current user
type ListRequest struct {
// Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by vinsId
// Required: false
VINSID uint64 `url:"vinsId,omitempty" json:"vinsId,omitempty"`
// Find by VINS name
// Required: false
VINSName string `url:"vinsName,omitempty" json:"vinsName,omitempty"`
// Find by extnetId
// Required: false
ExtNetID uint64 `url:"extnetId,omitempty" json:"extnetId,omitempty"`
// Find by IP
// Reuqired: false
ByIP string `url:"byIp,omitempty" json:"byIp,omitempty"`
// Find by resource group ID
// Reuqired: false
RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"`
// Find by id
// Required: false
ByID uint64 `url:"by_id,omitempty" json:"by_id,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 list FLIPGroup managed cluster instances available to the current user
func (f FLIPGroup) List(ctx context.Context, req ListRequest) (*ListFLIPGroups, error) {
url := "/cloudbroker/flipgroup/list"
res, err := f.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
list := ListFLIPGroups{}
err = json.Unmarshal(res, &list)
if err != nil {
return nil, err
}
return &list, nil
}

View File

@@ -0,0 +1,169 @@
package flipgroup
// Main information about FLIPGroup
type RecordFLIPGroupCreated struct {
// Default GW
DefaultGW string `json:"defaultGW"`
// ID
ID uint64 `json:"id"`
// IP
IP string `json:"ip"`
// Name
Name string `json:"name"`
// Network mask
NetMask uint64 `json:"netmask"`
}
type RecordFLIPGroup struct {
// Account ID
AccountID uint64 `json:"accountId"`
// Account name
AccountName string `json:"accountName"`
// List of client IDs
ClientIDs []uint64 `json:"clientIds"`
// Client names
ClientNames []string `json:"clientNames"`
// Client type
ClientType string `json:"clientType"`
// Connection ID
ConnID uint64 `json:"connId"`
// Connection type
ConnType string `json:"connType"`
// Created by
CreatedBy string `json:"createdBy"`
// Created time
CreatedTime uint64 `json:"createdTime"`
// Default GW
DefaultGW string `json:"defaultGW"`
// Deleted by
DeletedBy string `json:"deletedBy"`
// Deleted time
DeletedTime uint64 `json:"deletedTime"`
// Description
Description string `json:"desc"`
// Grid ID
GID uint64 `json:"gid"`
// GUID
GUID uint64 `json:"guid"`
// ID
ID uint64 `json:"id"`
// IP
IP string `json:"ip"`
// Milestones
Milestones uint64 `json:"milestones"`
// Name
Name string `json:"name"`
// Network ID
NetID uint64 `json:"netId"`
// Network type
NetType string `json:"netType"`
// Network
Network string `json:"network"`
// Resource group ID
RGID uint64 `json:"rgId"`
// Resource group name
RGName string `json:"rgName"`
// Status
Status string `json:"status"`
// Updated by
UpdatedBy string `json:"updatedBy"`
// Updated time
UpdatedTime uint64 `json:"updatedTime"`
}
// Detailed information about FLIPGroup
type ItemFLIPGroup struct {
// CKey
CKey string `json:"_ckey"`
// Meta
Meta []interface{} `json:"_meta"`
// Account ID
AccountID uint64 `json:"accountId"`
// List of client IDs
ClientIDs []uint64 `json:"clientIds"`
// Client type
ClientType string `json:"clientType"`
// Connection ID
ConnID uint64 `json:"connId"`
// Connection type
ConnType string `json:"connType"`
// Default GW
DefaultGW string `json:"defaultGW"`
// Description
Description string `json:"desc"`
// Grid ID
GID uint64 `json:"gid"`
// GUID
GUID uint64 `json:"guid"`
// ID
ID uint64 `json:"id"`
// IP
IP string `json:"ip"`
// Milestones
Milestones uint64 `json:"milestones"`
// Name
Name string `json:"name"`
// Network ID
NetID uint64 `json:"netId"`
// Network type
NetType string `json:"netType"`
// NetMask
NetMask uint64 `json:"netmask"`
// Status
Status string `json:"status"`
}
// List of FLIPGroup
type ListFLIPGroups struct {
Data []ItemFLIPGroup `json:"data"`
EntryCount uint64 `json:"entryCount"`
}

View File

@@ -1,4 +1,4 @@
package computeci
package flipgroup
import (
"encoding/json"
@@ -11,8 +11,8 @@ import (
// In order to serialize with indent make sure to follow these guidelines:
// - First argument -> prefix
// - Second argument -> indent
func (lci ListComputeCI) Serialize(params ...string) (serialization.Serialized, error) {
if lci.EntryCount == 0 {
func (lfg ListFLIPGroups) Serialize(params ...string) (serialization.Serialized, error) {
if len(lfg.Data) == 0 {
return []byte{}, nil
}
@@ -20,10 +20,10 @@ func (lci ListComputeCI) Serialize(params ...string) (serialization.Serialized,
prefix := params[0]
indent := params[1]
return json.MarshalIndent(lci, prefix, indent)
return json.MarshalIndent(lfg, prefix, indent)
}
return json.Marshal(lci)
return json.Marshal(lfg)
}
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
@@ -31,13 +31,13 @@ func (lci ListComputeCI) Serialize(params ...string) (serialization.Serialized,
// In order to serialize with indent make sure to follow these guidelines:
// - First argument -> prefix
// - Second argument -> indent
func (ic ItemComputeCI) Serialize(params ...string) (serialization.Serialized, error) {
func (ifg ItemFLIPGroup) Serialize(params ...string) (serialization.Serialized, error) {
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(ic, prefix, indent)
return json.MarshalIndent(ifg, prefix, indent)
}
return json.Marshal(ic)
return json.Marshal(ifg)
}

View File

@@ -2,7 +2,7 @@ package grid
// FilterByID returns ListGrids with specified ID.
func (lg ListGrids) FilterByID(id uint64) ListGrids {
predicate := func(rg RecordGrid) bool {
predicate := func(rg ItemGridList) bool {
return rg.ID == id
}
@@ -11,7 +11,7 @@ func (lg ListGrids) FilterByID(id uint64) ListGrids {
// FilterByName returns ListGrids with specified Name.
func (lg ListGrids) FilterByName(name string) ListGrids {
predicate := func(rg RecordGrid) bool {
predicate := func(rg ItemGridList) bool {
return rg.Name == name
}
@@ -20,7 +20,7 @@ func (lg ListGrids) FilterByName(name string) ListGrids {
// FilterByLocationCode returns ListGrids with specified LocationCode.
func (lg ListGrids) FilterByLocationCode(locationCode string) ListGrids {
predicate := func(rg RecordGrid) bool {
predicate := func(rg ItemGridList) bool {
return rg.LocationCode == locationCode
}
@@ -28,7 +28,7 @@ func (lg ListGrids) FilterByLocationCode(locationCode string) ListGrids {
}
// FilterFunc allows filtering ListGrids based on a user-specified predicate.
func (lg ListGrids) FilterFunc(predicate func(RecordGrid) bool) ListGrids {
func (lg ListGrids) FilterFunc(predicate func(ItemGridList) bool) ListGrids {
var result ListGrids
for _, item := range lg.Data {
@@ -44,9 +44,9 @@ func (lg ListGrids) FilterFunc(predicate func(RecordGrid) bool) ListGrids {
// FindOne returns first found RecordGrid.
// If none was found, returns an empty struct.
func (lg ListGrids) FindOne() RecordGrid {
func (lg ListGrids) FindOne() ItemGridList {
if len(lg.Data) == 0 {
return RecordGrid{}
return ItemGridList{}
}
return lg.Data[0]

View File

@@ -3,7 +3,7 @@ package grid
import "testing"
var grids = ListGrids{
Data: []RecordGrid{
Data: []ItemGridList{
{
Resources: Resources{
Current: RecordResource{
@@ -123,7 +123,7 @@ func TestFilterByLocationCode(t *testing.T) {
}
func TestFilterFunc(t *testing.T) {
actual := grids.FilterFunc(func(rg RecordGrid) bool {
actual := grids.FilterFunc(func(rg ItemGridList) bool {
return rg.GID == 777
}).
FindOne()

View File

@@ -18,7 +18,7 @@ type RecordResourcesConsumption struct {
Reserved RecordResource `json:"Reserved"`
// GID
GID uint64 `json:"gid"`
GID uint64 `json:"id"`
}
type ListResourceConsumption struct {
@@ -67,6 +67,27 @@ type DiskUsage struct {
// Detailed information about grid
type RecordGrid struct {
// Flag
Flag string `json:"flag"`
// Grid ID
GID uint64 `json:"gid"`
// GUID
GUID uint64 `json:"guid"`
// ID
ID uint64 `json:"id"`
// Location code
LocationCode string `json:"locationCode"`
// Name
Name string `json:"name"`
}
// Information about grid
type ItemGridList struct {
// Resource information
Resources Resources `json:"Resources"`
@@ -92,7 +113,7 @@ type RecordGrid struct {
// List Grids
type ListGrids struct {
//Data
Data []RecordGrid `json:"data"`
Data []ItemGridList `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`

View File

@@ -20,7 +20,7 @@ type DeleteRequest struct {
// Whether to completely delete the image
// Required: false
Permanently bool `url:"permanently,omitempty" json:"permanently,omitempty"`
Permanently bool `url:"permanently" json:"permanently"`
}
// Delete deletes image by ID

View File

@@ -162,7 +162,7 @@ type ListACL []ACL
// History information
type History struct {
// GUID
GUID uint64 `json:"guid"`
GUID GUID `json:"guid"`
// ID
ID uint64 `json:"id"`
@@ -171,6 +171,20 @@ type History struct {
Timestamp uint64 `json:"timestamp"`
}
type GUID string
func (r *GUID) UnmarshalJSON(b []byte) error {
if b[0] == '"' {
*r = GUID(string(b[1:len(b)-1]))
return nil
}
*r = GUID(string(b))
return nil
}
// List history
type ListHistory []History

View File

@@ -24,7 +24,7 @@ type CreateRequest struct {
// Name for first worker group created with cluster
// Required: true
WorkerGroupName string `url:"workerGroupName" json:"workerGroupName" validate:"required"`
WorkerGroupName string `url:"workerGroupName" json:"workerGroupName" validate:"required, workerGroupName"`
// Network plugin
// Must be one of these values: flunnel, weawenet, calico

View File

@@ -64,8 +64,10 @@ type CreateRequest struct {
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Slice of structs with net interface description.
// If not specified, compute will be created with default interface from RG.
// To create compute without interfaces, pass initialized empty slice .
// Required: false
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"`
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"`
// Input data for cloud-init facility
// Required: false
@@ -102,15 +104,21 @@ func (k KVMPPC) Create(ctx context.Context, req CreateRequest) (uint64, error) {
}
}
interfaces := make([]string, 0, len(req.Interfaces))
var interfaces []string
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
if req.Interfaces != nil && len(req.Interfaces) != 0 {
interfaces = make([]string, 0, len(req.Interfaces))
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
}
interfaces = append(interfaces, string(b))
}
interfaces = append(interfaces, string(b))
} else if req.Interfaces != nil && len(req.Interfaces) == 0 {
interfaces = []string{"[]"}
}
reqWrapped := wrapperCreateRequest{

View File

@@ -42,8 +42,10 @@ type CreateBlankRequest struct {
Pool string `url:"pool" json:"pool" validate:"required"`
// Slice of structs with net interface description.
// If not specified, compute will be created with default interface from RG.
// To create compute without interfaces, pass initialized empty slice .
// Required: false
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"`
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"`
// Text description of this VM
// Required: false
@@ -64,15 +66,21 @@ func (k KVMPPC) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64
}
}
interfaces := make([]string, 0, len(req.Interfaces))
var interfaces []string
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
if req.Interfaces != nil && len(req.Interfaces) != 0 {
interfaces = make([]string, 0, len(req.Interfaces))
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
}
interfaces = append(interfaces, string(b))
}
interfaces = append(interfaces, string(b))
} else if req.Interfaces != nil && len(req.Interfaces) == 0 {
interfaces = []string{"[]"}
}
reqWrapped := wrapperCreateBlankRequest{

View File

@@ -49,8 +49,10 @@ type MassCreateRequest struct {
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Slice of structs with net interface description.
// If not specified, compute will be created with default interface from RG.
// To create compute without interfaces, pass initialized empty slice.
// Required: false
Interfaces []Interface `url:"interfaces,omitempty" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"`
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"`
// Input data for cloud-init facility
// Required: false
@@ -69,6 +71,11 @@ type MassCreateRequest struct {
Reason string `url:"reason,omitempty" json:"reason,omitempty"`
}
type wrapperMassCreateRequest struct {
MassCreateRequest
Interfaces []string `url:"interfaces,omitempty"`
}
// MassCreate creates KVM PPC computes based on specified OS image
func (k KVMPPC) MassCreate(ctx context.Context, req MassCreateRequest) ([]uint64, error) {
err := validators.ValidateRequest(req)
@@ -78,9 +85,31 @@ func (k KVMPPC) MassCreate(ctx context.Context, req MassCreateRequest) ([]uint64
}
}
var interfaces []string
if req.Interfaces != nil && len(req.Interfaces) != 0 {
interfaces = make([]string, 0, len(req.Interfaces))
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return nil, err
}
interfaces = append(interfaces, string(b))
}
} else if req.Interfaces != nil && len(req.Interfaces) == 0 {
interfaces = []string{"[]"}
}
reqWrapped := wrapperMassCreateRequest{
MassCreateRequest: req,
Interfaces: interfaces,
}
url := "/cloudbroker/kvmppc/massCreate"
res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req)
res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped)
if err != nil {
return nil, err
}

View File

@@ -64,8 +64,10 @@ type CreateRequest struct {
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Slice of structs with net interface description.
// If not specified, compute will be created with default interface from RG.
// To create compute without interfaces, pass initialized empty slice .
// Required: false
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"`
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"`
// Input data for cloud-init facility
// Required: false
@@ -114,15 +116,21 @@ func (k KVMX86) Create(ctx context.Context, req CreateRequest) (uint64, error) {
}
}
interfaces := make([]string, 0, len(req.Interfaces))
var interfaces []string
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
if req.Interfaces != nil && len(req.Interfaces) != 0 {
interfaces = make([]string, 0, len(req.Interfaces))
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
}
interfaces = append(interfaces, string(b))
}
interfaces = append(interfaces, string(b))
} else if req.Interfaces != nil && len(req.Interfaces) == 0 {
interfaces = []string{"[]"}
}
reqWrapped := wrapperCreateRequest{

View File

@@ -42,8 +42,10 @@ type CreateBlankRequest struct {
Pool string `url:"pool" json:"pool" validate:"required"`
// Slice of structs with net interface description.
// If not specified, compute will be created with default interface from RG.
// To create compute without interfaces, pass initialized empty slice .
// Required: false
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"`
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"`
// Text description of this VM
// Required: false
@@ -64,15 +66,21 @@ func (k KVMX86) CreateBlank(ctx context.Context, req CreateBlankRequest) (uint64
}
}
interfaces := make([]string, 0, len(req.Interfaces))
var interfaces []string
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
if req.Interfaces != nil && len(req.Interfaces) != 0 {
interfaces = make([]string, 0, len(req.Interfaces))
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return 0, err
}
interfaces = append(interfaces, string(b))
}
interfaces = append(interfaces, string(b))
} else if req.Interfaces != nil && len(req.Interfaces) == 0 {
interfaces = []string{"[]"}
}
reqWrapped := wrapperCreateBlankRequest{

View File

@@ -49,8 +49,10 @@ type MassCreateRequest struct {
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Slice of structs with net interface description.
// If not specified, compute will be created with default interface from RG.
// To create compute without interfaces, pass initialized empty slice .
// Required: false
Interfaces []Interface `url:"interfaces,omitempty" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"`
Interfaces []Interface `url:"-" json:"interfaces,omitempty" validate:"omitempty,dive"`
// Input data for cloud-init facility
// Required: false
@@ -69,6 +71,11 @@ type MassCreateRequest struct {
Reason string `url:"reason,omitempty" json:"reason,omitempty"`
}
type wrapperMassCreateRequest struct {
MassCreateRequest
Interfaces []string `url:"interfaces,omitempty"`
}
// MassCreate creates KVM x86 computes based on specified OS image
func (k KVMX86) MassCreate(ctx context.Context, req MassCreateRequest) ([]uint64, error) {
err := validators.ValidateRequest(req)
@@ -78,9 +85,31 @@ func (k KVMX86) MassCreate(ctx context.Context, req MassCreateRequest) ([]uint64
}
}
var interfaces []string
if req.Interfaces != nil && len(req.Interfaces) != 0 {
interfaces = make([]string, 0, len(req.Interfaces))
for i := range req.Interfaces {
b, err := json.Marshal(req.Interfaces[i])
if err != nil {
return nil, err
}
interfaces = append(interfaces, string(b))
}
} else if req.Interfaces != nil && len(req.Interfaces) == 0 {
interfaces = []string{"[]"}
}
reqWrapped := wrapperMassCreateRequest{
MassCreateRequest: req,
Interfaces: interfaces,
}
url := "/cloudbroker/kvmx86/massCreate"
res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req)
res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, reqWrapped)
if err != nil {
return nil, err
}

View File

@@ -29,7 +29,7 @@ type CreateRequest struct {
// Start now Load balancer
// Required: false
Start bool `url:"start" json:"start" validate:"required"`
Start bool `url:"start" json:"start"`
// Text description of this load balancer
// Required: false

View File

@@ -9,7 +9,7 @@ import (
// FilterByID returns ListLB with specified ID.
func (ll ListLB) FilterByID(id uint64) ListLB {
predicate := func(rlb RecordLB) bool {
predicate := func(rlb ItemLBList) bool {
return rlb.ID == id
}
@@ -18,7 +18,7 @@ func (ll ListLB) FilterByID(id uint64) ListLB {
// FilterByName returns ListLB with specified Name.
func (ll ListLB) FilterByName(name string) ListLB {
predicate := func(rlb RecordLB) bool {
predicate := func(rlb ItemLBList) bool {
return rlb.Name == name
}
@@ -27,22 +27,13 @@ func (ll ListLB) FilterByName(name string) ListLB {
// FilterByExtNetID returns ListLB with specified ExtNetID.
func (ll ListLB) FilterByExtNetID(extNetID uint64) ListLB {
predicate := func(rlb RecordLB) bool {
predicate := func(rlb ItemLBList) bool {
return rlb.ExtNetID == extNetID
}
return ll.FilterFunc(predicate)
}
// FilterByImageID returns ListLB with specified ImageID.
func (ll ListLB) FilterByImageID(imageID uint64) ListLB {
predicate := func(rlb RecordLB) bool {
return rlb.ImageID == imageID
}
return ll.FilterFunc(predicate)
}
// FilterByK8SID returns ListLB used by specified K8S cluster.
func (ll ListLB) FilterByK8SID(ctx context.Context, k8sID uint64, decortClient interfaces.Caller) (*ListLB, error) {
caller := k8s.New(decortClient)
@@ -56,7 +47,7 @@ func (ll ListLB) FilterByK8SID(ctx context.Context, k8sID uint64, decortClient i
return nil, err
}
predicate := func(rlb RecordLB) bool {
predicate := func(rlb ItemLBList) bool {
return cluster.LBID == rlb.ID
}
@@ -66,7 +57,7 @@ func (ll ListLB) FilterByK8SID(ctx context.Context, k8sID uint64, decortClient i
}
// FilterFunc allows filtering ListLB based on a user-specified predicate.
func (ll ListLB) FilterFunc(predicate func(RecordLB) bool) ListLB {
func (ll ListLB) FilterFunc(predicate func(ItemLBList) bool) ListLB {
var result ListLB
for _, item := range ll.Data {
@@ -82,9 +73,9 @@ func (ll ListLB) FilterFunc(predicate func(RecordLB) bool) ListLB {
// FindOne returns first found RecordLB
// If none was found, returns an empty struct.
func (ll ListLB) FindOne() RecordLB {
func (ll ListLB) FindOne() ItemLBList {
if len(ll.Data) == 0 {
return RecordLB{}
return ItemLBList{}
}
return ll.Data[0]

View File

@@ -3,11 +3,9 @@ package lb
import "testing"
var lbs = ListLB{
Data: []RecordLB{
Data: []ItemLBList{
{
HAMode: true,
CKey: "",
Meta: []interface{}{},
ACL: []interface{}{},
Backends: []ItemBackend{},
CreatedBy: "test_user_1",
@@ -22,7 +20,6 @@ var lbs = ListLB{
GID: 212,
GUID: 1,
ID: 1,
ImageID: 2121,
Milestones: 129000,
Name: "k8s-lb-test-1",
PrimaryNode: Node{},
@@ -37,8 +34,6 @@ var lbs = ListLB{
},
{
HAMode: false,
CKey: "",
Meta: []interface{}{},
ACL: []interface{}{},
Backends: []ItemBackend{},
CreatedBy: "test_user_2",
@@ -53,7 +48,6 @@ var lbs = ListLB{
GID: 212,
GUID: 2,
ID: 2,
ImageID: 2129,
Milestones: 129013,
Name: "k8s-lb-test-2",
PrimaryNode: Node{},
@@ -68,8 +62,6 @@ var lbs = ListLB{
},
{
HAMode: true,
CKey: "",
Meta: []interface{}{},
ACL: []interface{}{},
Backends: []ItemBackend{},
CreatedBy: "te2t_user_3",
@@ -84,7 +76,6 @@ var lbs = ListLB{
GID: 212,
GUID: 3,
ID: 3,
ImageID: 2139,
Milestones: 129025,
Name: "k8s-lb-test-3",
PrimaryNode: Node{},
@@ -125,16 +116,8 @@ func TestFilterByExtNetID(t *testing.T) {
}
}
func TestFilterByImageID(t *testing.T) {
actual := lbs.FilterByImageID(2139).FindOne()
if actual.ImageID != 2139 {
t.Fatal("expected ImageID 2139, found: ", actual.ImageID)
}
}
func TestFilterFunc(t *testing.T) {
actual := lbs.FilterFunc(func(rl RecordLB) bool {
actual := lbs.FilterFunc(func(rl ItemLBList) bool {
return rl.Status == "DISABLED"
})

View File

@@ -136,7 +136,7 @@ type Node struct {
// List of load balancers
type ListLB struct {
// Data
Data []RecordLB `json:"data"`
Data []ItemLBList `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
@@ -159,6 +159,69 @@ type RecordLB struct {
// List of load balancer backends
Backends ListBackends `json:"backends"`
// Description
Description string `json:"desc"`
// DPAPI password
DPAPIPassword string `json:"dpApiPassword"`
// DPAPI user
DPAPIUser string `json:"dpApiUser"`
// External network ID
ExtNetID uint64 `json:"extnetId"`
// List of load balancer frontends
Frontends ListFrontends `json:"frontends"`
// Grid ID
GID uint64 `json:"gid"`
// GUID
GUID uint64 `json:"guid"`
// ID
ID uint64 `json:"id"`
// Image ID
ImageID uint64 `json:"imageId"`
// Milestones
Milestones uint64 `json:"milestones"`
// Name
Name string `json:"name"`
// Primary node
PrimaryNode Node `json:"primaryNode"`
// Resource group ID
RGID uint64 `json:"rgId"`
// Secondary node
SecondaryNode Node `json:"secondaryNode"`
// Status
Status string `json:"status"`
// Tech status
TechStatus string `json:"techStatus"`
// VINS ID
VINSID uint64 `json:"vinsId"`
}
// Detailed information about load balancer in List
type ItemLBList struct {
// HAMode
HAMode bool `json:"HAmode"`
// Access Control List
ACL []interface{} `json:"acl"`
// List of load balancer backends
Backends ListBackends `json:"backends"`
// Created by
CreatedBy string `json:"createdBy"`
@@ -195,9 +258,6 @@ type RecordLB struct {
// ID
ID uint64 `json:"id"`
// Image ID
ImageID uint64 `json:"imageId"`
// Milestones
Milestones uint64 `json:"milestones"`

View File

@@ -24,10 +24,31 @@ type Total struct {
UsageLimit uint64 `json:"usage_limit"`
}
type ByPool struct {
// Disk count
DiskCount uint64 `json:"disk_count"`
// Disk usage
DiskUsage uint64 `json:"disk_usage"`
// Snapshot count
SnapshotCount uint64 `json:"snapshot_count"`
// Snapshot usage
SnapshotUsage uint64 `json:"snapshot_usage"`
// Usage
Usage uint64 `json:"usage"`
// Usage limit
UsageLimit uint64 `json:"usage_limit"`
}
// Main information about consumption
type RecordConsumption struct {
// By pool
ByPool map[string]interface{} `json:"byPool"`
ByPool map[string]ByPool `json:"byPool"`
// Total resource information
Total Total `json:"total"`
@@ -70,6 +91,9 @@ type RecordPool struct {
// List URIs
URIs ListURIs `json:"uris"`
// Usage Limit
UsageLimit uint64 `json:"usage_limit"`
}
// SEP config

10
pkg/cloudbroker/stack.go Normal file
View File

@@ -0,0 +1,10 @@
package cloudbroker
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/stack"
)
// Accessing the Stack method group
func (cb *CloudBroker) Stack() *stack.Stack {
return stack.New(cb.client)
}

View File

@@ -0,0 +1,42 @@
package stack
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// Request struct for get list stack
type GetRequest struct {
// Find by ID
// Required: true
StackId uint64 `url:"stackId" json:"stackId" validate:"required"`
}
// Get stack details by ID
func (i Stack) Get(ctx context.Context, req GetRequest) (*InfoStack, error) {
err := validators.ValidateRequest(req)
if err != nil {
for _, validationError := range validators.GetErrors(err) {
return nil, validators.ValidationError(validationError)
}
}
url := "/cloudbroker/stack/get"
res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
info := InfoStack{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}
return &info, nil
}

View File

@@ -1,4 +1,4 @@
package computeci
package stack
import (
"context"
@@ -6,23 +6,23 @@ import (
"net/http"
)
// Request struct for get list of computeci
// Request struct for get list stack
type ListRequest struct {
// Find by ID
// Required: false
ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"`
// Find by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by computeci ID
// Find by type
// Required: false
ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"`
Type string `url:"type,omitempty" json:"type,omitempty"`
// Find by drivers
// Find by computeci ID
Drivers []string `url:"drivers,omitempty" json:"drivers,omitempty"`
// If true list deleted instances as well
// Find by status
// Required: false
IncludeDeleted bool `url:"includeDeleted,omitempty" json:"includeDeleted,omitempty"`
Status string `url:"status,omitempty" json:"status,omitempty"`
// Page number
// Required: false
@@ -33,16 +33,16 @@ type ListRequest struct {
Size uint64 `url:"size,omitempty" json:"size,omitempty"`
}
// List gets list of computeci instances
func (c ComputeCI) List(ctx context.Context, req ListRequest) (*ListComputeCI, error) {
url := "/cloudapi/computeci/list"
// ListStacks gets list stack
func (i Stack) List(ctx context.Context, req ListRequest) (*ListStacks, error) {
url := "/cloudbroker/stack/list"
res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req)
res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return nil, err
}
list := ListComputeCI{}
list := ListStacks{}
err = json.Unmarshal(res, &list)
if err != nil {

View File

@@ -0,0 +1,164 @@
package stack
// Main information about stack
type InfoStack struct {
// CKey
Ckey string `json:"_ckey"`
// Meta
Meta []interface{} `json:"_meta"`
//API URL
APIURL string `json:"apiUrl"`
//API key
Apikey string `json:"apikey"`
// App ID
AppID string `json:"appId"`
// CPU allocation ratio
CPUAllocationRatio float64 `json:"cpu_allocation_ratio"`
// Description
Description string `json:"desc"`
// Descr
Descr string `json:"descr"`
// Drivers
Drivers []string `json:"drivers"`
// Eco
Eco interface{} `json:"eco"`
// Error
Error uint64 `json:"error"`
// Grid ID
GID uint64 `json:"gid"`
// GID
GUID uint64 `json:"guid"`
// ID
ID uint64 `json:"id"`
// List image IDs
Images []uint64 `json:"images"`
// Login
Login string `json:"login"`
// Mem allocation ratio
MemAllocationRatio float64 `json:"mem_allocation_ratio"`
// Name
Name string `json:"name"`
// Packegas
Packages Packages `json:"packages"`
//Password
Password string `json:"passwd"`
// Reference ID
ReferenceID string `json:"referenceId"`
// Status
Status string `json:"status"`
// Type
Type string `json:"type"`
}
// List of stacks
type ListStacks struct {
//List
Data []InfoStack `json:"data"`
//Entry count
EntryCount uint64 `json:"entryCount"`
}
// Package
type Packages struct {
// LibvirtBin
LibvirtBin LibvirtBin `json:"libvirt-bin"`
// Lvm2Lockd
Lvm2Lockd Lvm2Lockd `json:"lvm2-lockd"`
// OpenvswitchCommon
OpenvswitchCommon OpenvswitchCommon `json:"openvswitch-common"`
// OpenvswitchSwitch
OpenvswitchSwitch OpenvswitchSwitch `json:"openvswitch-switch"`
// QemuSystemX86
QemuSystemX86 QemuSystemX86 `json:"qemu-system-x86"`
// Sanlock
Sanlock Sanlock `json:"sanlock"`
}
// LibvirtBin
type LibvirtBin struct {
// InstalledSize
InstalledSize string `json:"installed_size"`
// Version
Ver string `json:"ver"`
}
// Lvm2Lockd
type Lvm2Lockd struct {
// InstalledSize
InstalledSize string `json:"installed_size"`
// Version
Ver string `json:"ver"`
}
// OpenvswitchCommon
type OpenvswitchCommon struct {
// InstalledSize
InstalledSize string `json:"installed_size"`
// Version
Ver string `json:"ver"`
}
// OpenvswitchSwitch
type OpenvswitchSwitch struct {
// InstalledSize
InstalledSize string `json:"installed_size"`
// Version
Ver string `json:"ver"`
}
// QemuSystemX86
type QemuSystemX86 struct {
// InstalledSize
InstalledSize string `json:"installed_size"`
// Version
Ver string `json:"ver"`
}
// Sanlock
type Sanlock struct {
// InstalledSize
InstalledSize string `json:"installed_size"`
// Version
Ver string `json:"ver"`
}

View File

@@ -0,0 +1,16 @@
// Lists all the stack.
package stack
import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
// Structure for creating request to stack
type Stack struct {
client interfaces.Caller
}
// Builder for stack endpoint
func New(client interfaces.Caller) *Stack {
return &Stack{
client: client,
}
}