Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d6cda7119 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
cmd/
|
||||
cmd/
|
||||
.idea/
|
||||
54
CHANGELOG.md
54
CHANGELOG.md
@@ -1,39 +1,33 @@
|
||||
## Version 1.3.0
|
||||
## Version 1.3.1
|
||||
|
||||
### Features
|
||||
|
||||
- Created CloudAPI/CloudBroker filtering, sorting and serialization functions for List requests.
|
||||
- Every handler with present List request has available FilterBy functions. Filtering by ID, Name is common for each handler.
|
||||
- In case user needs to filter response by uncommon field FilterFunc with user-specified predicate is also available.
|
||||
- CloudAPI/CloudBroker computes, disks and lb also have specific Filter methods predefined, to name a few:
|
||||
- computes:
|
||||
- FilterByK8SID, used to filter computes used by specified k8s cluster;
|
||||
- FilterByK8SMasters, FilterByK8SWorkers, used to filter master/workers nodes. Best used after FilterByK8SID call;
|
||||
- FilterByLBID, used to filter computes used by specified load balancer;
|
||||
|
||||
- disks:
|
||||
- FilterByK8SID, used to filter disks attached to computes inside specified k8s cluster;
|
||||
- FilterByLBID, used to filter disks attached to computes inside specified load balancer;
|
||||
|
||||
- lb:
|
||||
- FilterByK8SID, used to filter load balancers used by specified k8s cluster;
|
||||
|
||||
- Reinvented request validation using go-validator. Made easier to manipulate and add on to.
|
||||
- Request/Config validation now uses tags instead of hard-coded validation functions;
|
||||
|
||||
- Added ability to parse client configuration from JSON or YAML formatted files.
|
||||
- Added FilterByGID for cloudapi/locations/list handler response, used to filter locations by specified GID.
|
||||
- Added /cloudbroker/pcidevices endpoints support
|
||||
- /cloudbroker/pcidevices/create
|
||||
- /cloudbroker/pcidevices/delete
|
||||
- /cloudbroker/pcidevices/disable
|
||||
- /cloudbroker/pcidevices/enable
|
||||
- /cloudbroker/pcidevices/list
|
||||
- Added /cloudbroker/vgpu endpoints support
|
||||
- /cloudbroker/vgpu/allocate
|
||||
- /cloudbroker/vgpu/create
|
||||
- /cloudbroker/vgpu/deallocate
|
||||
- /cloudbroker/vgpu/destroy
|
||||
- /cloudbroker/vgpu/list
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed SSO_URL trailing slash possibly breaking authentication process.
|
||||
- Fixed cloudbroker/vins/nat_rule_add request model types.
|
||||
- Fixed cloudbroker/grid DiskSize field type
|
||||
- Fixed TasksResult, InfoResult in cloudbroker/cloudapi/tasks/models JSON unmarshalling.
|
||||
- Fixed cloudbroker/cloudapi/account/update request model types.
|
||||
- Fixed cloudbroker/cloudapi/rg/update request model types.
|
||||
- Fixed cloudapi/account DeactivationTime field type.
|
||||
- Fixed cloudapi/k8s/workersGroupAdd return value type.
|
||||
- Fixed cloudapi/disks/listUnattached return value type.
|
||||
- Added ListDisksUnattached model as a cloudapi/disks/listUnattached handler response with filters.
|
||||
- Fixed cloudapi/extnet Excluded field type.
|
||||
- Fixed cloudapi/rg RecordResourceUsage model.
|
||||
- Fixed cloudapi/compute ItemACL model.
|
||||
|
||||
### Tests
|
||||
|
||||
- Covered CloudAPI/CloudBroker filters with unit tests.
|
||||
|
||||
### Other
|
||||
|
||||
- Updated module to new repository
|
||||
- Covered cloudapi/disks ListDisksUnattached filters with unit tests.
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package validators
|
||||
|
||||
import "github.com/go-playground/validator/v10"
|
||||
import (
|
||||
"github.com/go-playground/validator/v10"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// protoValidator is used to validate Proto fields.
|
||||
func protoValidator(fe validator.FieldLevel) bool {
|
||||
@@ -203,3 +206,12 @@ func sepFieldTypeValidator(fe validator.FieldLevel) bool {
|
||||
|
||||
return StringInSlice(fieldValue, sepFieldTypeValues)
|
||||
}
|
||||
|
||||
// hwPathValidator is used to validate HWPath field.
|
||||
func hwPathValidator(fe validator.FieldLevel) bool {
|
||||
fieldValue := fe.Field().String()
|
||||
|
||||
ok, _ := regexp.MatchString(`^\b[0-9a-f]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}.\d{1}$`, fieldValue)
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -187,6 +187,10 @@ func errorMessage(fe validator.FieldError) string {
|
||||
fe.Field(),
|
||||
joinValues(sepFieldTypeValues))
|
||||
|
||||
case "hwPath":
|
||||
return fmt.Sprintf("%s %s must be in format 0000:1f:2b.0",
|
||||
prefix,
|
||||
fe.Field())
|
||||
}
|
||||
|
||||
return fe.Error()
|
||||
|
||||
@@ -159,5 +159,10 @@ func registerAllValidators(validate *validator.Validate) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = validate.RegisterValidation("hwPath", hwPathValidator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ type RecordAccount struct {
|
||||
CreatedTime uint64 `json:"createdTime"`
|
||||
|
||||
// Deactivation time
|
||||
DeactivationTime uint64 `json:"deactivationTime"`
|
||||
DeactivationTime float64 `json:"deactivationTime"`
|
||||
|
||||
// Deleted by
|
||||
DeletedBy string `json:"deletedBy"`
|
||||
|
||||
@@ -20,23 +20,23 @@ type UpdateRequest struct {
|
||||
|
||||
// Max size of memory in MB
|
||||
// Required: false
|
||||
MaxMemoryCapacity uint64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
|
||||
MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
|
||||
|
||||
// Max size of aggregated vdisks in GB
|
||||
// Required: false
|
||||
MaxVDiskCapacity uint64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
|
||||
MaxVDiskCapacity int64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
|
||||
|
||||
// Max number of CPU cores
|
||||
// Required: false
|
||||
MaxCPUCapacity uint64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
|
||||
MaxCPUCapacity int64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
|
||||
|
||||
// Max sent/received network transfer peering
|
||||
// Required: false
|
||||
MaxNetworkPeerTransfer uint64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
|
||||
MaxNetworkPeerTransfer int64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
|
||||
|
||||
// Max number of assigned public IPs
|
||||
// Required: false
|
||||
MaxNumPublicIP uint64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
|
||||
MaxNumPublicIP int64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
|
||||
|
||||
// If true send emails when a user is granted access to resources
|
||||
// Required: false
|
||||
@@ -44,7 +44,7 @@ type UpdateRequest struct {
|
||||
|
||||
// Limit (positive) or disable (0) GPU resources
|
||||
// Required: false
|
||||
GPUUnits uint64 `url:"gpu_units,omitempty" json:"gpu_units,omitempty"`
|
||||
GPUUnits int64 `url:"gpu_units,omitempty" json:"gpu_units,omitempty"`
|
||||
}
|
||||
|
||||
// Update updates an account name and resource types and limits
|
||||
|
||||
@@ -4,7 +4,7 @@ import "testing"
|
||||
|
||||
var computes = ListComputes{
|
||||
ItemCompute{
|
||||
ACL: []interface{}{},
|
||||
ACL: ListACL{},
|
||||
AccountID: 132847,
|
||||
AccountName: "std_2",
|
||||
AffinityLabel: "",
|
||||
@@ -85,7 +85,7 @@ var computes = ListComputes{
|
||||
VirtualImageID: 0,
|
||||
},
|
||||
ItemCompute{
|
||||
ACL: []interface{}{},
|
||||
ACL: ListACL{},
|
||||
AccountID: 132848,
|
||||
AccountName: "std_broker",
|
||||
AffinityLabel: "",
|
||||
@@ -150,92 +150,92 @@ var computes = ListComputes{
|
||||
}
|
||||
|
||||
func TestFilterByID(t *testing.T) {
|
||||
actual := computes.FilterByID(48500).FindOne()
|
||||
actual := computes.FilterByID(48500).FindOne()
|
||||
|
||||
if actual.ID != 48500 {
|
||||
t.Fatal("expected ID 48500, found: ", actual.ID)
|
||||
}
|
||||
if actual.ID != 48500 {
|
||||
t.Fatal("expected ID 48500, found: ", actual.ID)
|
||||
}
|
||||
|
||||
actualEmpty := computes.FilterByID(0)
|
||||
actualEmpty := computes.FilterByID(0)
|
||||
|
||||
if len(actualEmpty) != 0 {
|
||||
t.Fatal("expected empty, actual: ", len(actualEmpty))
|
||||
}
|
||||
if len(actualEmpty) != 0 {
|
||||
t.Fatal("expected empty, actual: ", len(actualEmpty))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterByName(t *testing.T) {
|
||||
actual := computes.FilterByName("test").FindOne()
|
||||
actual := computes.FilterByName("test").FindOne()
|
||||
|
||||
if actual.Name != "test" {
|
||||
t.Fatal("expected compute with name 'test', found: ", actual.Name)
|
||||
}
|
||||
if actual.Name != "test" {
|
||||
t.Fatal("expected compute with name 'test', found: ", actual.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterByStatus(t *testing.T) {
|
||||
actual := computes.FilterByStatus("ENABLED")
|
||||
actual := computes.FilterByStatus("ENABLED")
|
||||
|
||||
for _, item := range actual {
|
||||
if item.Status != "ENABLED" {
|
||||
t.Fatal("expected ENABLED status, found: ", item.Status)
|
||||
}
|
||||
}
|
||||
for _, item := range actual {
|
||||
if item.Status != "ENABLED" {
|
||||
t.Fatal("expected ENABLED status, found: ", item.Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterByTechStatus(t *testing.T) {
|
||||
actual := computes.FilterByTechStatus("STARTED").FindOne()
|
||||
actual := computes.FilterByTechStatus("STARTED").FindOne()
|
||||
|
||||
if actual.ID != 48556 {
|
||||
t.Fatal("expected 48556 with STARTED techStatus, found: ", actual.ID)
|
||||
}
|
||||
if actual.ID != 48556 {
|
||||
t.Fatal("expected 48556 with STARTED techStatus, found: ", actual.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterByDiskID(t *testing.T) {
|
||||
actual := computes.FilterByDiskID(65248).FindOne()
|
||||
actual := computes.FilterByDiskID(65248).FindOne()
|
||||
|
||||
if actual.ID != 48556 {
|
||||
t.Fatal("expected 48556 with DiskID 65248, found: ", actual.ID)
|
||||
}
|
||||
if actual.ID != 48556 {
|
||||
t.Fatal("expected 48556 with DiskID 65248, found: ", actual.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterFunc(t *testing.T) {
|
||||
actual := computes.FilterFunc(func(ic ItemCompute) bool {
|
||||
return ic.Registered == true
|
||||
})
|
||||
actual := computes.FilterFunc(func(ic ItemCompute) bool {
|
||||
return ic.Registered == true
|
||||
})
|
||||
|
||||
if len(actual) != 2 {
|
||||
t.Fatal("expected 2 elements found, actual: ", len(actual))
|
||||
}
|
||||
if len(actual) != 2 {
|
||||
t.Fatal("expected 2 elements found, actual: ", len(actual))
|
||||
}
|
||||
|
||||
for _, item := range actual {
|
||||
if item.Registered != true {
|
||||
t.Fatal("expected Registered to be true, actual: ", item.Registered)
|
||||
}
|
||||
}
|
||||
for _, item := range actual {
|
||||
if item.Registered != true {
|
||||
t.Fatal("expected Registered to be true, actual: ", item.Registered)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortingByCreatedTime(t *testing.T) {
|
||||
actual := computes.SortByCreatedTime(false)
|
||||
actual := computes.SortByCreatedTime(false)
|
||||
|
||||
if actual[0].Name != "test" {
|
||||
t.Fatal("expected 'test', found: ", actual[0].Name)
|
||||
}
|
||||
if actual[0].Name != "test" {
|
||||
t.Fatal("expected 'test', found: ", actual[0].Name)
|
||||
}
|
||||
|
||||
actual = computes.SortByCreatedTime(true)
|
||||
if actual[0].Name != "compute_2" {
|
||||
t.Fatal("expected 'compute_2', found: ", actual[0].Name)
|
||||
}
|
||||
actual = computes.SortByCreatedTime(true)
|
||||
if actual[0].Name != "compute_2" {
|
||||
t.Fatal("expected 'compute_2', found: ", actual[0].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortingByCPU(t *testing.T) {
|
||||
actual := computes.SortByCPU(false)
|
||||
actual := computes.SortByCPU(false)
|
||||
|
||||
if actual[0].CPU != 4{
|
||||
t.Fatal("expected 4 CPU cores, found: ", actual[0].CPU)
|
||||
}
|
||||
if actual[0].CPU != 4 {
|
||||
t.Fatal("expected 4 CPU cores, found: ", actual[0].CPU)
|
||||
}
|
||||
|
||||
actual = computes.SortByCPU(true)
|
||||
actual = computes.SortByCPU(true)
|
||||
|
||||
if actual[0].CPU != 6 {
|
||||
t.Fatal("expected 6 CPU cores, found: ", actual[0].CPU)
|
||||
}
|
||||
if actual[0].CPU != 6 {
|
||||
t.Fatal("expected 6 CPU cores, found: ", actual[0].CPU)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package compute
|
||||
|
||||
import "strconv"
|
||||
|
||||
// Access Control List
|
||||
type RecordACL struct {
|
||||
// Account ACL list
|
||||
@@ -12,10 +14,27 @@ type RecordACL struct {
|
||||
RGACL ListACL `json:"rgAcl"`
|
||||
}
|
||||
|
||||
type Explicit bool
|
||||
|
||||
func (e *Explicit) UnmarshalJSON(b []byte) error {
|
||||
if b[0] == '"' {
|
||||
b = b[1 : len(b)-1]
|
||||
}
|
||||
|
||||
res, err := strconv.ParseBool(string(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*e = Explicit(res)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ACL information
|
||||
type ItemACL struct {
|
||||
// Explicit
|
||||
Explicit bool `json:"explicit"`
|
||||
Explicit Explicit `json:"explicit"`
|
||||
|
||||
// GUID
|
||||
GUID string `json:"guid"`
|
||||
@@ -709,8 +728,7 @@ type IOTune struct {
|
||||
// Main information about compute
|
||||
type ItemCompute struct {
|
||||
// Access Control List
|
||||
ACL []interface{} `json:"acl"`
|
||||
|
||||
ACL ListACL `json:"acl"`
|
||||
// Account ID
|
||||
AccountID uint64 `json:"accountId"`
|
||||
|
||||
|
||||
@@ -130,3 +130,62 @@ func (ld ListDisks) FindOne() ItemDisk {
|
||||
|
||||
return ld[0]
|
||||
}
|
||||
|
||||
// FilterByID returns ListDisksUnattached with specified ID.
|
||||
func (lu ListDisksUnattached) FilterByID(id uint64) ListDisksUnattached {
|
||||
predicate := func(idisk ItemDiskUnattached) bool {
|
||||
return idisk.ID == id
|
||||
}
|
||||
|
||||
return lu.FilterFunc(predicate)
|
||||
}
|
||||
|
||||
// FilterByName returns ListDisksUnattached with specified Name.
|
||||
func (lu ListDisksUnattached) FilterByName(name string) ListDisksUnattached {
|
||||
predicate := func(idisk ItemDiskUnattached) bool {
|
||||
return idisk.Name == name
|
||||
}
|
||||
|
||||
return lu.FilterFunc(predicate)
|
||||
}
|
||||
|
||||
// FilterByStatus returns ListDisksUnattached with specified Status.
|
||||
func (lu ListDisksUnattached) FilterByStatus(status string) ListDisksUnattached {
|
||||
predicate := func(idisk ItemDiskUnattached) bool {
|
||||
return idisk.Status == status
|
||||
}
|
||||
|
||||
return lu.FilterFunc(predicate)
|
||||
}
|
||||
|
||||
// FilterByTechStatus returns ListDisksUnattached with specified TechStatus.
|
||||
func (lu ListDisksUnattached) FilterByTechStatus(techStatus string) ListDisksUnattached {
|
||||
predicate := func(idisk ItemDiskUnattached) bool {
|
||||
return idisk.TechStatus == techStatus
|
||||
}
|
||||
|
||||
return lu.FilterFunc(predicate)
|
||||
}
|
||||
|
||||
// FilterFunc allows filtering ListDisksUnattached based on a user-specified predicate.
|
||||
func (lu ListDisksUnattached) FilterFunc(predicate func(ItemDiskUnattached) bool) ListDisksUnattached {
|
||||
var result ListDisksUnattached
|
||||
|
||||
for _, item := range lu {
|
||||
if predicate(item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FindOne returns first found ItemDiskUnattached
|
||||
// If none was found, returns an empty struct.
|
||||
func (lu ListDisksUnattached) FindOne() ItemDiskUnattached {
|
||||
if len(lu) == 0 {
|
||||
return ItemDiskUnattached{}
|
||||
}
|
||||
|
||||
return lu[0]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package disks
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var disks = ListDisks{
|
||||
ItemDisk{
|
||||
@@ -175,3 +177,198 @@ func TestSortByCreatedTime(t *testing.T) {
|
||||
t.Fatal("expected ID 65193, found: ", actual[0].ID)
|
||||
}
|
||||
}
|
||||
|
||||
var unattachedDisks = ListDisksUnattached{
|
||||
{
|
||||
CKey: "",
|
||||
Meta: []interface{}{
|
||||
"cloudbroker",
|
||||
"disk",
|
||||
1,
|
||||
},
|
||||
AccountID: 149,
|
||||
AccountName: "test_account1",
|
||||
ACL: map[string]interface{}{},
|
||||
BootPartition: 0,
|
||||
CreatedTime: 1681477547,
|
||||
DeletedTime: 0,
|
||||
Description: "",
|
||||
DestructionTime: 0,
|
||||
DiskPath: "",
|
||||
GID: 2002,
|
||||
GUID: 22636,
|
||||
ID: 22636,
|
||||
ImageID: 0,
|
||||
Images: []uint64{},
|
||||
IOTune: IOTune{
|
||||
TotalIOPSSec: 2000,
|
||||
},
|
||||
IQN: "",
|
||||
Login: "",
|
||||
Milestones: 43834,
|
||||
Name: "test_disk",
|
||||
Order: 0,
|
||||
Params: "",
|
||||
ParentID: 0,
|
||||
Password: "",
|
||||
PCISlot: -1,
|
||||
Pool: "data05",
|
||||
PresentTo: []uint64{},
|
||||
PurgeAttempts: 0,
|
||||
PurgeTime: 0,
|
||||
RealityDeviceNumber: 0,
|
||||
ReferenceID: "",
|
||||
ResID: "79bd3bd8-3424-48d3-963f-1870d506f169",
|
||||
ResName: "volumes/volume_22636",
|
||||
Role: "",
|
||||
SEPID: 1,
|
||||
Shareable: false,
|
||||
SizeMax: 0,
|
||||
SizeUsed: 0,
|
||||
Snapshots: nil,
|
||||
Status: "CREATED",
|
||||
TechStatus: "ALLOCATED",
|
||||
Type: "D",
|
||||
VMID: 0,
|
||||
},
|
||||
{
|
||||
CKey: "",
|
||||
Meta: []interface{}{
|
||||
"cloudbroker",
|
||||
"disk",
|
||||
1,
|
||||
},
|
||||
AccountID: 150,
|
||||
AccountName: "test_account",
|
||||
ACL: map[string]interface{}{},
|
||||
BootPartition: 0,
|
||||
CreatedTime: 1681477558,
|
||||
DeletedTime: 0,
|
||||
Description: "",
|
||||
DestructionTime: 0,
|
||||
DiskPath: "",
|
||||
GID: 2002,
|
||||
GUID: 22637,
|
||||
ID: 22637,
|
||||
ImageID: 0,
|
||||
Images: []uint64{},
|
||||
IOTune: IOTune{
|
||||
TotalIOPSSec: 2000,
|
||||
},
|
||||
IQN: "",
|
||||
Login: "",
|
||||
Milestones: 43834,
|
||||
Name: "test_disk",
|
||||
Order: 0,
|
||||
Params: "",
|
||||
ParentID: 0,
|
||||
Password: "",
|
||||
PCISlot: -1,
|
||||
Pool: "data05",
|
||||
PresentTo: []uint64{
|
||||
27,
|
||||
27,
|
||||
},
|
||||
PurgeAttempts: 0,
|
||||
PurgeTime: 0,
|
||||
RealityDeviceNumber: 0,
|
||||
ReferenceID: "",
|
||||
ResID: "79bd3bd8-3424-48d3-963f-1870d506f169",
|
||||
ResName: "volumes/volume_22637",
|
||||
Role: "",
|
||||
SEPID: 1,
|
||||
Shareable: false,
|
||||
SizeMax: 0,
|
||||
SizeUsed: 0,
|
||||
Snapshots: nil,
|
||||
Status: "CREATED",
|
||||
TechStatus: "ALLOCATED",
|
||||
Type: "B",
|
||||
VMID: 0,
|
||||
},
|
||||
}
|
||||
|
||||
func TestListDisksUnattached_FilterByID(t *testing.T) {
|
||||
actual := unattachedDisks.FilterByID(22636)
|
||||
|
||||
if len(actual) == 0 {
|
||||
t.Fatal("No elements were found")
|
||||
}
|
||||
|
||||
actualItem := actual.FindOne()
|
||||
|
||||
if actualItem.ID != 22636 {
|
||||
t.Fatal("expected ID 22636, found: ", actualItem.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListDisksUnattached_FilterByName(t *testing.T) {
|
||||
actual := unattachedDisks.FilterByName("test_disk")
|
||||
|
||||
if len(actual) != 2 {
|
||||
t.Fatal("expected 2 elements, found: ", len(actual))
|
||||
}
|
||||
|
||||
for _, item := range actual {
|
||||
if item.Name != "test_disk" {
|
||||
t.Fatal("expected 'test_disk' name, found: ", item.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestListDisksUnattached_FilterByStatus(t *testing.T) {
|
||||
actual := unattachedDisks.FilterByStatus("CREATED")
|
||||
|
||||
if len(actual) == 0 {
|
||||
t.Fatal("No elements were found")
|
||||
}
|
||||
|
||||
for _, item := range actual {
|
||||
if item.Status != "CREATED" {
|
||||
t.Fatal("expected 'CREATED' status, found: ", item.Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestListDisksUnattached_FilterByTechStatus(t *testing.T) {
|
||||
actual := unattachedDisks.FilterByTechStatus("ALLOCATED")
|
||||
|
||||
if len(actual) == 0 {
|
||||
t.Fatal("No elements were found")
|
||||
}
|
||||
|
||||
for _, item := range actual {
|
||||
if item.TechStatus != "ALLOCATED" {
|
||||
t.Fatal("expected 'ALLOCATED' techStatus, found: ", item.TechStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestListDisksUnattached_FilterFunc(t *testing.T) {
|
||||
actual := unattachedDisks.FilterFunc(func(id ItemDiskUnattached) bool {
|
||||
return len(id.PresentTo) == 2
|
||||
})
|
||||
|
||||
if len(actual) == 0 {
|
||||
t.Fatal("No elements were found")
|
||||
}
|
||||
|
||||
if len(actual[0].PresentTo) != 2 {
|
||||
t.Fatal("expected 2 elements in PresentTo, found: ", len(actual[0].PresentTo))
|
||||
}
|
||||
}
|
||||
|
||||
func TestListDisksUnattached_SortByCreatedTime(t *testing.T) {
|
||||
actual := unattachedDisks.SortByCreatedTime(false)
|
||||
|
||||
if actual[0].ID != 22636 {
|
||||
t.Fatal("expected ID 22636, found: ", actual[0].ID)
|
||||
}
|
||||
|
||||
actual = unattachedDisks.SortByCreatedTime(true)
|
||||
|
||||
if actual[0].ID != 22637 {
|
||||
t.Fatal("expected ID 22637, found: ", actual[0].ID)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ type ListUnattachedRequest struct {
|
||||
}
|
||||
|
||||
// ListUnattached gets list of unattached disks
|
||||
func (d Disks) ListUnattached(ctx context.Context, req ListUnattachedRequest) (ListDisks, error) {
|
||||
func (d Disks) ListUnattached(ctx context.Context, req ListUnattachedRequest) (ListDisksUnattached, error) {
|
||||
url := "/cloudapi/disks/listUnattached"
|
||||
|
||||
res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req)
|
||||
@@ -22,7 +22,7 @@ func (d Disks) ListUnattached(ctx context.Context, req ListUnattachedRequest) (L
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := ListDisks{}
|
||||
list := ListDisksUnattached{}
|
||||
|
||||
err = json.Unmarshal(res, &list)
|
||||
if err != nil {
|
||||
|
||||
@@ -114,9 +114,146 @@ type ItemDisk struct {
|
||||
VMID uint64 `json:"vmid"`
|
||||
}
|
||||
|
||||
type ItemDiskUnattached struct {
|
||||
// CKey
|
||||
CKey string `json:"_ckey"`
|
||||
|
||||
// Meta
|
||||
Meta []interface{} `json:"_meta"`
|
||||
|
||||
// Account ID
|
||||
AccountID uint64 `json:"accountId"`
|
||||
|
||||
// Account name
|
||||
AccountName string `json:"accountName"`
|
||||
|
||||
// Access Control List
|
||||
ACL map[string]interface{} `json:"acl"`
|
||||
|
||||
// Boot Partition
|
||||
BootPartition uint64 `json:"bootPartition"`
|
||||
|
||||
// Created time
|
||||
CreatedTime uint64 `json:"createdTime"`
|
||||
|
||||
// Deleted time
|
||||
DeletedTime uint64 `json:"deletedTime"`
|
||||
|
||||
// Description
|
||||
Description string `json:"desc"`
|
||||
|
||||
// Destruction time
|
||||
DestructionTime uint64 `json:"destructionTime"`
|
||||
|
||||
// Disk path
|
||||
DiskPath string `json:"diskPath"`
|
||||
|
||||
// Grid ID
|
||||
GID uint64 `json:"gid"`
|
||||
|
||||
// GUID
|
||||
GUID uint64 `json:"guid"`
|
||||
|
||||
// ID
|
||||
ID uint64 `json:"id"`
|
||||
|
||||
// Image ID
|
||||
ImageID uint64 `json:"imageId"`
|
||||
|
||||
// Images
|
||||
Images []uint64 `json:"images"`
|
||||
|
||||
// IOTune
|
||||
IOTune IOTune `json:"iotune"`
|
||||
|
||||
// IQN
|
||||
IQN string `json:"iqn"`
|
||||
|
||||
// Login
|
||||
Login string `json:"login"`
|
||||
|
||||
// Milestones
|
||||
Milestones uint64 `json:"milestones"`
|
||||
|
||||
// Name
|
||||
Name string `json:"name"`
|
||||
|
||||
// Order
|
||||
Order uint64 `json:"order"`
|
||||
|
||||
// Params
|
||||
Params string `json:"params"`
|
||||
|
||||
// Parent ID
|
||||
ParentID uint64 `json:"parentId"`
|
||||
|
||||
// Password
|
||||
Password string `json:"passwd"`
|
||||
|
||||
//PCISlot
|
||||
PCISlot int64 `json:"pciSlot"`
|
||||
|
||||
// Pool
|
||||
Pool string `json:"pool"`
|
||||
|
||||
// Present to
|
||||
PresentTo []uint64 `json:"presentTo"`
|
||||
|
||||
// Purge attempts
|
||||
PurgeAttempts uint64 `json:"purgeAttempts"`
|
||||
|
||||
// Purge time
|
||||
PurgeTime uint64 `json:"purgeTime"`
|
||||
|
||||
// Reality device number
|
||||
RealityDeviceNumber uint64 `json:"realityDeviceNumber"`
|
||||
|
||||
// Reference ID
|
||||
ReferenceID string `json:"referenceId"`
|
||||
|
||||
// Resource ID
|
||||
ResID string `json:"resId"`
|
||||
|
||||
// Resource name
|
||||
ResName string `json:"resName"`
|
||||
|
||||
// Role
|
||||
Role string `json:"role"`
|
||||
|
||||
// ID SEP
|
||||
SEPID uint64 `json:"sepId"`
|
||||
|
||||
// Shareable
|
||||
Shareable bool `json:"shareable"`
|
||||
|
||||
// Size max
|
||||
SizeMax uint64 `json:"sizeMax"`
|
||||
|
||||
// Size used
|
||||
SizeUsed float64 `json:"sizeUsed"`
|
||||
|
||||
// List of snapshots
|
||||
Snapshots ListSnapshots `json:"snapshots"`
|
||||
|
||||
// Status
|
||||
Status string `json:"status"`
|
||||
|
||||
// Tech status
|
||||
TechStatus string `json:"techStatus"`
|
||||
|
||||
// Type
|
||||
Type string `json:"type"`
|
||||
|
||||
// Virtual machine ID
|
||||
VMID uint64 `json:"vmid"`
|
||||
}
|
||||
|
||||
// List of disks
|
||||
type ListDisks []ItemDisk
|
||||
|
||||
// List of unattached disks
|
||||
type ListDisksUnattached []ItemDiskUnattached
|
||||
|
||||
// Main information about snapshot
|
||||
type ItemSnapshot struct {
|
||||
// GUID
|
||||
|
||||
@@ -41,3 +41,39 @@ func (idisk ItemDisk) Serialize(params ...string) (serialization.Serialized, err
|
||||
|
||||
return json.Marshal(idisk)
|
||||
}
|
||||
|
||||
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
|
||||
//
|
||||
// In order to serialize with indent make sure to follow these guidelines:
|
||||
// - First argument -> prefix
|
||||
// - Second argument -> indent
|
||||
func (lu ListDisksUnattached) Serialize(params ...string) (serialization.Serialized, error) {
|
||||
if len(lu) == 0 {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
if len(params) > 1 {
|
||||
prefix := params[0]
|
||||
indent := params[1]
|
||||
|
||||
return json.MarshalIndent(lu, prefix, indent)
|
||||
}
|
||||
|
||||
return json.Marshal(lu)
|
||||
}
|
||||
|
||||
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
|
||||
//
|
||||
// In order to serialize with indent make sure to follow these guidelines:
|
||||
// - First argument -> prefix
|
||||
// - Second argument -> indent
|
||||
func (idisk ItemDiskUnattached) Serialize(params ...string) (serialization.Serialized, error) {
|
||||
if len(params) > 1 {
|
||||
prefix := params[0]
|
||||
indent := params[1]
|
||||
|
||||
return json.MarshalIndent(idisk, prefix, indent)
|
||||
}
|
||||
|
||||
return json.Marshal(idisk)
|
||||
}
|
||||
|
||||
@@ -58,3 +58,60 @@ func (ld ListDisks) SortByDeletedTime(inverse bool) ListDisks {
|
||||
|
||||
return ld
|
||||
}
|
||||
|
||||
// SortByCreatedTime sorts ListDisksUnattached by the CreatedTime field in ascending order.
|
||||
//
|
||||
// If inverse param is set to true, the order is reversed.
|
||||
func (lu ListDisksUnattached) SortByCreatedTime(inverse bool) ListDisksUnattached {
|
||||
if len(lu) < 2 {
|
||||
return lu
|
||||
}
|
||||
|
||||
sort.Slice(lu, func(i, j int) bool {
|
||||
if inverse {
|
||||
return lu[i].CreatedTime > lu[j].CreatedTime
|
||||
}
|
||||
|
||||
return lu[i].CreatedTime < lu[j].CreatedTime
|
||||
})
|
||||
|
||||
return lu
|
||||
}
|
||||
|
||||
// SortByDestructionTime sorts ListDisksUnattached by the DestructionTime field in ascending order.
|
||||
//
|
||||
// If inverse param is set to true, the order is reversed.
|
||||
func (lu ListDisksUnattached) SortByDestructionTime(inverse bool) ListDisksUnattached {
|
||||
if len(lu) < 2 {
|
||||
return lu
|
||||
}
|
||||
|
||||
sort.Slice(lu, func(i, j int) bool {
|
||||
if inverse {
|
||||
return lu[i].DestructionTime > lu[j].DestructionTime
|
||||
}
|
||||
|
||||
return lu[i].DestructionTime < lu[j].DestructionTime
|
||||
})
|
||||
|
||||
return lu
|
||||
}
|
||||
|
||||
// SortByDeletedTime sorts ListDisksUnattached by the DeletedTime field in ascending order.
|
||||
//
|
||||
// If inverse param is set to true, the order is reversed.
|
||||
func (lu ListDisksUnattached) SortByDeletedTime(inverse bool) ListDisksUnattached {
|
||||
if len(lu) < 2 {
|
||||
return lu
|
||||
}
|
||||
|
||||
sort.Slice(lu, func(i, j int) bool {
|
||||
if inverse {
|
||||
return lu[i].DeletedTime > lu[j].DeletedTime
|
||||
}
|
||||
|
||||
return lu[i].DeletedTime < lu[j].DeletedTime
|
||||
})
|
||||
|
||||
return lu
|
||||
}
|
||||
|
||||
@@ -107,6 +107,23 @@ type VNFs struct {
|
||||
DHCP uint64 `json:"dhcp"`
|
||||
}
|
||||
|
||||
type Excluded struct {
|
||||
// ClientType
|
||||
ClientType string `json:"clientType"`
|
||||
|
||||
// IP
|
||||
IP string `json:"ip"`
|
||||
|
||||
// MAC
|
||||
MAC string `json:"mac"`
|
||||
|
||||
// Type
|
||||
Type string `json:"type"`
|
||||
|
||||
// VMID
|
||||
VMID uint64 `json:"vmId"`
|
||||
}
|
||||
|
||||
// Detailed information about external network
|
||||
type RecordExtNet struct {
|
||||
// CKey
|
||||
@@ -134,7 +151,7 @@ type RecordExtNet struct {
|
||||
DNS []string `json:"dns"`
|
||||
|
||||
// Excluded
|
||||
Excluded []string `json:"excluded"`
|
||||
Excluded []Excluded `json:"excluded"`
|
||||
|
||||
// Free IPs
|
||||
FreeIPs uint64 `json:"free_ips"`
|
||||
|
||||
@@ -59,11 +59,11 @@ type WorkersGroupAddRequest struct {
|
||||
}
|
||||
|
||||
// WorkersGroupAdd adds workers group to Kubernetes cluster
|
||||
func (k8s K8S) WorkersGroupAdd(ctx context.Context, req WorkersGroupAddRequest) (bool, error) {
|
||||
func (k8s K8S) WorkersGroupAdd(ctx context.Context, req WorkersGroupAddRequest) (uint64, error) {
|
||||
err := validators.ValidateRequest(req)
|
||||
if err != nil {
|
||||
for _, validationError := range validators.GetErrors(err) {
|
||||
return false, validators.ValidationError(validationError)
|
||||
return 0, validators.ValidationError(validationError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,12 +71,12 @@ func (k8s K8S) WorkersGroupAdd(ctx context.Context, req WorkersGroupAddRequest)
|
||||
|
||||
res, err := k8s.client.DecortApiCall(ctx, http.MethodPost, url, req)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
result, err := strconv.ParseBool(string(res))
|
||||
result, err := strconv.ParseUint(string(res), 10, 64)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
@@ -18,6 +18,15 @@ func (ll ListLocations) FilterByName(name string) ListLocations {
|
||||
return ll.FilterFunc(predicate)
|
||||
}
|
||||
|
||||
// FilterByGID returns ListLocations with specified GID.
|
||||
func (ll ListLocations) FilterByGID(gid uint64) ListLocations {
|
||||
predicate := func(il ItemLocation) bool {
|
||||
return il.GID == gid
|
||||
}
|
||||
|
||||
return ll.FilterFunc(predicate)
|
||||
}
|
||||
|
||||
// FilterFunc allows filtering ListLocations based on a user-specified predicate.
|
||||
func (ll ListLocations) FilterFunc(predicate func(ItemLocation) bool) ListLocations {
|
||||
var result ListLocations
|
||||
|
||||
@@ -735,7 +735,10 @@ type RecordResourceUsage struct {
|
||||
CPU uint64 `json:"cpu"`
|
||||
|
||||
// Disk size
|
||||
DiskSize uint64 `json:"disksize"`
|
||||
DiskSize float64 `json:"disksize"`
|
||||
|
||||
// Max disk size
|
||||
DiskSizeMax uint64 `json:"disksizemax"`
|
||||
|
||||
// Number of external IPs
|
||||
ExtIPs uint64 `json:"extips"`
|
||||
@@ -748,4 +751,7 @@ type RecordResourceUsage struct {
|
||||
|
||||
// Number of RAM
|
||||
RAM uint64 `json:"ram"`
|
||||
|
||||
// SEPs
|
||||
SEPs map[string]map[string]DiskUsage `json:"seps"`
|
||||
}
|
||||
|
||||
@@ -24,23 +24,23 @@ type UpdateRequest struct {
|
||||
|
||||
// Max size of memory in MB
|
||||
// Required: false
|
||||
MaxMemoryCapacity uint64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
|
||||
MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
|
||||
|
||||
// Max size of aggregated virtual disks in GB
|
||||
// Required: false
|
||||
MaxVDiskCapacity uint64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
|
||||
MaxVDiskCapacity int64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
|
||||
|
||||
// Max number of CPU cores
|
||||
// Required: false
|
||||
MaxCPUCapacity uint64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
|
||||
MaxCPUCapacity int64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
|
||||
|
||||
// Max sent/received network transfer peering
|
||||
// Required: false
|
||||
MaxNetworkPeerTransfer uint64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
|
||||
MaxNetworkPeerTransfer int64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
|
||||
|
||||
// Max number of assigned public IPs
|
||||
// Required: false
|
||||
MaxNumPublicIP uint64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
|
||||
MaxNumPublicIP int64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
|
||||
|
||||
// Register computes in registration system
|
||||
// Required: false
|
||||
|
||||
@@ -15,8 +15,8 @@ type UpdateRequest struct {
|
||||
AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
|
||||
|
||||
// Display name
|
||||
// Required: true
|
||||
Name string `url:"name" json:"name" validate:"required"`
|
||||
// Required: false
|
||||
Name string `url:"name" json:"name"`
|
||||
|
||||
// Name of the account
|
||||
// Required: true
|
||||
@@ -24,27 +24,27 @@ type UpdateRequest struct {
|
||||
|
||||
// Email
|
||||
// Required: false
|
||||
EmailAddress string `url:"emailaddress,omitempty" json:"emailaddress,omitempty" validate:"omitempty,email"`
|
||||
EmailAddress string `url:"emailaddress,omitempty" json:"emailaddress,omitempty" validate:"omitempty,email"`
|
||||
|
||||
// Max size of memory in MB
|
||||
// Required: false
|
||||
MaxMemoryCapacity uint64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
|
||||
MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
|
||||
|
||||
// Max size of aggregated vdisks in GB
|
||||
// Required: false
|
||||
MaxVDiskCapacity uint64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
|
||||
MaxVDiskCapacity int64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
|
||||
|
||||
// Max number of CPU cores
|
||||
// Required: false
|
||||
MaxCPUCapacity uint64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
|
||||
MaxCPUCapacity int64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
|
||||
|
||||
// Max sent/received network transfer peering
|
||||
// Required: false
|
||||
MaxNetworkPeerTransfer uint64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
|
||||
MaxNetworkPeerTransfer int64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
|
||||
|
||||
// Max number of assigned public IPs
|
||||
// Required: false
|
||||
MaxNumPublicIP uint64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
|
||||
MaxNumPublicIP int64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
|
||||
|
||||
// If true send emails when a user is granted access to resources
|
||||
// Required: false
|
||||
@@ -52,7 +52,7 @@ type UpdateRequest struct {
|
||||
|
||||
// Limit (positive) or disable (0) GPU resources
|
||||
// Required: false
|
||||
GPUUnits uint64 `url:"gpu_units,omitempty" json:"gpu_units,omitempty"`
|
||||
GPUUnits int64 `url:"gpu_units,omitempty" json:"gpu_units,omitempty"`
|
||||
|
||||
// List of strings with pools
|
||||
// i.e.: ["sep1_poolName1", "sep2_poolName2", etc]
|
||||
|
||||
8
pkg/cloudbroker/pcidevice.go
Normal file
8
pkg/cloudbroker/pcidevice.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package cloudbroker
|
||||
|
||||
import "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/pcidevice"
|
||||
|
||||
// Accessing the PCI Device method group
|
||||
func (cb *CloudBroker) PCIDevice() *pcidevice.PCIDevice {
|
||||
return pcidevice.New(cb.client)
|
||||
}
|
||||
56
pkg/cloudbroker/pcidevice/create.go
Normal file
56
pkg/cloudbroker/pcidevice/create.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package pcidevice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Request struct for creating PCI device
|
||||
type CreateRequest struct {
|
||||
// StackID
|
||||
// Required: true
|
||||
StackID uint64 `url:"stackId" json:"stackId" validate:"required"`
|
||||
|
||||
// Resource group ID
|
||||
// Required: true
|
||||
RGID uint64 `url:"rgId" json:"rgId" validate:"required"`
|
||||
|
||||
// Name of device
|
||||
// Required: true
|
||||
Name string `url:"name" json:"name" validate:"required"`
|
||||
|
||||
// PCI address of the device
|
||||
// Must be in format 0000:1f:2b.0
|
||||
// Required: true
|
||||
HWPath string `url:"hwPath" json:"hwPath" validate:"required,hwPath"`
|
||||
|
||||
// Description, just for information
|
||||
// Required: false
|
||||
Description string `url:"description,omitempty" json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// Create creates PCI Device
|
||||
func (p PCIDevice) Create(ctx context.Context, req CreateRequest) (uint64, error) {
|
||||
err := validators.ValidateRequest(req)
|
||||
if err != nil {
|
||||
for _, validationError := range validators.GetErrors(err) {
|
||||
return 0, validators.ValidationError(validationError)
|
||||
}
|
||||
}
|
||||
|
||||
url := "/cloudbroker/pcidevice/create"
|
||||
|
||||
res, err := p.client.DecortApiCall(ctx, http.MethodPost, url, req)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
result, err := strconv.ParseUint(string(res), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
43
pkg/cloudbroker/pcidevice/delete.go
Normal file
43
pkg/cloudbroker/pcidevice/delete.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package pcidevice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Request struct for deleting PCI device
|
||||
type DeleteRequest struct {
|
||||
// PCI device ID
|
||||
// Required: true
|
||||
DeviceID uint64 `url:"deviceId" json:"deviceId" validate:"required"`
|
||||
|
||||
// Force delete
|
||||
// Required: false
|
||||
Force bool `url:"force,omitempty" json:"force,omitempty"`
|
||||
}
|
||||
|
||||
// Delete PCI device
|
||||
func (p PCIDevice) 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/pcidevice/delete"
|
||||
|
||||
res, err := p.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
|
||||
}
|
||||
43
pkg/cloudbroker/pcidevice/disable.go
Normal file
43
pkg/cloudbroker/pcidevice/disable.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package pcidevice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Request struct for disabling PCI device
|
||||
type DisableRequest struct {
|
||||
// PCI device ID
|
||||
// Required: true
|
||||
DeviceID uint64 `url:"deviceId" json:"deviceId" validate:"required"`
|
||||
|
||||
// Force delete
|
||||
// Required: false
|
||||
Force bool `url:"force,omitempty" json:"force,omitempty"`
|
||||
}
|
||||
|
||||
// Disable PCI device
|
||||
func (p PCIDevice) Disable(ctx context.Context, req DisableRequest) (bool, error) {
|
||||
err := validators.ValidateRequest(req)
|
||||
if err != nil {
|
||||
for _, validationError := range validators.GetErrors(err) {
|
||||
return false, validators.ValidationError(validationError)
|
||||
}
|
||||
}
|
||||
|
||||
url := "/cloudbroker/pcidevice/disable"
|
||||
|
||||
res, err := p.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
|
||||
}
|
||||
39
pkg/cloudbroker/pcidevice/enable.go
Normal file
39
pkg/cloudbroker/pcidevice/enable.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package pcidevice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Request struct for enabling PCI device
|
||||
type EnableRequest struct {
|
||||
// PCI device ID
|
||||
// Required: true
|
||||
DeviceID uint64 `url:"deviceId" json:"deviceId" validate:"required"`
|
||||
}
|
||||
|
||||
// Enable PCI device
|
||||
func (p PCIDevice) Enable(ctx context.Context, req EnableRequest) (bool, error) {
|
||||
err := validators.ValidateRequest(req)
|
||||
if err != nil {
|
||||
for _, validationError := range validators.GetErrors(err) {
|
||||
return false, validators.ValidationError(validationError)
|
||||
}
|
||||
}
|
||||
|
||||
url := "/cloudbroker/pcidevice/enable"
|
||||
|
||||
res, err := p.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
|
||||
}
|
||||
26
pkg/cloudbroker/pcidevice/list.go
Normal file
26
pkg/cloudbroker/pcidevice/list.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package pcidevice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// List gets list all pci devices
|
||||
func (p PCIDevice) List(ctx context.Context) (ListPCIDevices, error) {
|
||||
url := "/cloudbroker/pcidevice/list"
|
||||
|
||||
res, err := p.client.DecortApiCall(ctx, http.MethodPost, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := ListPCIDevices{}
|
||||
|
||||
err = json.Unmarshal(res, &list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
43
pkg/cloudbroker/pcidevice/models.go
Normal file
43
pkg/cloudbroker/pcidevice/models.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package pcidevice
|
||||
|
||||
// Main information about PCI device
|
||||
type ItemPCIDevice struct {
|
||||
// CKey
|
||||
CKey string `json:"_ckey"`
|
||||
|
||||
// Meta
|
||||
Meta []interface{} `json:"_meta"`
|
||||
|
||||
// Compute ID
|
||||
ComputeID uint64 `json:"computeId"`
|
||||
|
||||
// Description
|
||||
Description string `json:"description"`
|
||||
|
||||
// GUID
|
||||
GUID uint64 `json:"guid"`
|
||||
|
||||
// HwPath
|
||||
HwPath string `json:"hwPath"`
|
||||
|
||||
// ID
|
||||
ID uint64 `json:"id"`
|
||||
|
||||
// Name
|
||||
Name string `json:"name"`
|
||||
|
||||
// Resource group ID
|
||||
RGID uint64 `json:"rgId"`
|
||||
|
||||
// Stack ID
|
||||
StackID uint64 `json:"stackId"`
|
||||
|
||||
// Status
|
||||
Status string `json:"status"`
|
||||
|
||||
// System name
|
||||
SystemName string `json:"systemName"`
|
||||
}
|
||||
|
||||
// List PCI devices
|
||||
type ListPCIDevices []ItemPCIDevice
|
||||
15
pkg/cloudbroker/pcidevice/pcidevice.go
Normal file
15
pkg/cloudbroker/pcidevice/pcidevice.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package pcidevice
|
||||
|
||||
import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
|
||||
|
||||
// Structure for creating request to PCI device
|
||||
type PCIDevice struct {
|
||||
client interfaces.Caller
|
||||
}
|
||||
|
||||
// Builder for PCI device endpoints
|
||||
func New(client interfaces.Caller) *PCIDevice {
|
||||
return &PCIDevice{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
42
pkg/cloudbroker/pcidevice/serialize.go
Normal file
42
pkg/cloudbroker/pcidevice/serialize.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package pcidevice
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/serialization"
|
||||
)
|
||||
|
||||
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
|
||||
//
|
||||
// In order to serialize with indent make sure to follow these guidelines:
|
||||
// - First argument -> prefix
|
||||
// - Second argument -> indent
|
||||
func (l ListPCIDevices) Serialize(params ...string) (serialization.Serialized, error) {
|
||||
if len(l) == 0 {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
if len(params) > 1 {
|
||||
prefix := params[0]
|
||||
indent := params[1]
|
||||
|
||||
return json.MarshalIndent(l, prefix, indent)
|
||||
}
|
||||
|
||||
return json.Marshal(l)
|
||||
}
|
||||
|
||||
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
|
||||
//
|
||||
// In order to serialize with indent make sure to follow these guidelines:
|
||||
// - First argument -> prefix
|
||||
// - Second argument -> indent
|
||||
func (i ItemPCIDevice) Serialize(params ...string) (serialization.Serialized, error) {
|
||||
if len(params) > 1 {
|
||||
prefix := params[0]
|
||||
indent := params[1]
|
||||
|
||||
return json.MarshalIndent(i, prefix, indent)
|
||||
}
|
||||
|
||||
return json.Marshal(i)
|
||||
}
|
||||
@@ -24,23 +24,23 @@ type UpdateRequest struct {
|
||||
|
||||
// Max size of memory in MB
|
||||
// Required: false
|
||||
MaxMemoryCapacity uint64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
|
||||
MaxMemoryCapacity int64 `url:"maxMemoryCapacity,omitempty" json:"maxMemoryCapacity,omitempty"`
|
||||
|
||||
// Max size of aggregated virtual disks in GB
|
||||
// Required: false
|
||||
MaxVDiskCapacity uint64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
|
||||
MaxVDiskCapacity int64 `url:"maxVDiskCapacity,omitempty" json:"maxVDiskCapacity,omitempty"`
|
||||
|
||||
// Max number of CPU cores
|
||||
// Required: false
|
||||
MaxCPUCapacity uint64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
|
||||
MaxCPUCapacity int64 `url:"maxCPUCapacity,omitempty" json:"maxCPUCapacity,omitempty"`
|
||||
|
||||
// Max sent/received network transfer peering
|
||||
// Required: false
|
||||
MaxNetworkPeerTransfer uint64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
|
||||
MaxNetworkPeerTransfer int64 `url:"maxNetworkPeerTransfer,omitempty" json:"maxNetworkPeerTransfer,omitempty"`
|
||||
|
||||
// Max number of assigned public IPs
|
||||
// Required: false
|
||||
MaxNumPublicIP uint64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
|
||||
MaxNumPublicIP int64 `url:"maxNumPublicIP,omitempty" json:"maxNumPublicIP,omitempty"`
|
||||
|
||||
// Register computes in registration system
|
||||
// Required: false
|
||||
|
||||
8
pkg/cloudbroker/vgpu.go
Normal file
8
pkg/cloudbroker/vgpu.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package cloudbroker
|
||||
|
||||
import "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/vgpu"
|
||||
|
||||
// Accessing the VGPU method group
|
||||
func (cb *CloudBroker) VGPU() *vgpu.VGPU {
|
||||
return vgpu.New(cb.client)
|
||||
}
|
||||
39
pkg/cloudbroker/vgpu/allocate.go
Normal file
39
pkg/cloudbroker/vgpu/allocate.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package vgpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Request for allocating VGPU
|
||||
type AllocateRequest struct {
|
||||
// Virtual GPU ID
|
||||
// Required: true
|
||||
VGPUID uint64 `url:"vgpuId" json:"vgpuId" validate:"required"`
|
||||
}
|
||||
|
||||
// Allocate allocates GPU
|
||||
func (v VGPU) Allocate(ctx context.Context, req AllocateRequest) (bool, error) {
|
||||
err := validators.ValidateRequest(req)
|
||||
if err != nil {
|
||||
for _, validationError := range validators.GetErrors(err) {
|
||||
return false, validators.ValidationError(validationError)
|
||||
}
|
||||
}
|
||||
|
||||
url := "/cloudbroker/vgpu/allocate"
|
||||
|
||||
res, err := v.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
|
||||
}
|
||||
51
pkg/cloudbroker/vgpu/create.go
Normal file
51
pkg/cloudbroker/vgpu/create.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package vgpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Request struct for creating VGPU
|
||||
type CreateRequest struct {
|
||||
// ID of pGPU
|
||||
// Required: true
|
||||
PGPUID uint64 `url:"pgpuId" json:"pgpuId" validate:"required"`
|
||||
|
||||
// ID of the target resource group.
|
||||
// Required: true
|
||||
RGID uint64 `url:"rgId" json:"rgId" validate:"required"`
|
||||
|
||||
// Virtual profile id
|
||||
// Required: false
|
||||
ProfileID uint64 `url:"profileId,omitempty" json:"profileId,omitempty"`
|
||||
|
||||
// Allocate vgpu after creation
|
||||
// Required: false
|
||||
Allocate bool `url:"allocate,omitempty" json:"allocate,omitempty"`
|
||||
}
|
||||
|
||||
// Create creates VGPU
|
||||
func (v VGPU) Create(ctx context.Context, req CreateRequest) (uint64, error) {
|
||||
err := validators.ValidateRequest(req)
|
||||
if err != nil {
|
||||
for _, validationError := range validators.GetErrors(err) {
|
||||
return 0, validators.ValidationError(validationError)
|
||||
}
|
||||
}
|
||||
|
||||
url := "/cloudbroker/vgpu/create"
|
||||
|
||||
res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
result, err := strconv.ParseUint(string(res), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
43
pkg/cloudbroker/vgpu/deallocate.go
Normal file
43
pkg/cloudbroker/vgpu/deallocate.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package vgpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Request for deallocating VGPU
|
||||
type DeallocateRequest struct {
|
||||
// Virtual GPU ID
|
||||
// Required: true
|
||||
VGPUID uint64 `url:"vgpuId" json:"vgpuId" validate:"required"`
|
||||
|
||||
// Force delete (detach from compute)
|
||||
// Required: false
|
||||
Force bool `url:"force,omitempty" json:"force,omitempty"`
|
||||
}
|
||||
|
||||
// Deallocate releases GPU resources
|
||||
func (v VGPU) Deallocate(ctx context.Context, req DeallocateRequest) (bool, error) {
|
||||
err := validators.ValidateRequest(req)
|
||||
if err != nil {
|
||||
for _, validationError := range validators.GetErrors(err) {
|
||||
return false, validators.ValidationError(validationError)
|
||||
}
|
||||
}
|
||||
|
||||
url := "/cloudbroker/vgpu/deallocate"
|
||||
|
||||
res, err := v.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
|
||||
}
|
||||
43
pkg/cloudbroker/vgpu/destroy.go
Normal file
43
pkg/cloudbroker/vgpu/destroy.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package vgpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Request for destroying VGPU
|
||||
type DestroyRequest struct {
|
||||
// Virtual GPU ID
|
||||
// Required: true
|
||||
VGPUID uint64 `url:"vgpuId" json:"vgpuId" validate:"required"`
|
||||
|
||||
// Force delete (deallocate and detach from compute)
|
||||
// Required: false
|
||||
Force bool `url:"force,omitempty" json:"force,omitempty"`
|
||||
}
|
||||
|
||||
// Destroy destroys VGPU
|
||||
func (v VGPU) Destroy(ctx context.Context, req DestroyRequest) (bool, error) {
|
||||
err := validators.ValidateRequest(req)
|
||||
if err != nil {
|
||||
for _, validationError := range validators.GetErrors(err) {
|
||||
return false, validators.ValidationError(validationError)
|
||||
}
|
||||
}
|
||||
|
||||
url := "/cloudbroker/vgpu/destroy"
|
||||
|
||||
res, err := v.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
|
||||
}
|
||||
37
pkg/cloudbroker/vgpu/list.go
Normal file
37
pkg/cloudbroker/vgpu/list.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package vgpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Request struct for getting list of VGPU
|
||||
type ListRequest struct {
|
||||
// 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 all VGPU
|
||||
func (v VGPU) List(ctx context.Context, req ListRequest) (ListVGPU, error) {
|
||||
url := "/cloudbroker/vgpu/list"
|
||||
|
||||
res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := ListVGPU{}
|
||||
|
||||
err = json.Unmarshal(res, &list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
66
pkg/cloudbroker/vgpu/models.go
Normal file
66
pkg/cloudbroker/vgpu/models.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package vgpu
|
||||
|
||||
type ItemVGPU struct {
|
||||
// CKey
|
||||
CKey string `json:"_ckey"`
|
||||
|
||||
// Meta
|
||||
Meta []interface{} `json:"_meta"`
|
||||
|
||||
// Account ID
|
||||
AccountID uint64 `json:"accountId"`
|
||||
|
||||
// Created time
|
||||
CreatedTime uint64 `json:"createdTime"`
|
||||
|
||||
// Deleted time
|
||||
DeletedTime uint64 `json:"deletedTime"`
|
||||
|
||||
//Grid ID
|
||||
GID uint64 `json:"gid"`
|
||||
|
||||
// GUID
|
||||
GUID uint64 `json:"guid"`
|
||||
|
||||
// VGPU ID
|
||||
ID uint64 `json:"id"`
|
||||
|
||||
// Last claimed by
|
||||
LastClaimedBy uint64 `json:"lastClaimedBy"`
|
||||
|
||||
// Last update time
|
||||
LastUpdateTime uint64 `json:"lastUpdateTime"`
|
||||
|
||||
// Mode
|
||||
Mode string `json:"mode"`
|
||||
|
||||
// PCI Slot
|
||||
PCISlot interface{} `json:"pciSlot"`
|
||||
|
||||
// PGPUID
|
||||
PGPUID uint64 `json:"pgpuid"`
|
||||
|
||||
// Profile ID
|
||||
ProfileID interface{} `json:"profileId"`
|
||||
|
||||
// RAM
|
||||
RAM uint64 `json:"ram"`
|
||||
|
||||
// Reference ID
|
||||
ReferenceID interface{} `json:"referenceId"`
|
||||
|
||||
// RGID
|
||||
RGID uint64 `json:"rgId"`
|
||||
|
||||
// Status
|
||||
Status string `json:"status"`
|
||||
|
||||
// Type
|
||||
Type string `json:"type"`
|
||||
|
||||
// VMID
|
||||
VMID uint64 `json:"vmid"`
|
||||
}
|
||||
|
||||
// List of VGPU
|
||||
type ListVGPU []ItemVGPU
|
||||
42
pkg/cloudbroker/vgpu/serialize.go
Normal file
42
pkg/cloudbroker/vgpu/serialize.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package vgpu
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/serialization"
|
||||
)
|
||||
|
||||
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
|
||||
//
|
||||
// In order to serialize with indent make sure to follow these guidelines:
|
||||
// - First argument -> prefix
|
||||
// - Second argument -> indent
|
||||
func (l ListVGPU) Serialize(params ...string) (serialization.Serialized, error) {
|
||||
if len(l) == 0 {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
if len(params) > 1 {
|
||||
prefix := params[0]
|
||||
indent := params[1]
|
||||
|
||||
return json.MarshalIndent(l, prefix, indent)
|
||||
}
|
||||
|
||||
return json.Marshal(l)
|
||||
}
|
||||
|
||||
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
|
||||
//
|
||||
// In order to serialize with indent make sure to follow these guidelines:
|
||||
// - First argument -> prefix
|
||||
// - Second argument -> indent
|
||||
func (i ItemVGPU) Serialize(params ...string) (serialization.Serialized, error) {
|
||||
if len(params) > 1 {
|
||||
prefix := params[0]
|
||||
indent := params[1]
|
||||
|
||||
return json.MarshalIndent(i, prefix, indent)
|
||||
}
|
||||
|
||||
return json.Marshal(i)
|
||||
}
|
||||
15
pkg/cloudbroker/vgpu/vgpu.go
Normal file
15
pkg/cloudbroker/vgpu/vgpu.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package vgpu
|
||||
|
||||
import "repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
|
||||
|
||||
// Structure for creating request to VGPU
|
||||
type VGPU struct {
|
||||
client interfaces.Caller
|
||||
}
|
||||
|
||||
// Builder for VGPU endpoints
|
||||
func New(client interfaces.Caller) *VGPU {
|
||||
return &VGPU{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user