diff --git a/.gitignore b/.gitignore index c4c9112..224dd8c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ cmd/ -.idea/ \ No newline at end of file +.idea/ +.vscode/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4113a2f..13c212b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ ## Version 1.4.7 ### Bugfix -- Deleted validate:"required" tag from IPCIDR field in cloudapi/vins/createInRg request struct \ No newline at end of file +- Deleted validate:"required" tag from IPCIDR field in cloudapi/vins/createInRg request struct diff --git a/internal/validators/values.go b/internal/validators/values.go index c2032de..42f0968 100644 --- a/internal/validators/values.go +++ b/internal/validators/values.go @@ -6,7 +6,7 @@ var ( resTypesValues = []string{"compute", "vins", "k8s", "openshift", "lb", "flipgroup"} protoValues = []string{"tcp", "udp"} - accountCUTypeValues = []string{"CU_M", "CU_C", "CU_D", "CU_S", "CU_A", "CU_NO", "CU_I", "CU_NP"} + accountCUTypeValues = []string{"CU_M", "CU_C", "CU_D", "CU_DM", "CU_S", "CU_A", "CU_NO", "CU_I", "CU_NP"} bserviceModeValues = []string{"ABSOLUTE", "RELATIVE"} diff --git a/pkg/cloudapi/account/filter.go b/pkg/cloudapi/account/filter.go index be18360..aa4d709 100644 --- a/pkg/cloudapi/account/filter.go +++ b/pkg/cloudapi/account/filter.go @@ -48,21 +48,23 @@ func (la ListAccounts) FilterByUserGroupID(userGroupID string) ListAccounts { func (la ListAccounts) FilterFunc(predicate func(ItemAccount) bool) ListAccounts { var result ListAccounts - for _, acc := range la { + for _, acc := range la.Data { if predicate(acc) { - result = append(result, acc) + result.Data = append(result.Data, acc) } } + result.EntryCount = uint64(len(result.Data)) + return result } // FindOne returns first found ItemAccount. // If none was found, returns an empty struct. func (la ListAccounts) FindOne() ItemAccount { - if len(la) == 0 { + if la.EntryCount == 0 { return ItemAccount{} } - return la[0] + return la.Data[0] } diff --git a/pkg/cloudapi/account/filter_test.go b/pkg/cloudapi/account/filter_test.go index 0e98cc2..b1e7f9f 100644 --- a/pkg/cloudapi/account/filter_test.go +++ b/pkg/cloudapi/account/filter_test.go @@ -5,68 +5,71 @@ import ( ) var accounts = ListAccounts{ - ItemAccount{ - ACL: []RecordACL{ - { - IsExplicit: true, - GUID: "", - Rights: "CXDRAU", - Status: "CONFIRMED", - Type: "U", - UgroupID: "timofey_tkachev_1@decs3o", + Data: []ItemAccount{ + { + ACL: []RecordACL{ + { + IsExplicit: true, + GUID: "", + Rights: "CXDRAU", + Status: "CONFIRMED", + Type: "U", + UgroupID: "timofey_tkachev_1@decs3o", + }, }, + CreatedTime: 1676645275, + DeletedTime: 0, + ID: 132846, + Name: "std", + Status: "CONFIRMED", + UpdatedTime: 1676645275, }, - CreatedTime: 1676645275, - DeletedTime: 0, - ID: 132846, - Name: "std", - Status: "CONFIRMED", - UpdatedTime: 1676645275, - }, - ItemAccount{ - ACL: []RecordACL{ - { - IsExplicit: true, - GUID: "", - Rights: "CXDRAU", - Status: "CONFIRMED", - Type: "U", - UgroupID: "not_really_timofey_tkachev_1@decs3o", + { + ACL: []RecordACL{ + { + IsExplicit: true, + GUID: "", + Rights: "CXDRAU", + Status: "CONFIRMED", + Type: "U", + UgroupID: "not_really_timofey_tkachev_1@decs3o", + }, }, + CreatedTime: 1676878820, + DeletedTime: 0, + ID: 132847, + Name: "std_2", + Status: "CONFIRMED", + UpdatedTime: 1676645275, }, - CreatedTime: 1676878820, - DeletedTime: 0, - ID: 132847, - Name: "std_2", - Status: "CONFIRMED", - UpdatedTime: 1676645275, - }, - ItemAccount{ - ACL: []RecordACL{ - { - IsExplicit: true, - GUID: "", - Rights: "CXDRAU", - Status: "CONFIRMED", - Type: "U", - UgroupID: "timofey_tkachev_1@decs3o", - }, - { - IsExplicit: true, - GUID: "", - Rights: "CXDRAU", - Status: "CONFIRMED", - Type: "U", - UgroupID: "second_account@decs3o", + { + ACL: []RecordACL{ + { + IsExplicit: true, + GUID: "", + Rights: "CXDRAU", + Status: "CONFIRMED", + Type: "U", + UgroupID: "timofey_tkachev_1@decs3o", + }, + { + IsExplicit: true, + GUID: "", + Rights: "CXDRAU", + Status: "CONFIRMED", + Type: "U", + UgroupID: "second_account@decs3o", + }, }, + CreatedTime: 1676883850, + DeletedTime: 1676883899, + ID: 132848, + Name: "std_broker", + Status: "DELETED", + UpdatedTime: 1676878820, }, - CreatedTime: 1676883850, - DeletedTime: 1676883899, - ID: 132848, - Name: "std_broker", - Status: "DELETED", - UpdatedTime: 1676878820, }, + EntryCount: 3, } func TestFilterByID(t *testing.T) { @@ -100,11 +103,11 @@ func TestFilterByName(t *testing.T) { func TestFilterByStatus(t *testing.T) { actual := accounts.FilterByStatus("CONFIRMED") - if len(actual) != 2 { - t.Fatal("Expected 2 elements in slice, found: ", len(actual)) + if len(actual.Data) != 2 { + t.Fatal("Expected 2 elements in slice, found: ", len(actual.Data)) } - for _, item := range actual { + for _, item := range actual.Data { if item.Status != "CONFIRMED" { t.Fatal("expected CONFIRMED, found: ", item.Status) } @@ -116,7 +119,7 @@ func TestFilterFunc(t *testing.T) { return ia.DeletedTime == 0 }) - for _, item := range actual { + for _, item := range actual.Data { if item.DeletedTime != 0 { t.Fatal("Expected DeletedTime = 0, found: ", item.DeletedTime) } @@ -126,21 +129,21 @@ func TestFilterFunc(t *testing.T) { func TestSortingByCreatedTime(t *testing.T) { actual := accounts.SortByCreatedTime(false) - if actual[0].Name != "std" { - t.Fatal("Expected account std as earliest, found: ", actual[0].Name) + if actual.Data[0].Name != "std" { + t.Fatal("Expected account std as earliest, found: ", actual.Data[0].Name) } actual = accounts.SortByCreatedTime(true) - if actual[0].Name != "std_broker" { - t.Fatal("Expected account std_broker as latest, found: ", actual[0].Name) + if actual.Data[0].Name != "std_broker" { + t.Fatal("Expected account std_broker as latest, found: ", actual.Data[0].Name) } } func TestFilterEmpty(t *testing.T) { actual := accounts.FilterByID(0) - if len(actual) != 0 { - t.Fatal("Expected 0 found, actual: ", len(actual)) + if len(actual.Data) != 0 { + t.Fatal("Expected 0 found, actual: ", len(actual.Data)) } } diff --git a/pkg/cloudapi/account/get_consumed_account_units.go b/pkg/cloudapi/account/get_consumed_account_units.go index 02aeab2..23c15fc 100644 --- a/pkg/cloudapi/account/get_consumed_account_units.go +++ b/pkg/cloudapi/account/get_consumed_account_units.go @@ -20,6 +20,7 @@ type GetConsumedAccountUnitsRequest struct { // - CU_M: consumed memory in MB // - CU_C: number of cpu cores // - CU_D: consumed vdisk storage in GB +// - CU_DM: consumed max vdisk storage in GB // - CU_I: number of public IPs func (a Account) GetConsumedAccountUnits(ctx context.Context, req GetConsumedAccountUnitsRequest) (*ResourceLimits, error) { err := validators.ValidateRequest(req) diff --git a/pkg/cloudapi/account/get_consumed_cloud_units_by_type.go b/pkg/cloudapi/account/get_consumed_cloud_units_by_type.go index 2347980..e09a58d 100644 --- a/pkg/cloudapi/account/get_consumed_cloud_units_by_type.go +++ b/pkg/cloudapi/account/get_consumed_cloud_units_by_type.go @@ -26,6 +26,7 @@ type GetConsumedCloudUnitsByTypeRequest struct { // - CU_M: returns consumed memory in MB // - CU_C: returns number of virtual cpu cores // - CU_D: returns consumed virtual disk storage in GB +// - CU_DM: returns consumed max virtual disk storage in GB // - CU_S: returns consumed primary storage (NAS) in TB // - CU_A: returns consumed secondary storage (Archive) in TB // - CU_NO: returns sent/received network transfer in operator in GB diff --git a/pkg/cloudapi/account/get_reserved_account_units.go b/pkg/cloudapi/account/get_reserved_account_units.go index d8d3ab0..c3f9605 100644 --- a/pkg/cloudapi/account/get_reserved_account_units.go +++ b/pkg/cloudapi/account/get_reserved_account_units.go @@ -21,6 +21,7 @@ type GetReservedAccountUnitsRequest struct { // - CU_M: reserved memory in MB // - CU_C: number of cpu cores // - CU_D: reserved vdisk storage in GB +// - CU_DM: reserved max vdisk storage in GB // - CU_I: number of public IPs func (a Account) GetReservedAccountUnits(ctx context.Context, req GetReservedAccountUnitsRequest) (*ResourceLimits, error) { err := validators.ValidateRequest(req) diff --git a/pkg/cloudapi/account/get_resource_consumption.go b/pkg/cloudapi/account/get_resource_consumption.go new file mode 100644 index 0000000..ae65e02 --- /dev/null +++ b/pkg/cloudapi/account/get_resource_consumption.go @@ -0,0 +1,42 @@ +package account + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// Request struct for getting resource consumption +type GetResourceConsumptionRequest struct { + // ID an account + // Required: true + AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` +} + +// 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) { + err := validators.ValidateRequest(req) + if err != nil { + for _, validationError := range validators.GetErrors(err) { + return nil, validators.ValidationError(validationError) + } + } + + url := "/cloudapi/account/getResourceConsumption" + + info := ItemResourceConsumption{} + + res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudapi/account/list.go b/pkg/cloudapi/account/list.go index 6c59b20..acaba37 100644 --- a/pkg/cloudapi/account/list.go +++ b/pkg/cloudapi/account/list.go @@ -8,17 +8,33 @@ import ( // Request struct for get list of accounts 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 access control list + // Required: false + ACL string `url:"acl,omitempty" json:"acl,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + // Page number // Required: false - Page uint64 `url:"page" json:"page"` + Page uint64 `url:"page,omitempty" json:"page,omitempty"` // Page size // Required: false - Size uint64 `url:"size" json:"size"` + Size uint64 `url:"size,omitempty" json:"size,omitempty"` } // List gets list all accounts the user has access to -func (a Account) List(ctx context.Context, req ListRequest) (ListAccounts, error) { +func (a Account) List(ctx context.Context, req ListRequest) (*ListAccounts, error) { url := "/cloudapi/account/list" res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -33,5 +49,5 @@ func (a Account) List(ctx context.Context, req ListRequest) (ListAccounts, error return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/account/list_deleted.go b/pkg/cloudapi/account/list_deleted.go index 313e343..fd3e231 100644 --- a/pkg/cloudapi/account/list_deleted.go +++ b/pkg/cloudapi/account/list_deleted.go @@ -10,15 +10,15 @@ import ( type ListDeletedRequest struct { // Page number // Required: false - Page uint64 `url:"page" json:"page"` + Page uint64 `url:"page,omitempty" json:"page,omitempty"` // Page size // Required: false - Size uint64 `url:"size" json:"size"` + Size uint64 `url:"size,omitempty" json:"size,omitempty"` } // ListDeleted gets list all deleted accounts the user has access to -func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListAccounts, error) { +func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListAccounts, error) { url := "/cloudapi/account/listDeleted" res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -33,5 +33,5 @@ func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListA return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/account/list_resource_consumption.go b/pkg/cloudapi/account/list_resource_consumption.go new file mode 100644 index 0000000..be7df42 --- /dev/null +++ b/pkg/cloudapi/account/list_resource_consumption.go @@ -0,0 +1,26 @@ +package account + +import ( + "context" + "encoding/json" + "net/http" +) + +// ListResourceConsumption show data list amount of consumed and reserved resources (cpu, ram, disk) by specific accounts +func (a Account) ListResourceConsumption(ctx context.Context) (*ListResourceConsumption, error) { + url := "/cloudapi/account/listResourceConsumption" + + info := ListResourceConsumption{} + + res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, nil) + if err != nil { + return nil, err + } + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudapi/account/models.go b/pkg/cloudapi/account/models.go index e2dec19..7a46633 100644 --- a/pkg/cloudapi/account/models.go +++ b/pkg/cloudapi/account/models.go @@ -32,6 +32,9 @@ type ResourceLimits struct { // Disk size, GB CUD float64 `json:"CU_D"` + // Max disk size, GB + CU_DM float64 `json:"CU_DM"` + // Number of public IP addresses CUI float64 `json:"CU_I"` @@ -70,7 +73,11 @@ type ItemAccount struct { } // List of accounts -type ListAccounts []ItemAccount +type ListAccounts struct { + Data []ItemAccount `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} // Resources used type Resource struct { @@ -109,12 +116,21 @@ type DiskUsage struct { } // Information about resources -type Resources struct { +type ItemResourceConsumption struct { // Current information about resources Current Resource `json:"Current"` // Reserved information about resources Reserved Resource `json:"Reserved"` + + // Account ID + AccountID uint64 `json:"id"` +} + +type ListResourceConsumption struct { + Data []ItemResourceConsumption `json:"data"` + + EntryCount uint64 `json:"entryCount"` } // Information about computes @@ -140,9 +156,6 @@ type RecordAccount struct { // DCLocation DCLocation string `json:"DCLocation"` - // Resources - Resources Resources `json:"Resources"` - // CKey CKey string `json:"_ckey"` diff --git a/pkg/cloudapi/account/serialize.go b/pkg/cloudapi/account/serialize.go index 8ee25ca..5c45955 100644 --- a/pkg/cloudapi/account/serialize.go +++ b/pkg/cloudapi/account/serialize.go @@ -12,7 +12,7 @@ import ( // - First argument -> prefix // - Second argument -> indent func (la ListAccounts) Serialize(params ...string) (serialization.Serialized, error) { - if len(la) == 0 { + if la.EntryCount == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/account/sorting.go b/pkg/cloudapi/account/sorting.go index daf5ffd..7303f75 100644 --- a/pkg/cloudapi/account/sorting.go +++ b/pkg/cloudapi/account/sorting.go @@ -6,16 +6,16 @@ import "sort" // // If inverse param is set to true, the order is reversed. func (la ListAccounts) SortByCreatedTime(inverse bool) ListAccounts { - if len(la) < 2 { + if la.EntryCount < 2 { return la } - sort.Slice(la, func(i, j int) bool { + sort.Slice(la.Data, func(i, j int) bool { if inverse { - return la[i].CreatedTime > la[j].CreatedTime + return la.Data[i].CreatedTime > la.Data[j].CreatedTime } - return la[i].CreatedTime < la[j].CreatedTime + return la.Data[i].CreatedTime < la.Data[j].CreatedTime }) return la @@ -25,16 +25,16 @@ func (la ListAccounts) SortByCreatedTime(inverse bool) ListAccounts { // // If inverse param is set to true, the order is reversed. func (la ListAccounts) SortByUpdatedTime(inverse bool) ListAccounts { - if len(la) < 2 { + if la.EntryCount < 2 { return la } - sort.Slice(la, func(i, j int) bool { + sort.Slice(la.Data, func(i, j int) bool { if inverse { - return la[i].UpdatedTime > la[j].UpdatedTime + return la.Data[i].UpdatedTime > la.Data[j].UpdatedTime } - return la[i].UpdatedTime < la[j].UpdatedTime + return la.Data[i].UpdatedTime < la.Data[j].UpdatedTime }) return la @@ -44,16 +44,16 @@ func (la ListAccounts) SortByUpdatedTime(inverse bool) ListAccounts { // // If inverse param is set to true, the order is reversed. func (la ListAccounts) SortByDeletedTime(inverse bool) ListAccounts { - if len(la) < 2 { + if la.EntryCount < 2 { return la } - sort.Slice(la, func(i, j int) bool { + sort.Slice(la.Data, func(i, j int) bool { if inverse { - return la[i].DeletedTime > la[j].DeletedTime + return la.Data[i].DeletedTime > la.Data[j].DeletedTime } - return la[i].DeletedTime < la[j].DeletedTime + return la.Data[i].DeletedTime < la.Data[j].DeletedTime }) return la diff --git a/pkg/cloudapi/bservice/filter.go b/pkg/cloudapi/bservice/filter.go index 311f46b..f503212 100644 --- a/pkg/cloudapi/bservice/filter.go +++ b/pkg/cloudapi/bservice/filter.go @@ -49,21 +49,23 @@ func (lbs ListBasicServices) FilterByTechStatus(techStatus string) ListBasicServ func (lbs ListBasicServices) FilterFunc(predicate func(ItemBasicService) bool) ListBasicServices { var result ListBasicServices - for _, item := range lbs { + for _, item := range lbs.Data { if predicate(item) { - result = append(result, item) + result.Data = append(result.Data, item) } } + result.EntryCount = uint64(len(lbs.Data)) + return result } // FindOne returns first found ItemBasicService // If none was found, returns an empty struct. func (lbs ListBasicServices) FindOne() ItemBasicService { - if len(lbs) == 0 { + if lbs.EntryCount == 0 { return ItemBasicService{} } - return lbs[0] + return lbs.Data[0] } diff --git a/pkg/cloudapi/bservice/filter_test.go b/pkg/cloudapi/bservice/filter_test.go index cb7930d..70e2949 100644 --- a/pkg/cloudapi/bservice/filter_test.go +++ b/pkg/cloudapi/bservice/filter_test.go @@ -3,78 +3,81 @@ package bservice import "testing" var bservices = ListBasicServices{ - { - AccountID: 1, - AccountName: "std_1", - BaseDomain: "", - CreatedBy: "sample_user_1@decs3o", - CreatedTime: 1677743675, - DeletedBy: "", - DeletedTime: 0, - GID: 212, - Groups: []uint64{}, - GUID: 1, - ID: 1, - Name: "bservice_1", - ParentSrvID: 0, - ParentSrvType: "", - RGID: 7971, - RGName: "rg_1", - SSHUser: "", - Status: "CREATED", - TechStatus: "STOPPED", - UpdatedBy: "", - UpdatedTime: 0, - UserManaged: true, - }, - { - AccountID: 2, - AccountName: "std_2", - BaseDomain: "", - CreatedBy: "sample_user_1@decs3o", - CreatedTime: 1677743736, - DeletedBy: "", - DeletedTime: 0, - GID: 212, - Groups: []uint64{}, - GUID: 2, - ID: 2, - Name: "bservice_2", - ParentSrvID: 0, - ParentSrvType: "", - RGID: 7972, - RGName: "rg_2", - SSHUser: "", - Status: "CREATED", - TechStatus: "STOPPED", - UpdatedBy: "", - UpdatedTime: 0, - UserManaged: true, - }, - { - AccountID: 3, - AccountName: "std_3", - BaseDomain: "", - CreatedBy: "sample_user_2@decs3o", - CreatedTime: 1677743830, - DeletedBy: "", - DeletedTime: 0, - GID: 212, - Groups: []uint64{}, - GUID: 3, - ID: 3, - Name: "bservice_3", - ParentSrvID: 0, - ParentSrvType: "", - RGID: 7973, - RGName: "rg_3", - SSHUser: "", - Status: "ENABLED", - TechStatus: "STARTED", - UpdatedBy: "", - UpdatedTime: 0, - UserManaged: true, + Data: []ItemBasicService{ + { + AccountID: 1, + AccountName: "std_1", + BaseDomain: "", + CreatedBy: "sample_user_1@decs3o", + CreatedTime: 1677743675, + DeletedBy: "", + DeletedTime: 0, + GID: 212, + Groups: []uint64{}, + GUID: 1, + ID: 1, + Name: "bservice_1", + ParentSrvID: 0, + ParentSrvType: "", + RGID: 7971, + RGName: "rg_1", + SSHUser: "", + Status: "CREATED", + TechStatus: "STOPPED", + UpdatedBy: "", + UpdatedTime: 0, + UserManaged: true, + }, + { + AccountID: 2, + AccountName: "std_2", + BaseDomain: "", + CreatedBy: "sample_user_1@decs3o", + CreatedTime: 1677743736, + DeletedBy: "", + DeletedTime: 0, + GID: 212, + Groups: []uint64{}, + GUID: 2, + ID: 2, + Name: "bservice_2", + ParentSrvID: 0, + ParentSrvType: "", + RGID: 7972, + RGName: "rg_2", + SSHUser: "", + Status: "CREATED", + TechStatus: "STOPPED", + UpdatedBy: "", + UpdatedTime: 0, + UserManaged: true, + }, + { + AccountID: 3, + AccountName: "std_3", + BaseDomain: "", + CreatedBy: "sample_user_2@decs3o", + CreatedTime: 1677743830, + DeletedBy: "", + DeletedTime: 0, + GID: 212, + Groups: []uint64{}, + GUID: 3, + ID: 3, + Name: "bservice_3", + ParentSrvID: 0, + ParentSrvType: "", + RGID: 7973, + RGName: "rg_3", + SSHUser: "", + Status: "ENABLED", + TechStatus: "STARTED", + UpdatedBy: "", + UpdatedTime: 0, + UserManaged: true, + }, }, + EntryCount: 3, } func TestFilterByID(t *testing.T) { @@ -104,11 +107,11 @@ func TestFilterByRGID(t *testing.T) { func TestFilterByStatus(t *testing.T) { actual := bservices.FilterByStatus("CREATED") - 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.Status != "CREATED" { t.Fatal("expected Status 'CREATED', found: ", item.Status) } @@ -118,11 +121,11 @@ func TestFilterByStatus(t *testing.T) { func TestFilterByTechStatus(t *testing.T) { actual := bservices.FilterByTechStatus("STOPPED") - 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.TechStatus != "STOPPED" { t.Fatal("expected TechStatus 'STOPPED', found: ", item.TechStatus) } @@ -134,8 +137,8 @@ func TestFilterFunc(t *testing.T) { return ibs.CreatedBy == "sample_user_2@decs3o" }) - if len(actual) > 1 { - t.Fatal("expected 1 found, actual: ", len(actual)) + if len(actual.Data) > 1 { + t.Fatal("expected 1 found, actual: ", len(actual.Data)) } if actual.FindOne().CreatedBy != "sample_user_2@decs3o" { @@ -146,7 +149,7 @@ func TestFilterFunc(t *testing.T) { func TestSortByCreatedTime(t *testing.T) { actual := bservices.SortByCreatedTime(true) - if actual[0].CreatedTime != 1677743830 || actual[2].CreatedTime != 1677743675 { + if actual.Data[0].CreatedTime != 1677743830 || actual.Data[2].CreatedTime != 1677743675 { t.Fatal("expected descending order, found ascending") } } diff --git a/pkg/cloudapi/bservice/list.go b/pkg/cloudapi/bservice/list.go index 9f8bd17..f768d6f 100644 --- a/pkg/cloudapi/bservice/list.go +++ b/pkg/cloudapi/bservice/list.go @@ -6,16 +6,40 @@ import ( "net/http" ) -// Request struct for get list/deleted list BasicService instances +// Request struct for get list BasicService instances 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"` + // ID of the account to query for BasicService instances // Required: false AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + // Find by resource group name + // Required: false + RGName string `url:"rgName,omitempty" json:"rgName,omitempty"` + // ID of the resource group to query for BasicService instances // Required: false RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"` + // Find by tech status + // Required: false + TechStatus string `url:"techStatus,omitempty" json:"techStatus,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Find by account name + // Required: false + AccountName string `url:"accountName,omitempty" json:"accountName,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -26,7 +50,7 @@ type ListRequest struct { } // List gets list BasicService instances associated with the specified Resource Group -func (b BService) List(ctx context.Context, req ListRequest) (ListBasicServices, error) { +func (b BService) List(ctx context.Context, req ListRequest) (*ListBasicServices, error) { url := "/cloudapi/bservice/list" res, err := b.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -41,24 +65,5 @@ func (b BService) List(ctx context.Context, req ListRequest) (ListBasicServices, return nil, err } - return list, nil -} - -// ListDeleted gets list deleted BasicService instances associated with the specified Resource Group -func (b BService) ListDeleted(ctx context.Context, req ListRequest) (ListBasicServices, error) { - url := "/cloudapi/bservice/listDeleted" - - res, err := b.client.DecortApiCall(ctx, http.MethodPost, url, req) - if err != nil { - return nil, err - } - - list := ListBasicServices{} - - err = json.Unmarshal(res, &list) - if err != nil { - return nil, err - } - - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/bservice/list_deleted.go b/pkg/cloudapi/bservice/list_deleted.go new file mode 100644 index 0000000..cf9856e --- /dev/null +++ b/pkg/cloudapi/bservice/list_deleted.go @@ -0,0 +1,45 @@ +package bservice + +import ( + "context" + "encoding/json" + "net/http" +) + +// Request struct for get list of deleted BasicService instances +type ListDeletedRequest struct { + // ID of the account to query for BasicService instances + // Required: false + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + + // ID of the resource group to query for BasicService instances + // Required: false + RGID uint64 `url:"rgId,omitempty" json:"rgId,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"` +} + +// ListDeleted gets list deleted BasicService instances associated with the specified Resource Group +func (b BService) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListBasicServices, error) { + url := "/cloudapi/bservice/listDeleted" + + res, err := b.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + list := ListBasicServices{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} diff --git a/pkg/cloudapi/bservice/models.go b/pkg/cloudapi/bservice/models.go index f0aa48f..4432780 100644 --- a/pkg/cloudapi/bservice/models.go +++ b/pkg/cloudapi/bservice/models.go @@ -373,4 +373,8 @@ type ItemBasicService struct { } // List of BasicServices -type ListBasicServices []ItemBasicService +type ListBasicServices struct { + Data []ItemBasicService `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} diff --git a/pkg/cloudapi/bservice/serialize.go b/pkg/cloudapi/bservice/serialize.go index 8968bc4..ab23a16 100644 --- a/pkg/cloudapi/bservice/serialize.go +++ b/pkg/cloudapi/bservice/serialize.go @@ -12,7 +12,7 @@ import ( // - First argument -> prefix // - Second argument -> indent func (lbs ListBasicServices) Serialize(params ...string) (serialization.Serialized, error) { - if len(lbs) == 0 { + if lbs.EntryCount == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/bservice/sorting.go b/pkg/cloudapi/bservice/sorting.go index 93ab69f..3fdaed1 100644 --- a/pkg/cloudapi/bservice/sorting.go +++ b/pkg/cloudapi/bservice/sorting.go @@ -6,16 +6,16 @@ import "sort" // // If inverse param is set to true, the order is reversed. func (lbs ListBasicServices) SortByCreatedTime(inverse bool) ListBasicServices { - if len(lbs) < 2 { + if lbs.EntryCount < 2 { return lbs } - sort.Slice(lbs, func(i, j int) bool { + sort.Slice(lbs.Data, func(i, j int) bool { if inverse { - return lbs[i].CreatedTime > lbs[j].CreatedTime + return lbs.Data[i].CreatedTime > lbs.Data[j].CreatedTime } - return lbs[i].CreatedTime < lbs[j].CreatedTime + return lbs.Data[i].CreatedTime < lbs.Data[j].CreatedTime }) return lbs @@ -25,16 +25,16 @@ func (lbs ListBasicServices) SortByCreatedTime(inverse bool) ListBasicServices { // // If inverse param is set to true, the order is reversed. func (lbs ListBasicServices) SortByUpdatedTime(inverse bool) ListBasicServices { - if len(lbs) < 2 { + if lbs.EntryCount < 2 { return lbs } - sort.Slice(lbs, func(i, j int) bool { + sort.Slice(lbs.Data, func(i, j int) bool { if inverse { - return lbs[i].UpdatedTime > lbs[j].UpdatedTime + return lbs.Data[i].UpdatedTime > lbs.Data[j].UpdatedTime } - return lbs[i].UpdatedTime < lbs[j].UpdatedTime + return lbs.Data[i].UpdatedTime < lbs.Data[j].UpdatedTime }) return lbs @@ -44,16 +44,16 @@ func (lbs ListBasicServices) SortByUpdatedTime(inverse bool) ListBasicServices { // // If inverse param is set to true, the order is reversed. func (lbs ListBasicServices) SortByDeletedTime(inverse bool) ListBasicServices { - if len(lbs) < 2 { + if lbs.EntryCount < 2 { return lbs } - sort.Slice(lbs, func(i, j int) bool { + sort.Slice(lbs.Data, func(i, j int) bool { if inverse { - return lbs[i].DeletedTime > lbs[j].DeletedTime + return lbs.Data[i].DeletedTime > lbs.Data[j].DeletedTime } - return lbs[i].DeletedTime < lbs[j].DeletedTime + return lbs.Data[i].DeletedTime < lbs.Data[j].DeletedTime }) return lbs diff --git a/pkg/cloudapi/compute/filter.go b/pkg/cloudapi/compute/filter.go index 881f0c8..eb05e5d 100644 --- a/pkg/cloudapi/compute/filter.go +++ b/pkg/cloudapi/compute/filter.go @@ -59,7 +59,7 @@ func (lc ListComputes) FilterByDiskID(diskID uint64) ListComputes { } // FilterByK8SID returns master and worker nodes (ListComputes) inside specified K8S cluster. -func (lc ListComputes) FilterByK8SID(ctx context.Context, k8sID uint64, decortClient interfaces.Caller) (ListComputes, error) { +func (lc ListComputes) FilterByK8SID(ctx context.Context, k8sID uint64, decortClient interfaces.Caller) (*ListComputes, error) { caller := k8s.New(decortClient) req := k8s.GetRequest{ @@ -89,7 +89,9 @@ func (lc ListComputes) FilterByK8SID(ctx context.Context, k8sID uint64, decortCl return false } - return lc.FilterFunc(predicate), nil + res := lc.FilterFunc(predicate) + + return &res, nil } // K8SMasters is used to filter master nodes. Best used after FilterByK8SID function. @@ -121,7 +123,7 @@ func (lc ListComputes) FilterByK8SWorkers() ListComputes { } // FilterByLBID returns ListComputes used by specified Load Balancer. -func (lc ListComputes) FilterByLBID(ctx context.Context, lbID uint64, decortClient interfaces.Caller) (ListComputes, error) { +func (lc ListComputes) FilterByLBID(ctx context.Context, lbID uint64, decortClient interfaces.Caller) (*ListComputes, error) { caller := lb.New(decortClient) req := lb.GetRequest{ @@ -137,28 +139,32 @@ func (lc ListComputes) FilterByLBID(ctx context.Context, lbID uint64, decortClie return ic.ID == foundLB.PrimaryNode.ComputeID || ic.ID == foundLB.SecondaryNode.ComputeID } - return lc.FilterFunc(predicate), nil + res := lc.FilterFunc(predicate) + + return &res, nil } // FilterFunc allows filtering ListComputes based on a user-specified predicate. func (lc ListComputes) FilterFunc(predicate func(ItemCompute) bool) ListComputes { var result ListComputes - for _, item := range lc { + for _, item := range lc.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 ItemCompute // If none was found, returns an empty struct. func (lc ListComputes) FindOne() ItemCompute { - if len(lc) == 0 { + if len(lc.Data) == 0 { return ItemCompute{} } - return lc[0] + return lc.Data[0] } diff --git a/pkg/cloudapi/compute/filter_test.go b/pkg/cloudapi/compute/filter_test.go index fb6a9d0..7f2c1fe 100644 --- a/pkg/cloudapi/compute/filter_test.go +++ b/pkg/cloudapi/compute/filter_test.go @@ -3,150 +3,153 @@ package compute import "testing" var computes = ListComputes{ - ItemCompute{ - ACL: ListACL{}, - AccountID: 132847, - AccountName: "std_2", - AffinityLabel: "", - AffinityRules: []ItemRule{ - { - GUID: "", - Key: "aff_key", - Mode: "ANY", - Policy: "RECOMMENDED", - Topology: "compute", - Value: "aff_val", + Data: []ItemCompute{ + { + ACL: ListACL{}, + AccountID: 132847, + AccountName: "std_2", + AffinityLabel: "", + AffinityRules: []ItemRule{ + { + GUID: "", + Key: "aff_key", + Mode: "ANY", + Policy: "RECOMMENDED", + Topology: "compute", + Value: "aff_val", + }, }, - }, - AffinityWeight: 0, - AntiAffinityRules: []ItemRule{ - { - GUID: "", - Key: "antiaff_key", - Mode: "ANY", - Policy: "RECOMMENDED", - Topology: "compute", - Value: "antiaff_val", + AffinityWeight: 0, + AntiAffinityRules: []ItemRule{ + { + GUID: "", + Key: "antiaff_key", + Mode: "ANY", + Policy: "RECOMMENDED", + Topology: "compute", + Value: "antiaff_val", + }, }, - }, - Architecture: "X86_64", - BootOrder: []string{ - "hd", "cdrom", - }, - BootDiskSize: 0, - CloneReference: 0, - Clones: []uint64{}, - ComputeCIID: 0, - CPU: 4, - CreatedBy: "timofey_tkachev_1@decs3o", - CreatedTime: 1676975175, - CustomFields: map[string]interface{}{}, - DeletedBy: "", - DeletedTime: 0, - Description: "", - Devices: nil, - Disks: []InfoDisk{ - { - ID: 65191, - PCISlot: 6, + Architecture: "X86_64", + BootOrder: []string{ + "hd", "cdrom", }, + BootDiskSize: 0, + CloneReference: 0, + Clones: []uint64{}, + ComputeCIID: 0, + CPU: 4, + CreatedBy: "timofey_tkachev_1@decs3o", + CreatedTime: 1676975175, + CustomFields: map[string]interface{}{}, + DeletedBy: "", + DeletedTime: 0, + Description: "", + Devices: nil, + Disks: []InfoDisk{ + { + ID: 65191, + PCISlot: 6, + }, + }, + Driver: "KVM_X86", + GID: 212, + GUID: 48500, + ID: 48500, + ImageID: 9884, + Interfaces: []ItemVNFInterface{}, + LockStatus: "UNLOCKED", + ManagerID: 0, + ManagerType: "", + MigrationJob: 0, + Milestones: 363500, + Name: "test", + Pinned: false, + RAM: 4096, + ReferenceID: "c7cb19ac-af4a-4067-852f-c5572949207e", + Registered: true, + ResName: "compute-48500", + RGID: 79724, + RGName: "std_broker2", + SnapSets: []ItemSnapSet{}, + StatelessSepID: 0, + StatelessSepType: "", + Status: "ENABLED", + Tags: map[string]string{}, + TechStatus: "STOPPED", + TotalDiskSize: 2, + UpdatedBy: "", + UpdatedTime: 1677058904, + UserManaged: true, + VGPUs: []uint64{}, + VINSConnected: 0, + VirtualImageID: 0, }, - Driver: "KVM_X86", - GID: 212, - GUID: 48500, - ID: 48500, - ImageID: 9884, - Interfaces: []ItemVNFInterface{}, - LockStatus: "UNLOCKED", - ManagerID: 0, - ManagerType: "", - MigrationJob: 0, - Milestones: 363500, - Name: "test", - Pinned: false, - RAM: 4096, - ReferenceID: "c7cb19ac-af4a-4067-852f-c5572949207e", - Registered: true, - ResName: "compute-48500", - RGID: 79724, - RGName: "std_broker2", - SnapSets: []ItemSnapSet{}, - StatelessSepID: 0, - StatelessSepType: "", - Status: "ENABLED", - Tags: map[string]string{}, - TechStatus: "STOPPED", - TotalDiskSize: 2, - UpdatedBy: "", - UpdatedTime: 1677058904, - UserManaged: true, - VGPUs: []uint64{}, - VINSConnected: 0, - VirtualImageID: 0, - }, - ItemCompute{ - ACL: ListACL{}, - AccountID: 132848, - AccountName: "std_broker", - AffinityLabel: "", - AffinityRules: []ItemRule{}, - AffinityWeight: 0, - AntiAffinityRules: []ItemRule{}, - Architecture: "X86_64", - BootOrder: []string{ - "hd", "cdrom", - }, - BootDiskSize: 0, - CloneReference: 0, - Clones: []uint64{}, - ComputeCIID: 0, - CPU: 6, - CreatedBy: "timofey_tkachev_1@decs3o", - CreatedTime: 1677579436, - CustomFields: map[string]interface{}{}, - DeletedBy: "", - DeletedTime: 0, - Description: "", - Devices: nil, - Disks: []InfoDisk{ - { - ID: 65248, - PCISlot: 6, + { + ACL: ListACL{}, + AccountID: 132848, + AccountName: "std_broker", + AffinityLabel: "", + AffinityRules: []ItemRule{}, + AffinityWeight: 0, + AntiAffinityRules: []ItemRule{}, + Architecture: "X86_64", + BootOrder: []string{ + "hd", "cdrom", + }, + BootDiskSize: 0, + CloneReference: 0, + Clones: []uint64{}, + ComputeCIID: 0, + CPU: 6, + CreatedBy: "timofey_tkachev_1@decs3o", + CreatedTime: 1677579436, + CustomFields: map[string]interface{}{}, + DeletedBy: "", + DeletedTime: 0, + Description: "", + Devices: nil, + Disks: []InfoDisk{ + { + ID: 65248, + PCISlot: 6, + }, }, + Driver: "KVM_X86", + GID: 212, + GUID: 48556, + ID: 48556, + ImageID: 9884, + Interfaces: []ItemVNFInterface{}, + LockStatus: "UNLOCKED", + ManagerID: 0, + ManagerType: "", + MigrationJob: 0, + Milestones: 363853, + Name: "compute_2", + Pinned: false, + RAM: 4096, + ReferenceID: "a542c449-5b1c-4f90-88c5-7bb5f8ae68ff", + Registered: true, + ResName: "compute-48556", + RGID: 79727, + RGName: "sdk_negative_fields_test", + SnapSets: []ItemSnapSet{}, + StatelessSepID: 0, + StatelessSepType: "", + Status: "ENABLED", + Tags: map[string]string{}, + TechStatus: "STARTED", + TotalDiskSize: 1, + UpdatedBy: "", + UpdatedTime: 1677579436, + UserManaged: true, + VGPUs: []uint64{}, + VINSConnected: 0, + VirtualImageID: 0, }, - Driver: "KVM_X86", - GID: 212, - GUID: 48556, - ID: 48556, - ImageID: 9884, - Interfaces: []ItemVNFInterface{}, - LockStatus: "UNLOCKED", - ManagerID: 0, - ManagerType: "", - MigrationJob: 0, - Milestones: 363853, - Name: "compute_2", - Pinned: false, - RAM: 4096, - ReferenceID: "a542c449-5b1c-4f90-88c5-7bb5f8ae68ff", - Registered: true, - ResName: "compute-48556", - RGID: 79727, - RGName: "sdk_negative_fields_test", - SnapSets: []ItemSnapSet{}, - StatelessSepID: 0, - StatelessSepType: "", - Status: "ENABLED", - Tags: map[string]string{}, - TechStatus: "STARTED", - TotalDiskSize: 1, - UpdatedBy: "", - UpdatedTime: 1677579436, - UserManaged: true, - VGPUs: []uint64{}, - VINSConnected: 0, - VirtualImageID: 0, }, + EntryCount: 2, } func TestFilterByID(t *testing.T) { @@ -158,8 +161,8 @@ func TestFilterByID(t *testing.T) { actualEmpty := computes.FilterByID(0) - if len(actualEmpty) != 0 { - t.Fatal("expected empty, actual: ", len(actualEmpty)) + if len(actualEmpty.Data) != 0 { + t.Fatal("expected empty, actual: ", len(actualEmpty.Data)) } } @@ -174,7 +177,7 @@ func TestFilterByName(t *testing.T) { func TestFilterByStatus(t *testing.T) { actual := computes.FilterByStatus("ENABLED") - for _, item := range actual { + for _, item := range actual.Data { if item.Status != "ENABLED" { t.Fatal("expected ENABLED status, found: ", item.Status) } @@ -202,11 +205,11 @@ func TestFilterFunc(t *testing.T) { return ic.Registered == true }) - if len(actual) != 2 { - t.Fatal("expected 2 elements found, actual: ", len(actual)) + if len(actual.Data) != 2 { + t.Fatal("expected 2 elements found, actual: ", len(actual.Data)) } - for _, item := range actual { + for _, item := range actual.Data { if item.Registered != true { t.Fatal("expected Registered to be true, actual: ", item.Registered) } @@ -216,26 +219,26 @@ func TestFilterFunc(t *testing.T) { func TestSortingByCreatedTime(t *testing.T) { actual := computes.SortByCreatedTime(false) - if actual[0].Name != "test" { - t.Fatal("expected 'test', found: ", actual[0].Name) + if actual.Data[0].Name != "test" { + t.Fatal("expected 'test', found: ", actual.Data[0].Name) } actual = computes.SortByCreatedTime(true) - if actual[0].Name != "compute_2" { - t.Fatal("expected 'compute_2', found: ", actual[0].Name) + if actual.Data[0].Name != "compute_2" { + t.Fatal("expected 'compute_2', found: ", actual.Data[0].Name) } } func TestSortingByCPU(t *testing.T) { actual := computes.SortByCPU(false) - if actual[0].CPU != 4 { - t.Fatal("expected 4 CPU cores, found: ", actual[0].CPU) + if actual.Data[0].CPU != 4 { + t.Fatal("expected 4 CPU cores, found: ", actual.Data[0].CPU) } actual = computes.SortByCPU(true) - if actual[0].CPU != 6 { - t.Fatal("expected 6 CPU cores, found: ", actual[0].CPU) + if actual.Data[0].CPU != 6 { + t.Fatal("expected 6 CPU cores, found: ", actual.Data[0].CPU) } } diff --git a/pkg/cloudapi/compute/list.go b/pkg/cloudapi/compute/list.go index a5b2918..b86f3bd 100644 --- a/pkg/cloudapi/compute/list.go +++ b/pkg/cloudapi/compute/list.go @@ -8,6 +8,46 @@ import ( // Request struct for get list available computes 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 account ID + // Required: false + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + + // Find by resource group name + // Required: false + RGName string `url:"rgName,omitempty" json:"rgName,omitempty"` + + // Find by resource group ID + // Required: false + RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"` + + // Find by tech status + // Required: false + TechStatus string `url:"techStatus,omitempty" json:"techStatus,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Find by IP address + // Required: false + IPAddress string `url:"ipAddress,omitempty" json:"ipAddress,omitempty"` + + // Find by external network name + // Required: false + ExtNetName string `url:"extNetName,omitempty" json:"extNetName,omitempty"` + + // Find by external network ID + // Required: false + ExtNetID uint64 `url:"extNetId,omitempty" json:"extNetId,omitempty"` + // Include deleted computes // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` @@ -23,7 +63,7 @@ type ListRequest struct { // List gets list of the available computes. // Filtering based on status is possible -func (c Compute) List(ctx context.Context, req ListRequest) (ListComputes, error) { +func (c Compute) List(ctx context.Context, req ListRequest) (*ListComputes, error) { url := "/cloudapi/compute/list" res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -38,5 +78,5 @@ func (c Compute) List(ctx context.Context, req ListRequest) (ListComputes, error return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/compute/list_deleted.go b/pkg/cloudapi/compute/list_deleted.go index 7a90f37..8213504 100644 --- a/pkg/cloudapi/compute/list_deleted.go +++ b/pkg/cloudapi/compute/list_deleted.go @@ -18,7 +18,7 @@ type ListDeletedRequest struct { } // ListDeleted gets list all deleted computes -func (c Compute) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListComputes, error) { +func (c Compute) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListComputes, error) { url := "/cloudapi/compute/listDeleted" res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -33,5 +33,5 @@ func (c Compute) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListC return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/compute/models.go b/pkg/cloudapi/compute/models.go index e9d5230..9088690 100644 --- a/pkg/cloudapi/compute/models.go +++ b/pkg/cloudapi/compute/models.go @@ -673,6 +673,9 @@ type SnapshotExtend struct { // Label Label string `json:"label"` + // Reference ID + ReferenceID string `json:"referenceId"` + // Resource ID ResID string `json:"resId"` @@ -905,4 +908,10 @@ type InfoDisk struct { } // List information about computes -type ListComputes []ItemCompute +type ListComputes struct { + // Data + Data []ItemCompute `json:"data"` + + // Entry count + EntryCount uint64 `json:"entryCount"` +} diff --git a/pkg/cloudapi/compute/resize.go b/pkg/cloudapi/compute/resize.go index 76fe53b..302ecc2 100644 --- a/pkg/cloudapi/compute/resize.go +++ b/pkg/cloudapi/compute/resize.go @@ -17,16 +17,16 @@ type ResizeRequest struct { // New CPU count. // Pass 0 if no change to CPU count is required // Required: false - Force bool `url:"force,omitempty" json:"force,omitempty"` + CPU uint64 `url:"cpu,omitempty" json:"cpu,omitempty"` // New RAM volume in MB. // Pass 0 if no change to RAM volume is required // Required: false - CPU uint64 `url:"cpu,omitempty" json:"cpu,omitempty"` + RAM uint64 `url:"ram,omitempty" json:"ram,omitempty"` // Force compute resize // Required: false - RAM uint64 `url:"ram,omitempty" json:"ram,omitempty"` + Force bool `url:"force,omitempty" json:"force,omitempty"` } // Resize resize compute instance diff --git a/pkg/cloudapi/compute/serialize.go b/pkg/cloudapi/compute/serialize.go index 31af2f2..1de6bc5 100644 --- a/pkg/cloudapi/compute/serialize.go +++ b/pkg/cloudapi/compute/serialize.go @@ -12,7 +12,7 @@ import ( // - First argument -> prefix // - Second argument -> indent func (lc ListComputes) Serialize(params ...string) (serialization.Serialized, error) { - if len(lc) == 0 { + if lc.EntryCount == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/compute/sorting.go b/pkg/cloudapi/compute/sorting.go index 248407b..648ecbc 100644 --- a/pkg/cloudapi/compute/sorting.go +++ b/pkg/cloudapi/compute/sorting.go @@ -6,16 +6,16 @@ import "sort" // // If inverse param is set to true, the order is reversed. func (lc ListComputes) SortByCPU(inverse bool) ListComputes { - if len(lc) < 2 { + if len(lc.Data) < 2 { return lc } - sort.Slice(lc, func(i, j int) bool { + sort.Slice(lc.Data, func(i, j int) bool { if inverse { - return lc[i].CPU > lc[j].CPU + return lc.Data[i].CPU > lc.Data[j].CPU } - return lc[i].CPU < lc[j].CPU + return lc.Data[i].CPU < lc.Data[j].CPU }) return lc @@ -25,16 +25,16 @@ func (lc ListComputes) SortByCPU(inverse bool) ListComputes { // // If inverse param is set to true, the order is reversed. func (lc ListComputes) SortByRAM(inverse bool) ListComputes { - if len(lc) < 2 { + if len(lc.Data) < 2 { return lc } - sort.Slice(lc, func(i, j int) bool { + sort.Slice(lc.Data, func(i, j int) bool { if inverse { - return lc[i].RAM > lc[j].RAM + return lc.Data[i].RAM > lc.Data[j].RAM } - return lc[i].RAM < lc[j].RAM + return lc.Data[i].RAM < lc.Data[j].RAM }) return lc @@ -44,16 +44,16 @@ func (lc ListComputes) SortByRAM(inverse bool) ListComputes { // // If inverse param is set to true, the order is reversed. func (lc ListComputes) SortByCreatedTime(inverse bool) ListComputes { - if len(lc) < 2 { + if len(lc.Data) < 2 { return lc } - sort.Slice(lc, func(i, j int) bool { + sort.Slice(lc.Data, func(i, j int) bool { if inverse { - return lc[i].CreatedTime > lc[j].CreatedTime + return lc.Data[i].CreatedTime > lc.Data[j].CreatedTime } - return lc[i].CreatedTime < lc[j].CreatedTime + return lc.Data[i].CreatedTime < lc.Data[j].CreatedTime }) return lc @@ -63,16 +63,16 @@ func (lc ListComputes) SortByCreatedTime(inverse bool) ListComputes { // // If inverse param is set to true, the order is reversed. func (lc ListComputes) SortByUpdatedTime(inverse bool) ListComputes { - if len(lc) < 2 { + if len(lc.Data) < 2 { return lc } - sort.Slice(lc, func(i, j int) bool { + sort.Slice(lc.Data, func(i, j int) bool { if inverse { - return lc[i].UpdatedTime > lc[j].UpdatedTime + return lc.Data[i].UpdatedTime > lc.Data[j].UpdatedTime } - return lc[i].UpdatedTime < lc[j].UpdatedTime + return lc.Data[i].UpdatedTime < lc.Data[j].UpdatedTime }) return lc @@ -82,16 +82,16 @@ func (lc ListComputes) SortByUpdatedTime(inverse bool) ListComputes { // // If inverse param is set to true, the order is reversed. func (lc ListComputes) SortByDeletedTime(inverse bool) ListComputes { - if len(lc) < 2 { + if len(lc.Data) < 2 { return lc } - sort.Slice(lc, func(i, j int) bool { + sort.Slice(lc.Data, func(i, j int) bool { if inverse { - return lc[i].DeletedTime > lc[j].DeletedTime + return lc.Data[i].DeletedTime > lc.Data[j].DeletedTime } - return lc[i].DeletedTime < lc[j].DeletedTime + return lc.Data[i].DeletedTime < lc.Data[j].DeletedTime }) return lc diff --git a/pkg/cloudapi/computeci/filter.go b/pkg/cloudapi/computeci/filter.go index ebbf697..3b28f3f 100644 --- a/pkg/cloudapi/computeci/filter.go +++ b/pkg/cloudapi/computeci/filter.go @@ -31,21 +31,23 @@ func (lci ListComputeCI) FilterByStatus(status string) ListComputeCI { func (lci ListComputeCI) FilterFunc(predicate func(ItemComputeCI) bool) ListComputeCI { var result ListComputeCI - for _, item := range lci { + for _, item := range lci.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 ItemComputeCI // If none was found, returns an empty struct. func (lci ListComputeCI) FindOne() ItemComputeCI { - if len(lci) == 0 { + if lci.EntryCount == 0 { return ItemComputeCI{} } - return lci[0] + return lci.Data[0] } diff --git a/pkg/cloudapi/computeci/filter_test.go b/pkg/cloudapi/computeci/filter_test.go index 804d228..4feb955 100644 --- a/pkg/cloudapi/computeci/filter_test.go +++ b/pkg/cloudapi/computeci/filter_test.go @@ -3,42 +3,45 @@ package computeci import "testing" var computeciItems = ListComputeCI{ - { - CustomFields: map[string]interface{}{}, - Description: "", - Drivers: []string{ - "KVM_X86", + Data: []ItemComputeCI{ + { + CustomFields: map[string]interface{}{}, + Description: "", + Drivers: []string{ + "KVM_X86", + }, + GUID: 1, + ID: 1, + Name: "computeci_1", + Status: "ENABLED", + Template: "", }, - GUID: 1, - ID: 1, - Name: "computeci_1", - Status: "ENABLED", - Template: "", - }, - { - CustomFields: map[string]interface{}{}, - Description: "", - Drivers: []string{ - "KVM_X86", + { + CustomFields: map[string]interface{}{}, + Description: "", + Drivers: []string{ + "KVM_X86", + }, + GUID: 2, + ID: 2, + Name: "computeci_2", + Status: "ENABLED", + Template: "", }, - GUID: 2, - ID: 2, - Name: "computeci_2", - Status: "ENABLED", - Template: "", - }, - { - CustomFields: map[string]interface{}{}, - Description: "", - Drivers: []string{ - "SVA_KVM_X86", + { + CustomFields: map[string]interface{}{}, + Description: "", + Drivers: []string{ + "SVA_KVM_X86", + }, + GUID: 3, + ID: 3, + Name: "computeci_3", + Status: "DISABLED", + Template: "", }, - GUID: 3, - ID: 3, - Name: "computeci_3", - Status: "DISABLED", - Template: "", }, + EntryCount: 3, } func TestFilterByID(t *testing.T) { @@ -60,11 +63,11 @@ func TestFilterByName(t *testing.T) { func TestFilterByStatus(t *testing.T) { actual := computeciItems.FilterByStatus("ENABLED") - 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.Status != "ENABLED" { t.Fatal("expected Status 'ENABLED', found: ", item.Status) } @@ -81,11 +84,11 @@ func TestFilterFunc(t *testing.T) { return false }) - 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 { for _, driver := range item.Drivers { if driver != "KVM_X86" { t.Fatal("expected 'KVM_X86' Driver, found: ", driver) diff --git a/pkg/cloudapi/computeci/list.go b/pkg/cloudapi/computeci/list.go index e248803..26a7f2b 100644 --- a/pkg/cloudapi/computeci/list.go +++ b/pkg/cloudapi/computeci/list.go @@ -8,6 +8,18 @@ import ( // Request struct for get list of computeci type ListRequest struct { + // Find by name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Find by computeci ID + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Find by drivers + // Find by computeci ID + Drivers []string `url:"drivers,omitempty" json:"drivers,omitempty"` + // If true list deleted instances as well // Required: false IncludeDeleted bool `url:"includeDeleted,omitempty" json:"includeDeleted,omitempty"` @@ -22,7 +34,7 @@ type ListRequest struct { } // List gets list of computeci instances -func (c ComputeCI) List(ctx context.Context, req ListRequest) (ListComputeCI, error) { +func (c ComputeCI) List(ctx context.Context, req ListRequest) (*ListComputeCI, error) { url := "/cloudapi/computeci/list" res, err := c.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -37,5 +49,5 @@ func (c ComputeCI) List(ctx context.Context, req ListRequest) (ListComputeCI, er return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/computeci/models.go b/pkg/cloudapi/computeci/models.go index 802e803..f8b5382 100644 --- a/pkg/cloudapi/computeci/models.go +++ b/pkg/cloudapi/computeci/models.go @@ -28,4 +28,8 @@ type ItemComputeCI struct { } // List of computeci instances -type ListComputeCI []ItemComputeCI +type ListComputeCI struct { + Data []ItemComputeCI `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} diff --git a/pkg/cloudapi/computeci/serialize.go b/pkg/cloudapi/computeci/serialize.go index d7621eb..fb38de3 100644 --- a/pkg/cloudapi/computeci/serialize.go +++ b/pkg/cloudapi/computeci/serialize.go @@ -12,7 +12,7 @@ import ( // - First argument -> prefix // - Second argument -> indent func (lci ListComputeCI) Serialize(params ...string) (serialization.Serialized, error) { - if len(lci) == 0 { + if lci.EntryCount == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/disks/filter.go b/pkg/cloudapi/disks/filter.go index 8e568f8..ec15a4d 100644 --- a/pkg/cloudapi/disks/filter.go +++ b/pkg/cloudapi/disks/filter.go @@ -61,7 +61,7 @@ func (ld ListDisks) FilterByComputeID(computeID uint64) ListDisks { } // FilterByK8SID is used to filter ListDisks by specified K8S cluster. -func (ld ListDisks) FilterByK8SID(ctx context.Context, k8sID uint64, decortClient interfaces.Caller) (ListDisks, error) { +func (ld ListDisks) FilterByK8SID(ctx context.Context, k8sID uint64, decortClient interfaces.Caller) (*ListDisks, error) { caller := k8s.New(decortClient) req := k8s.GetRequest{ @@ -75,6 +75,134 @@ func (ld ListDisks) FilterByK8SID(ctx context.Context, k8sID uint64, decortClien var result ListDisks + for _, masterCompute := range cluster.K8SGroups.Masters.DetailedInfo { + result.Data = append(result.Data, ld.FilterByComputeID(masterCompute.ID).Data...) + } + + for _, workerGroup := range cluster.K8SGroups.Workers { + for _, workerCompute := range workerGroup.DetailedInfo { + result.Data = append(result.Data, ld.FilterByComputeID(workerCompute.ID).Data...) + } + } + + result.EntryCount = uint64(len(result.Data)) + + return &result, nil +} + +// FilterByLBID is used to filter ListDisks used by computes inside specified Load Balancer. +func (ld ListDisks) FilterByLBID(ctx context.Context, lbID uint64, decortClient interfaces.Caller) (*ListDisks, error) { + caller := lb.New(decortClient) + + req := lb.GetRequest{ + LBID: lbID, + } + + foundLB, err := caller.Get(ctx, req) + if err != nil { + return nil, err + } + + var result ListDisks + result.Data = append(result.Data, ld.FilterByComputeID(foundLB.PrimaryNode.ComputeID).Data...) + result.Data = append(result.Data, ld.FilterByComputeID(foundLB.SecondaryNode.ComputeID).Data...) + + result.EntryCount = uint64(len(result.Data)) + + return &result, nil +} + +// FilterFunc allows filtering ListDisks based on a user-specified predicate. +func (ld ListDisks) FilterFunc(predicate func(ItemDisk) bool) ListDisks { + var result ListDisks + + for _, item := range ld.Data { + if predicate(item) { + result.Data = append(result.Data, item) + } + } + + result.EntryCount = uint64(len(result.Data)) + + return result +} + +// FindOne returns first found ItemDisk +// If none was found, returns an empty struct. +func (ld ListDisks) FindOne() ItemDisk { + if len(ld.Data) == 0 { + return ItemDisk{} + } + + return ld.Data[0] +} + +// FilterByID returns ListSearchDisks with specified ID. +func (ld ListSearchDisks) FilterByID(id uint64) ListSearchDisks { + predicate := func(idisk ItemDisk) bool { + return idisk.ID == id + } + + return ld.FilterFunc(predicate) +} + +// FilterByName returns ListSearchDisks with specified Name. +func (ld ListSearchDisks) FilterByName(name string) ListSearchDisks { + predicate := func(idisk ItemDisk) bool { + return idisk.Name == name + } + + return ld.FilterFunc(predicate) +} + +// FilterByStatus returns ListSearchDisks with specified Status. +func (ld ListSearchDisks) FilterByStatus(status string) ListSearchDisks { + predicate := func(idisk ItemDisk) bool { + return idisk.Status == status + } + + return ld.FilterFunc(predicate) +} + +// FilterByTechStatus returns ListSearchDisks with specified TechStatus. +func (ld ListSearchDisks) FilterByTechStatus(techStatus string) ListSearchDisks { + predicate := func(idisk ItemDisk) bool { + return idisk.TechStatus == techStatus + } + + return ld.FilterFunc(predicate) +} + +// FilterByComputeID is used to filter ListSearchDisks attached to specified compute. +func (ld ListSearchDisks) FilterByComputeID(computeID uint64) ListSearchDisks { + predicate := func(idisk ItemDisk) bool { + for k := range idisk.Computes { + if k == strconv.FormatUint(computeID, 10) { + return true + } + } + + return false + } + + return ld.FilterFunc(predicate) +} + +// FilterByK8SID is used to filter ListSearchDisks by specified K8S cluster. +func (ld ListSearchDisks) FilterByK8SID(ctx context.Context, k8sID uint64, decortClient interfaces.Caller) (ListSearchDisks, error) { + caller := k8s.New(decortClient) + + req := k8s.GetRequest{ + K8SID: k8sID, + } + + cluster, err := caller.Get(ctx, req) + if err != nil { + return nil, err + } + + var result ListSearchDisks + for _, masterCompute := range cluster.K8SGroups.Masters.DetailedInfo { result = append(result, ld.FilterByComputeID(masterCompute.ID)...) } @@ -88,8 +216,8 @@ func (ld ListDisks) FilterByK8SID(ctx context.Context, k8sID uint64, decortClien return result, nil } -// FilterByLBID is used to filter ListDisks used by computes inside specified Load Balancer. -func (ld ListDisks) FilterByLBID(ctx context.Context, lbID uint64, decortClient interfaces.Caller) (ListDisks, error) { +// FilterByLBID is used to filter ListSearchDisks used by computes inside specified Load Balancer. +func (ld ListSearchDisks) FilterByLBID(ctx context.Context, lbID uint64, decortClient interfaces.Caller) (ListSearchDisks, error) { caller := lb.New(decortClient) req := lb.GetRequest{ @@ -101,16 +229,16 @@ func (ld ListDisks) FilterByLBID(ctx context.Context, lbID uint64, decortClient return nil, err } - var result ListDisks + var result ListSearchDisks result = append(result, ld.FilterByComputeID(foundLB.PrimaryNode.ComputeID)...) result = append(result, ld.FilterByComputeID(foundLB.SecondaryNode.ComputeID)...) return result, nil } -// FilterFunc allows filtering ListDisks based on a user-specified predicate. -func (ld ListDisks) FilterFunc(predicate func(ItemDisk) bool) ListDisks { - var result ListDisks +// FilterFunc allows filtering ListSearchDisks based on a user-specified predicate. +func (ld ListSearchDisks) FilterFunc(predicate func(ItemDisk) bool) ListSearchDisks { + var result ListSearchDisks for _, item := range ld { if predicate(item) { @@ -123,7 +251,7 @@ func (ld ListDisks) FilterFunc(predicate func(ItemDisk) bool) ListDisks { // FindOne returns first found ItemDisk // If none was found, returns an empty struct. -func (ld ListDisks) FindOne() ItemDisk { +func (ld ListSearchDisks) FindOne() ItemDisk { if len(ld) == 0 { return ItemDisk{} } @@ -171,21 +299,23 @@ func (lu ListDisksUnattached) FilterByTechStatus(techStatus string) ListDisksUna func (lu ListDisksUnattached) FilterFunc(predicate func(ItemDiskUnattached) bool) ListDisksUnattached { var result ListDisksUnattached - for _, item := range lu { + for _, item := range lu.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 ItemDiskUnattached // If none was found, returns an empty struct. func (lu ListDisksUnattached) FindOne() ItemDiskUnattached { - if len(lu) == 0 { + if len(lu.Data) == 0 { return ItemDiskUnattached{} } - return lu[0] + return lu.Data[0] } diff --git a/pkg/cloudapi/disks/filter_test.go b/pkg/cloudapi/disks/filter_test.go index 3bd6462..8b72929 100644 --- a/pkg/cloudapi/disks/filter_test.go +++ b/pkg/cloudapi/disks/filter_test.go @@ -4,7 +4,186 @@ import ( "testing" ) +var techStatusAllocated = "ALLOCATED" + var disks = ListDisks{ + Data: []ItemDisk{ + { + MachineID: 0, + MachineName: "", + DeviceName: "vda", + AccountID: 132847, + AccountName: "std_2", + ACL: map[string]interface{}{}, + Computes: map[string]string{ + "48500": "test", + }, + CreatedTime: 1676975177, + DeletedTime: 0, + Description: "", + DestructionTime: 0, + GID: 212, + ID: 65191, + ImageID: 9884, + Images: []uint64{}, + IOTune: IOTune{ + TotalIOPSSec: 2000, + }, + Name: "bootdisk", + Order: 0, + Params: "", + ParentID: 0, + PCISlot: 6, + Pool: "vmstor", + PresentTo: []uint64{ + 27, + }, + PurgeTime: 0, + ResID: "sample", + ResName: "sample", + Role: "", + Shareable: false, + SizeMax: 2, + SizeUsed: 2, + Snapshots: []ItemSnapshot{}, + Status: "ASSIGNED", + TechStatus: techStatusAllocated, + Type: "B", + VMID: 48500, + }, + { + MachineID: 0, + MachineName: "", + DeviceName: "vda", + AccountID: 132852, + AccountName: "std", + ACL: map[string]interface{}{}, + Computes: map[string]string{ + "48502": "stdvm2", + }, + CreatedTime: 1676982606, + DeletedTime: 0, + Description: "", + DestructionTime: 0, + GID: 212, + ID: 65193, + ImageID: 9885, + Images: []uint64{}, + IOTune: IOTune{ + TotalIOPSSec: 2000, + }, + Name: "bootdisk", + Order: 0, + Params: "", + ParentID: 0, + PCISlot: 6, + Pool: "vmstor", + PresentTo: []uint64{ + 27, + 27, + }, + PurgeTime: 0, + ResID: "sample", + ResName: "sample", + Role: "", + Shareable: false, + SizeMax: 4, + SizeUsed: 4, + Snapshots: []ItemSnapshot{}, + Status: "ASSIGNED", + TechStatus: techStatusAllocated, + Type: "B", + VMID: 48502, + }, + }, + EntryCount: 2, +} + +func TestListDisks_FilterByID(t *testing.T) { + actual := disks.FilterByID(65193) + + if len(actual.Data) == 0 { + t.Fatal("No elements were found") + } + + actualItem := actual.FindOne() + + if actualItem.ID != 65193 { + t.Fatal("expected ID 65193, found: ", actualItem.ID) + } +} + +func TestListDisks_FilterByName(t *testing.T) { + actual := disks.FilterByName("bootdisk") + + if len(actual.Data) != 2 { + t.Fatal("expected 2 elements, found: ", len(actual.Data)) + } + + for _, item := range actual.Data { + if item.Name != "bootdisk" { + t.Fatal("expected 'bootdisk' name, found: ", item.Name) + } + } +} + +func TestListDisks_FilterByStatus(t *testing.T) { + actual := disks.FilterByStatus("ASSIGNED") + + if len(actual.Data) == 0 { + t.Fatal("No elements were found") + } + + for _, item := range actual.Data { + if item.Status != "ASSIGNED" { + t.Fatal("expected 'ASSIGNED' status, found: ", item.Status) + } + } +} + +func TestListDisks_FilterByTechStatus(t *testing.T) { + actual := disks.FilterByTechStatus(techStatusAllocated) + + if len(actual.Data) == 0 { + t.Fatal("No elements were found") + } + + for _, item := range actual.Data { + if item.TechStatus != techStatusAllocated { + t.Fatal("expected 'ALLOCATED' techStatus, found: ", item.TechStatus) + } + } +} + +func TestListDisks_FilterFunc(t *testing.T) { + actual := disks.FilterFunc(func(id ItemDisk) bool { + return len(id.PresentTo) == 2 + }) + + if len(actual.Data) == 0 { + t.Fatal("No elements were found") + } + + if len(actual.Data[0].PresentTo) != 2 { + t.Fatal("expected 2 elements in PresentTo, found: ", len(actual.Data[0].PresentTo)) + } +} + +func TestListDisks_SortByCreatedTime(t *testing.T) { + actual := disks.SortByCreatedTime(false) + + if actual.Data[0].ID != 65191 { + t.Fatal("expected ID 65191, found: ", actual.Data[0].ID) + } + + actual = disks.SortByCreatedTime(true) + + if actual.Data[0].ID != 65193 { + t.Fatal("expected ID 65193, found: ", actual.Data[0].ID) + } +} + +var searchDisks = ListSearchDisks{ ItemDisk{ MachineID: 0, MachineName: "", @@ -44,7 +223,7 @@ var disks = ListDisks{ SizeUsed: 2, Snapshots: []ItemSnapshot{}, Status: "ASSIGNED", - TechStatus: "ALLOCATED", + TechStatus: techStatusAllocated, Type: "B", VMID: 48500, }, @@ -88,14 +267,14 @@ var disks = ListDisks{ SizeUsed: 4, Snapshots: []ItemSnapshot{}, Status: "ASSIGNED", - TechStatus: "ALLOCATED", + TechStatus: techStatusAllocated, Type: "B", VMID: 48502, }, } -func TestFilterByID(t *testing.T) { - actual := disks.FilterByID(65193) +func TestListSearchDisks_FilterByID(t *testing.T) { + actual := searchDisks.FilterByID(65193) if len(actual) == 0 { t.Fatal("No elements were found") @@ -108,8 +287,8 @@ func TestFilterByID(t *testing.T) { } } -func TestFilterByName(t *testing.T) { - actual := disks.FilterByName("bootdisk") +func TestListSearchDisks_FilterByName(t *testing.T) { + actual := searchDisks.FilterByName("bootdisk") if len(actual) != 2 { t.Fatal("expected 2 elements, found: ", len(actual)) @@ -122,8 +301,8 @@ func TestFilterByName(t *testing.T) { } } -func TestFilterByStatus(t *testing.T) { - actual := disks.FilterByStatus("ASSIGNED") +func TestListSearchDisks_FilterByStatus(t *testing.T) { + actual := searchDisks.FilterByStatus("ASSIGNED") if len(actual) == 0 { t.Fatal("No elements were found") @@ -136,22 +315,22 @@ func TestFilterByStatus(t *testing.T) { } } -func TestFilterByTechStatus(t *testing.T) { - actual := disks.FilterByTechStatus("ALLOCATED") +func TestListSearchDisks_FilterByTechStatus(t *testing.T) { + actual := searchDisks.FilterByTechStatus(techStatusAllocated) if len(actual) == 0 { t.Fatal("No elements were found") } for _, item := range actual { - if item.TechStatus != "ALLOCATED" { + if item.TechStatus != techStatusAllocated { t.Fatal("expected 'ALLOCATED' techStatus, found: ", item.TechStatus) } } } -func TestFilterFunc(t *testing.T) { - actual := disks.FilterFunc(func(id ItemDisk) bool { +func TestListSearchDisks_FilterFunc(t *testing.T) { + actual := searchDisks.FilterFunc(func(id ItemDisk) bool { return len(id.PresentTo) == 2 }) @@ -164,14 +343,14 @@ func TestFilterFunc(t *testing.T) { } } -func TestSortByCreatedTime(t *testing.T) { - actual := disks.SortByCreatedTime(false) +func TestListSearchDisks_SortByCreatedTime(t *testing.T) { + actual := searchDisks.SortByCreatedTime(false) if actual[0].ID != 65191 { t.Fatal("expected ID 65191, found: ", actual[0].ID) } - actual = disks.SortByCreatedTime(true) + actual = searchDisks.SortByCreatedTime(true) if actual[0].ID != 65193 { t.Fatal("expected ID 65193, found: ", actual[0].ID) @@ -179,119 +358,122 @@ func TestSortByCreatedTime(t *testing.T) { } var unattachedDisks = ListDisksUnattached{ - { - CKey: "", - Meta: []interface{}{ - "cloudbroker", - "disk", - 1, + Data: []ItemDiskUnattached{ + { + 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: techStatusAllocated, + Type: "D", + VMID: 0, }, - 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, + { + 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: techStatusAllocated, + Type: "B", + VMID: 0, }, - 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, }, + EntryCount: 2, } func TestListDisksUnattached_FilterByID(t *testing.T) { actual := unattachedDisks.FilterByID(22636) - if len(actual) == 0 { + if len(actual.Data) == 0 { t.Fatal("No elements were found") } @@ -305,11 +487,11 @@ func TestListDisksUnattached_FilterByID(t *testing.T) { func TestListDisksUnattached_FilterByName(t *testing.T) { actual := unattachedDisks.FilterByName("test_disk") - if len(actual) != 2 { - t.Fatal("expected 2 elements, found: ", len(actual)) + if len(actual.Data) != 2 { + t.Fatal("expected 2 elements, found: ", len(actual.Data)) } - for _, item := range actual { + for _, item := range actual.Data { if item.Name != "test_disk" { t.Fatal("expected 'test_disk' name, found: ", item.Name) } @@ -319,11 +501,11 @@ func TestListDisksUnattached_FilterByName(t *testing.T) { func TestListDisksUnattached_FilterByStatus(t *testing.T) { actual := unattachedDisks.FilterByStatus("CREATED") - if len(actual) == 0 { + if len(actual.Data) == 0 { t.Fatal("No elements were found") } - for _, item := range actual { + for _, item := range actual.Data { if item.Status != "CREATED" { t.Fatal("expected 'CREATED' status, found: ", item.Status) } @@ -331,14 +513,14 @@ func TestListDisksUnattached_FilterByStatus(t *testing.T) { } func TestListDisksUnattached_FilterByTechStatus(t *testing.T) { - actual := unattachedDisks.FilterByTechStatus("ALLOCATED") + actual := unattachedDisks.FilterByTechStatus(techStatusAllocated) - if len(actual) == 0 { + if len(actual.Data) == 0 { t.Fatal("No elements were found") } - for _, item := range actual { - if item.TechStatus != "ALLOCATED" { + for _, item := range actual.Data { + if item.TechStatus != techStatusAllocated { t.Fatal("expected 'ALLOCATED' techStatus, found: ", item.TechStatus) } } @@ -349,26 +531,26 @@ func TestListDisksUnattached_FilterFunc(t *testing.T) { return len(id.PresentTo) == 2 }) - if len(actual) == 0 { + if len(actual.Data) == 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)) + if len(actual.Data[0].PresentTo) != 2 { + t.Fatal("expected 2 elements in PresentTo, found: ", len(actual.Data[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) + if actual.Data[0].ID != 22636 { + t.Fatal("expected ID 22636, found: ", actual.Data[0].ID) } actual = unattachedDisks.SortByCreatedTime(true) - if actual[0].ID != 22637 { - t.Fatal("expected ID 22637, found: ", actual[0].ID) + if actual.Data[0].ID != 22637 { + t.Fatal("expected ID 22637, found: ", actual.Data[0].ID) } } diff --git a/pkg/cloudapi/disks/list.go b/pkg/cloudapi/disks/list.go index d2b274b..a69ecdb 100644 --- a/pkg/cloudapi/disks/list.go +++ b/pkg/cloudapi/disks/list.go @@ -6,8 +6,32 @@ import ( "net/http" ) -// Request struct for get list/list_deleted of disks +// Request struct for get list of disks 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 account name + // Required: false + AccountName string `url:"accountName,omitempty" json:"accountName,omitempty"` + + // Find by max size disk + // Required: false + DiskMaxSize int64 `url:"diskMaxSize,omitempty" json:"diskMaxSize,omitempty"` + + // Find by status + // 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"` + // ID of the account the disks belong to // Required: false AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` @@ -26,7 +50,7 @@ type ListRequest struct { } // List gets list the created disks belonging to an account -func (d Disks) List(ctx context.Context, req ListRequest) (ListDisks, error) { +func (d Disks) List(ctx context.Context, req ListRequest) (*ListDisks, error) { url := "/cloudapi/disks/list" res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -41,24 +65,5 @@ func (d Disks) List(ctx context.Context, req ListRequest) (ListDisks, error) { return nil, err } - return list, nil -} - -// ListDeleted gets list the deleted disks belonging to an account -func (d Disks) ListDeleted(ctx context.Context, req ListRequest) (ListDisks, error) { - url := "/cloudapi/disks/listDeleted" - - res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) - if err != nil { - return nil, err - } - - list := ListDisks{} - - err = json.Unmarshal(res, &list) - if err != nil { - return nil, err - } - - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/disks/list_deleted.go b/pkg/cloudapi/disks/list_deleted.go new file mode 100644 index 0000000..fab8868 --- /dev/null +++ b/pkg/cloudapi/disks/list_deleted.go @@ -0,0 +1,45 @@ +package disks + +import ( + "context" + "encoding/json" + "net/http" +) + +// Request struct for get list of deleted disks +type ListDeletedRequest struct { + // ID of the account the disks belong to + // Required: false + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + + // Type of the disks + // 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"` +} + +// ListDeleted gets list the deleted disks belonging to an account +func (d Disks) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListDisks, error) { + url := "/cloudapi/disks/listDeleted" + + res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + list := ListDisks{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} diff --git a/pkg/cloudapi/disks/list_unattached.go b/pkg/cloudapi/disks/list_unattached.go index 47ca667..92aed08 100644 --- a/pkg/cloudapi/disks/list_unattached.go +++ b/pkg/cloudapi/disks/list_unattached.go @@ -8,13 +8,45 @@ import ( // Request struct for get list unattached disk type ListUnattachedRequest struct { + // Find by id + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Find by account name + // Required: false + AccountName string `url:"accountName,omitempty" json:"accountName,omitempty"` + + // Find by max size disk + // Required: false + DiskMaxSize int64 `url:"diskMaxSize,omitempty" json:"diskMaxSize,omitempty"` + + // Find by status + // 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"` + // ID of the account // Required: false AccountID uint64 `url:"accountId,omitempty" json:"accountId,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"` } // ListUnattached gets list of unattached disks -func (d Disks) ListUnattached(ctx context.Context, req ListUnattachedRequest) (ListDisksUnattached, 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) @@ -29,5 +61,5 @@ func (d Disks) ListUnattached(ctx context.Context, req ListUnattachedRequest) (L return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/disks/models.go b/pkg/cloudapi/disks/models.go index 1c84e4c..79f7d56 100644 --- a/pkg/cloudapi/disks/models.go +++ b/pkg/cloudapi/disks/models.go @@ -248,11 +248,24 @@ type ItemDiskUnattached struct { VMID uint64 `json:"vmid"` } +// List of disks searched +type ListSearchDisks []ItemDisk + // List of disks -type ListDisks []ItemDisk +type ListDisks struct { + // Data + Data []ItemDisk `json:"data"` + + // Entry count + EntryCount uint64 `json:"entryCount"` +} // List of unattached disks -type ListDisksUnattached []ItemDiskUnattached +type ListDisksUnattached struct { + Data []ItemDiskUnattached `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} // Main information about snapshot type ItemSnapshot struct { @@ -262,6 +275,8 @@ type ItemSnapshot struct { // Label Label string `json:"label"` + ReferenceID string `json:"referenceId"` + // Resource ID ResID string `json:"resId"` diff --git a/pkg/cloudapi/disks/search.go b/pkg/cloudapi/disks/search.go index d5b61de..72ef725 100644 --- a/pkg/cloudapi/disks/search.go +++ b/pkg/cloudapi/disks/search.go @@ -21,7 +21,7 @@ type SearchRequest struct { } // Search search disks -func (d Disks) Search(ctx context.Context, req SearchRequest) (ListDisks, error) { +func (d Disks) Search(ctx context.Context, req SearchRequest) (ListSearchDisks, error) { url := "/cloudapi/disks/search" res, err := d.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -29,7 +29,7 @@ func (d Disks) Search(ctx context.Context, req SearchRequest) (ListDisks, error) return nil, err } - list := ListDisks{} + list := ListSearchDisks{} err = json.Unmarshal(res, &list) if err != nil { diff --git a/pkg/cloudapi/disks/serialize.go b/pkg/cloudapi/disks/serialize.go index cf4ae08..7bc9287 100644 --- a/pkg/cloudapi/disks/serialize.go +++ b/pkg/cloudapi/disks/serialize.go @@ -12,6 +12,26 @@ import ( // - First argument -> prefix // - Second argument -> indent func (ld ListDisks) Serialize(params ...string) (serialization.Serialized, error) { + if ld.EntryCount == 0 { + return []byte{}, nil + } + + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(ld, prefix, indent) + } + + return json.Marshal(ld) +} + +// 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 (ld ListSearchDisks) Serialize(params ...string) (serialization.Serialized, error) { if len(ld) == 0 { return []byte{}, nil } @@ -48,7 +68,7 @@ func (idisk ItemDisk) Serialize(params ...string) (serialization.Serialized, err // - First argument -> prefix // - Second argument -> indent func (lu ListDisksUnattached) Serialize(params ...string) (serialization.Serialized, error) { - if len(lu) == 0 { + if lu.EntryCount == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/disks/sorting.go b/pkg/cloudapi/disks/sorting.go index 8b34498..39c9055 100644 --- a/pkg/cloudapi/disks/sorting.go +++ b/pkg/cloudapi/disks/sorting.go @@ -6,6 +6,63 @@ import "sort" // // If inverse param is set to true, the order is reversed. func (ld ListDisks) SortByCreatedTime(inverse bool) ListDisks { + if len(ld.Data) < 2 { + return ld + } + + sort.Slice(ld.Data, func(i, j int) bool { + if inverse { + return ld.Data[i].CreatedTime > ld.Data[j].CreatedTime + } + + return ld.Data[i].CreatedTime < ld.Data[j].CreatedTime + }) + + return ld +} + +// SortByDestructionTime sorts ListDisks by the DestructionTime field in ascending order. +// +// If inverse param is set to true, the order is reversed. +func (ld ListDisks) SortByDestructionTime(inverse bool) ListDisks { + if len(ld.Data) < 2 { + return ld + } + + sort.Slice(ld.Data, func(i, j int) bool { + if inverse { + return ld.Data[i].DestructionTime > ld.Data[j].DestructionTime + } + + return ld.Data[i].DestructionTime < ld.Data[j].DestructionTime + }) + + return ld +} + +// SortByDeletedTime sorts ListDisks by the DeletedTime field in ascending order. +// +// If inverse param is set to true, the order is reversed. +func (ld ListDisks) SortByDeletedTime(inverse bool) ListDisks { + if len(ld.Data) < 2 { + return ld + } + + sort.Slice(ld.Data, func(i, j int) bool { + if inverse { + return ld.Data[i].DeletedTime > ld.Data[j].DeletedTime + } + + return ld.Data[i].DeletedTime < ld.Data[j].DeletedTime + }) + + return ld +} + +// SortByCreatedTime sorts ListSearchDisks by the CreatedTime field in ascending order. +// +// If inverse param is set to true, the order is reversed. +func (ld ListSearchDisks) SortByCreatedTime(inverse bool) ListSearchDisks { if len(ld) < 2 { return ld } @@ -21,10 +78,10 @@ func (ld ListDisks) SortByCreatedTime(inverse bool) ListDisks { return ld } -// SortByDestructionTime sorts ListDisks by the DestructionTime field in ascending order. +// SortByDestructionTime sorts ListSearchDisks by the DestructionTime field in ascending order. // // If inverse param is set to true, the order is reversed. -func (ld ListDisks) SortByDestructionTime(inverse bool) ListDisks { +func (ld ListSearchDisks) SortByDestructionTime(inverse bool) ListSearchDisks { if len(ld) < 2 { return ld } @@ -40,10 +97,10 @@ func (ld ListDisks) SortByDestructionTime(inverse bool) ListDisks { return ld } -// SortByDeletedTime sorts ListDisks by the DeletedTime field in ascending order. +// SortByDeletedTime sorts ListSearchDisks by the DeletedTime field in ascending order. // // If inverse param is set to true, the order is reversed. -func (ld ListDisks) SortByDeletedTime(inverse bool) ListDisks { +func (ld ListSearchDisks) SortByDeletedTime(inverse bool) ListSearchDisks { if len(ld) < 2 { return ld } @@ -63,16 +120,16 @@ func (ld ListDisks) SortByDeletedTime(inverse bool) ListDisks { // // If inverse param is set to true, the order is reversed. func (lu ListDisksUnattached) SortByCreatedTime(inverse bool) ListDisksUnattached { - if len(lu) < 2 { + if len(lu.Data) < 2 { return lu } - sort.Slice(lu, func(i, j int) bool { + sort.Slice(lu.Data, func(i, j int) bool { if inverse { - return lu[i].CreatedTime > lu[j].CreatedTime + return lu.Data[i].CreatedTime > lu.Data[j].CreatedTime } - return lu[i].CreatedTime < lu[j].CreatedTime + return lu.Data[i].CreatedTime < lu.Data[j].CreatedTime }) return lu @@ -82,16 +139,16 @@ func (lu ListDisksUnattached) SortByCreatedTime(inverse bool) ListDisksUnattache // // If inverse param is set to true, the order is reversed. func (lu ListDisksUnattached) SortByDestructionTime(inverse bool) ListDisksUnattached { - if len(lu) < 2 { + if len(lu.Data) < 2 { return lu } - sort.Slice(lu, func(i, j int) bool { + sort.Slice(lu.Data, func(i, j int) bool { if inverse { - return lu[i].DestructionTime > lu[j].DestructionTime + return lu.Data[i].DestructionTime > lu.Data[j].DestructionTime } - return lu[i].DestructionTime < lu[j].DestructionTime + return lu.Data[i].DestructionTime < lu.Data[j].DestructionTime }) return lu @@ -101,16 +158,16 @@ func (lu ListDisksUnattached) SortByDestructionTime(inverse bool) ListDisksUnatt // // If inverse param is set to true, the order is reversed. func (lu ListDisksUnattached) SortByDeletedTime(inverse bool) ListDisksUnattached { - if len(lu) < 2 { + if len(lu.Data) < 2 { return lu } - sort.Slice(lu, func(i, j int) bool { + sort.Slice(lu.Data, func(i, j int) bool { if inverse { - return lu[i].DeletedTime > lu[j].DeletedTime + return lu.Data[i].DeletedTime > lu.Data[j].DeletedTime } - return lu[i].DeletedTime < lu[j].DeletedTime + return lu.Data[i].DeletedTime < lu.Data[j].DeletedTime }) return lu diff --git a/pkg/cloudapi/extnet/filter.go b/pkg/cloudapi/extnet/filter.go index 8148d25..c6d1e7b 100644 --- a/pkg/cloudapi/extnet/filter.go +++ b/pkg/cloudapi/extnet/filter.go @@ -31,21 +31,23 @@ func (lenet ListExtNets) FilterByStatus(status string) ListExtNets { func (lenet ListExtNets) FilterFunc(predicate func(ItemExtNet) bool) ListExtNets { var result ListExtNets - for _, item := range lenet { + for _, item := range lenet.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 ItemExtNet // If none was found, returns an empty struct. func (lenet ListExtNets) FindOne() ItemExtNet { - if len(lenet) == 0 { + if lenet.EntryCount == 0 { return ItemExtNet{} } - return lenet[0] + return lenet.Data[0] } diff --git a/pkg/cloudapi/extnet/filter_test.go b/pkg/cloudapi/extnet/filter_test.go index a9a7759..1b05b7b 100644 --- a/pkg/cloudapi/extnet/filter_test.go +++ b/pkg/cloudapi/extnet/filter_test.go @@ -3,23 +3,25 @@ package extnet import "testing" var extnets = ListExtNets{ - ItemExtNet{ - ID: 3, - IPCIDR: "176.118.164.0/24", - Name: "176.118.164.0/24", - Status: "ENABLED", - }, - ItemExtNet{ - ID: 10, - IPCIDR: "45.134.255.0/24", - Name: "45.134.255.0/24", - Status: "ENABLED", - }, - ItemExtNet{ - ID: 13, - IPCIDR: "88.218.249.0/24", - Name: "88.218.249.0/24", - Status: "DISABLED", + Data: []ItemExtNet{ + { + ID: 3, + IPCIDR: "176.118.164.0/24", + Name: "176.118.164.0/24", + Status: "ENABLED", + }, + { + ID: 10, + IPCIDR: "45.134.255.0/24", + Name: "45.134.255.0/24", + Status: "ENABLED", + }, + { + ID: 13, + IPCIDR: "88.218.249.0/24", + Name: "88.218.249.0/24", + Status: "DISABLED", + }, }, } @@ -43,11 +45,11 @@ func TestFilterByName(t *testing.T) { func TestFilterByStatus(t *testing.T) { actual := extnets.FilterByStatus("ENABLED") - 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.Status != "ENABLED" { t.Fatal("expected Status 'ENABLED', found: ", item.Status) } @@ -59,7 +61,7 @@ func TestFilterFunc(t *testing.T) { return ien.IPCIDR == ien.Name }) - if len(actual) != 3 { - t.Fatal("expected 3 elements, found: ", len(actual)) + if len(actual.Data) != 3 { + t.Fatal("expected 3 elements, found: ", len(actual.Data)) } } diff --git a/pkg/cloudapi/extnet/list.go b/pkg/cloudapi/extnet/list.go index 92ab4d2..9a1a905 100644 --- a/pkg/cloudapi/extnet/list.go +++ b/pkg/cloudapi/extnet/list.go @@ -8,10 +8,34 @@ import ( // Request struct for get list external network type ListRequest struct { - // Filter by account ID + // Find by account ID // Required: false AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + // 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 network ip address + // Required: false + Network string `url:"network,omitempty" json:"network,omitempty"` + + // Find by vlan ID + // Required: false + VLANID uint64 `url:"vlanId,omitempty" json:"vlanId,omitempty"` + + // Find by vnfDevices ID + // Required: false + VNFDevID uint64 `url:"vnfDevId,omitempty" json:"vnfDevId,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + // Page number // Required: false Page uint64 `url:"page,omitempty" json:"page,omitempty"` @@ -22,7 +46,7 @@ type ListRequest struct { } // List gets list all available external networks -func (e ExtNet) List(ctx context.Context, req ListRequest) (ListExtNets, error) { +func (e ExtNet) List(ctx context.Context, req ListRequest) (*ListExtNets, error) { url := "/cloudapi/extnet/list" res, err := e.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -37,5 +61,5 @@ func (e ExtNet) List(ctx context.Context, req ListRequest) (ListExtNets, error) return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/extnet/models.go b/pkg/cloudapi/extnet/models.go index 54f2ebb..5059d46 100644 --- a/pkg/cloudapi/extnet/models.go +++ b/pkg/cloudapi/extnet/models.go @@ -25,7 +25,11 @@ type ItemExtNetExtend struct { } // List of information about external network -type ListExtNets []ItemExtNet +type ListExtNets struct { + Data []ItemExtNet `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} // List of extend information about external network type ListExtNetExtends []ItemExtNetExtend diff --git a/pkg/cloudapi/extnet/serialize.go b/pkg/cloudapi/extnet/serialize.go index 2505180..fa94ebd 100644 --- a/pkg/cloudapi/extnet/serialize.go +++ b/pkg/cloudapi/extnet/serialize.go @@ -12,7 +12,7 @@ import ( // - First argument -> prefix // - Second argument -> indent func (lenet ListExtNets) Serialize(params ...string) (serialization.Serialized, error) { - if len(lenet) == 0 { + if lenet.EntryCount == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/flipgroup/list.go b/pkg/cloudapi/flipgroup/list.go index efbb6e4..bc9ae0b 100644 --- a/pkg/cloudapi/flipgroup/list.go +++ b/pkg/cloudapi/flipgroup/list.go @@ -8,6 +8,34 @@ import ( // 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"` @@ -18,7 +46,7 @@ type ListRequest struct { } // List gets list FLIPGroup managed cluster instances available to the current user -func (f FLIPGroup) List(ctx context.Context, req ListRequest) (ListFLIPGroups, error) { +func (f FLIPGroup) List(ctx context.Context, req ListRequest) (*ListFLIPGroups, error) { url := "/cloudapi/flipgroup/list" res, err := f.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -33,5 +61,5 @@ func (f FLIPGroup) List(ctx context.Context, req ListRequest) (ListFLIPGroups, e return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/flipgroup/models.go b/pkg/cloudapi/flipgroup/models.go index 5c8f090..8c8bbd8 100644 --- a/pkg/cloudapi/flipgroup/models.go +++ b/pkg/cloudapi/flipgroup/models.go @@ -20,18 +20,18 @@ type RecordFLIPGroup struct { // Detailed information about FLIPGroup type ItemFLIPGroup struct { + // CKey + CKey string `json:"_ckey"` + + // Meta + Meta []interface{} `json:"_meta"` + // Account ID AccountID uint64 `json:"accountId"` - // Account name - AccountName string `json:"accountName"` - // List of client IDs ClientIDs []uint64 `json:"clientIds"` - // Client names list - ClientNames []string `json:"clientNames"` - // Client type ClientType string `json:"clientType"` @@ -41,21 +41,9 @@ type ItemFLIPGroup struct { // 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"` @@ -83,24 +71,16 @@ type ItemFLIPGroup struct { // 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"` + // NetMask + NetMask uint64 `json:"netmask"` // Status Status string `json:"status"` - - // Updated by - UpdatedBy string `json:"updatedBy"` - - // Updated time - UpdatedTime uint64 `json:"updatedTime"` } // List of FLIPGroup -type ListFLIPGroups []ItemFLIPGroup +type ListFLIPGroups struct { + Data []ItemFLIPGroup `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} diff --git a/pkg/cloudapi/flipgroup/serialize.go b/pkg/cloudapi/flipgroup/serialize.go index f3e0399..4eaa6e1 100644 --- a/pkg/cloudapi/flipgroup/serialize.go +++ b/pkg/cloudapi/flipgroup/serialize.go @@ -12,7 +12,7 @@ import ( // - First argument -> prefix // - Second argument -> indent func (lfg ListFLIPGroups) Serialize(params ...string) (serialization.Serialized, error) { - if len(lfg) == 0 { + if len(lfg.Data) == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/k8ci/filter.go b/pkg/cloudapi/k8ci/filter.go index 5043acd..67c5db0 100644 --- a/pkg/cloudapi/k8ci/filter.go +++ b/pkg/cloudapi/k8ci/filter.go @@ -3,7 +3,7 @@ package k8ci // FilterByID returns ListK8CI with specified ID. func (lkc ListK8CI) FilterByID(id uint64) ListK8CI { predicate := func(ikc ItemK8CI) bool { - return ikc.RecordK8CI.ID == id + return ikc.ID == id } return lkc.FilterFunc(predicate) @@ -12,7 +12,7 @@ func (lkc ListK8CI) FilterByID(id uint64) ListK8CI { // FilterByName returns ListK8CI with specified Name. func (lkc ListK8CI) FilterByName(name string) ListK8CI { predicate := func(ikc ItemK8CI) bool { - return ikc.RecordK8CI.Name == name + return ikc.Name == name } return lkc.FilterFunc(predicate) @@ -22,21 +22,23 @@ func (lkc ListK8CI) FilterByName(name string) ListK8CI { func (lkc ListK8CI) FilterFunc(predicate func(ItemK8CI) bool) ListK8CI { var result ListK8CI - for _, item := range lkc { + for _, item := range lkc.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 ItemK8CI // If none was found, returns an empty struct. func (lkc ListK8CI) FindOne() ItemK8CI { - if len(lkc) == 0 { + if len(lkc.Data) == 0 { return ItemK8CI{} } - return lkc[0] + return lkc.Data[0] } diff --git a/pkg/cloudapi/k8ci/filter_test.go b/pkg/cloudapi/k8ci/filter_test.go index 6207612..61fa550 100644 --- a/pkg/cloudapi/k8ci/filter_test.go +++ b/pkg/cloudapi/k8ci/filter_test.go @@ -3,33 +3,50 @@ package k8ci import "testing" var k8ciItems = ListK8CI{ - ItemK8CI{ - CreatedTime: 123902139, - RecordK8CI: RecordK8CI{ + Data: []ItemK8CI{ + { + CreatedTime: 123902139, + Status: "ENABLED", Description: "", ID: 1, Name: "purple_snake", Version: "1", + LBImageID: 654, + NetworkPlugins: []string{ + "flannel", + "calico", + "weavenet", + }, }, - }, - ItemK8CI{ - CreatedTime: 123902232, - RecordK8CI: RecordK8CI{ + { + CreatedTime: 123902232, + Status: "ENABLED", Description: "", ID: 2, Name: "green_giant", Version: "2", + LBImageID: 654, + NetworkPlugins: []string{ + "flannel", + "calico", + "weavenet", + }, }, - }, - ItemK8CI{ - CreatedTime: 123902335, - RecordK8CI: RecordK8CI{ + { + CreatedTime: 123902335, + Status: "DISABLED", Description: "", ID: 3, Name: "magenta_cloud", Version: "3", + NetworkPlugins: []string{ + "flannel", + "calico", + "weavenet", + }, }, }, + EntryCount: 3, } func TestFilterByID(t *testing.T) { @@ -53,11 +70,11 @@ func TestFilterFunc(t *testing.T) { return ikc.CreatedTime > 123902139 }) - 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.CreatedTime < 123902139 { t.Fatal("expected CreatedTime greater than 123902139, found: ", item.CreatedTime) } @@ -67,7 +84,7 @@ func TestFilterFunc(t *testing.T) { func TestSortingByCreatedTime(t *testing.T) { actual := k8ciItems.SortByCreatedTime(true) - if actual[0].CreatedTime != 123902335 && actual[2].CreatedTime != 123902139 { + if actual.Data[0].CreatedTime != 123902335 && actual.Data[2].CreatedTime != 123902139 { t.Fatal("expected inverse sort, found normal") } } diff --git a/pkg/cloudapi/k8ci/list.go b/pkg/cloudapi/k8ci/list.go index ba77e13..7e22e75 100644 --- a/pkg/cloudapi/k8ci/list.go +++ b/pkg/cloudapi/k8ci/list.go @@ -8,6 +8,30 @@ import ( // Request struct for get list information about images type ListRequest struct { + // Find by ID + // Required: false + ByID uint64 `url:"id,omitempty" json:"id,omitempty"` + + // Find by name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Find by worker driver + // Required: false + WorkerDriver string `url:"workerDriver,omitempty" json:"workerDriver,omitempty"` + + // Find by master driver + // Required: false + MasterDriver string `url:"masterDriver,omitempty" json:"masterDriver,omitempty"` + + // Find by network plugin + // Required: false + NetworkPlugins string `url:"netPlugins,omitempty" json:"netPlugins,omitempty"` + // List disabled items as well // Required: false IncludeDisabled bool `url:"includeDisabled,omitempty" json:"includeDisabled,omitempty"` @@ -22,7 +46,7 @@ type ListRequest struct { } // List gets list all k8ci catalog items available to the current user -func (k K8CI) List(ctx context.Context, req ListRequest) (ListK8CI, error) { +func (k K8CI) List(ctx context.Context, req ListRequest) (*ListK8CI, error) { url := "/cloudapi/k8ci/list" res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -37,5 +61,5 @@ func (k K8CI) List(ctx context.Context, req ListRequest) (ListK8CI, error) { return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/k8ci/list_deleted.go b/pkg/cloudapi/k8ci/list_deleted.go index 1f1ee76..42c10eb 100644 --- a/pkg/cloudapi/k8ci/list_deleted.go +++ b/pkg/cloudapi/k8ci/list_deleted.go @@ -18,7 +18,7 @@ type ListDeletedRequest struct { } // ListDeleted gets list all deleted k8ci catalog items available to the current user -func (k K8CI) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListK8CI, error) { +func (k K8CI) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListK8CI, error) { url := "/cloudapi/k8ci/listDeleted" res, err := k.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -33,5 +33,5 @@ func (k K8CI) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListK8CI return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/k8ci/models.go b/pkg/cloudapi/k8ci/models.go index bd7cc95..76b0ce3 100644 --- a/pkg/cloudapi/k8ci/models.go +++ b/pkg/cloudapi/k8ci/models.go @@ -5,12 +5,34 @@ type ItemK8CI struct { // Created time CreatedTime uint64 `json:"createdTime"` - // Main information about K8CI - RecordK8CI + // Description + Description string `json:"desc"` + + // ID + ID uint64 `json:"id"` + + // LB image ID + LBImageID uint64 `json:"lbImageId"` + + // Name + Name string `json:"name"` + + // Network plugins + NetworkPlugins []string `json:"networkPlugins"` + + // Status + Status string `json:"status"` + + // Version + Version string `json:"version"` } // List of K8CI -type ListK8CI []ItemK8CI +type ListK8CI struct { + Data []ItemK8CI `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} // Main information about K8CI type RecordK8CI struct { diff --git a/pkg/cloudapi/k8ci/serialize.go b/pkg/cloudapi/k8ci/serialize.go index 01fadfa..6fd1bbf 100644 --- a/pkg/cloudapi/k8ci/serialize.go +++ b/pkg/cloudapi/k8ci/serialize.go @@ -12,7 +12,7 @@ import ( // - First argument -> prefix // - Second argument -> indent func (lkc ListK8CI) Serialize(params ...string) (serialization.Serialized, error) { - if len(lkc) == 0 { + if len(lkc.Data) == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/k8ci/sorting.go b/pkg/cloudapi/k8ci/sorting.go index db8b328..865c239 100644 --- a/pkg/cloudapi/k8ci/sorting.go +++ b/pkg/cloudapi/k8ci/sorting.go @@ -6,16 +6,16 @@ import "sort" // // If inverse param is set to true, the order is reversed. func (lkc ListK8CI) SortByCreatedTime(inverse bool) ListK8CI { - if len(lkc) < 2 { + if len(lkc.Data) < 2 { return lkc } - sort.Slice(lkc, func(i, j int) bool { + sort.Slice(lkc.Data, func(i, j int) bool { if inverse { - return lkc[i].CreatedTime > lkc[j].CreatedTime + return lkc.Data[i].CreatedTime > lkc.Data[j].CreatedTime } - return lkc[i].CreatedTime < lkc[j].CreatedTime + return lkc.Data[i].CreatedTime < lkc.Data[j].CreatedTime }) return lkc diff --git a/pkg/cloudapi/kvmx86/create.go b/pkg/cloudapi/kvmx86/create.go index be706a1..64eb711 100644 --- a/pkg/cloudapi/kvmx86/create.go +++ b/pkg/cloudapi/kvmx86/create.go @@ -8,6 +8,23 @@ import ( "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" ) +type Interface struct { + // Network type + // Should be one of: + // - VINS + // - EXTNET + NetType string `url:"netType" json:"netType" validate:"required,kvmNetType"` + + // Network ID for connect to, + // for EXTNET - external network ID, + // for VINS - VINS ID, + NetID uint64 `url:"netId" json:"netId" validate:"required"` + + // IP address to assign to this VM when connecting to the specified network + // Required: false + IPAddr string `url:"ipAddr,omitempty" json:"ipAddr,omitempty"` +} + // Request struct for create KVM x86 VM type CreateRequest struct { // ID of the resource group, which will own this VM @@ -45,24 +62,8 @@ type CreateRequest struct { // Required: false Pool string `url:"pool,omitempty" json:"pool,omitempty"` - // Network type - // Should be one of: - // - VINS - // - EXTNET - // - NONE - // Required: false - NetType string `url:"netType,omitempty" json:"netType,omitempty" validate:"omitempty,kvmNetType"` - - // Network ID for connect to, - // for EXTNET - external network ID, - // for VINS - VINS ID, - // when network type is not "NONE" - // Required: false - NetID uint64 `url:"netId,omitempty" json:"netId,omitempty"` - - // IP address to assign to this VM when connecting to the specified network - // Required: false - IPAddr string `url:"ipAddr,omitempty" json:"ipAddr,omitempty"` + // Slice of structs with net interface description. + Interfaces []Interface `url:"interfaces,omitempty" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"` // Input data for cloud-init facility // Required: false diff --git a/pkg/cloudapi/kvmx86/create_blank.go b/pkg/cloudapi/kvmx86/create_blank.go index 3771fc3..d0effdf 100644 --- a/pkg/cloudapi/kvmx86/create_blank.go +++ b/pkg/cloudapi/kvmx86/create_blank.go @@ -40,25 +40,8 @@ type CreateBlankRequest struct { // Required: true Pool string `url:"pool" json:"pool" validate:"required"` - // Network type - // Should be one of: - // - VINS - // - EXTNET - // - NONE - // Required: false - NetType string `url:"netType,omitempty" json:"netType,omitempty" validate:"omitempty,kvmNetType"` - - // Network ID for connect to, - // for EXTNET - external network ID, - // for VINS - VINS ID, - // when network type is not "NONE" - // Required: false - NetID uint64 `url:"netId,omitempty" json:"netId,omitempty"` - - // IP address to assign to this VM when connecting to the specified network - // Required: false - IPAddr string `url:"ipAddr,omitempty" json:"ipAddr,omitempty"` - + // Slice of structs with net interface description. + Interfaces []Interface `url:"interfaces,omitempty" json:"interfaces,omitempty" validate:"omitempty,min=1,dive"` // Text description of this VM // Required: false Description string `url:"desc,omitempty" json:"desc,omitempty"` diff --git a/pkg/cloudapi/locations/filter.go b/pkg/cloudapi/locations/filter.go index 886496a..cc46e8a 100644 --- a/pkg/cloudapi/locations/filter.go +++ b/pkg/cloudapi/locations/filter.go @@ -31,21 +31,23 @@ func (ll ListLocations) FilterByGID(gid uint64) ListLocations { func (ll ListLocations) FilterFunc(predicate func(ItemLocation) bool) ListLocations { var result ListLocations - for _, item := range ll { + for _, item := range ll.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 ItemLocation // If none was found, returns an empty struct. func (ll ListLocations) FindOne() ItemLocation { - if len(ll) == 0 { + if len(ll.Data) == 0 { return ItemLocation{} } - return ll[0] + return ll.Data[0] } diff --git a/pkg/cloudapi/locations/filter_test.go b/pkg/cloudapi/locations/filter_test.go index a8d253d..d1c5cb4 100644 --- a/pkg/cloudapi/locations/filter_test.go +++ b/pkg/cloudapi/locations/filter_test.go @@ -3,48 +3,51 @@ package locations import "testing" var locationItems = ListLocations{ - { - GID: 212, - ID: 1, - GUID: 1, - LocationCode: "alfa", - Name: "alfa", - Flag: "", - Meta: []interface{}{ - "cloudbroker", - "location", - 1, + Data: []ItemLocation{ + { + GID: 212, + ID: 1, + GUID: 1, + LocationCode: "alfa", + Name: "alfa", + Flag: "", + Meta: []interface{}{ + "cloudbroker", + "location", + 1, + }, + CKey: "", }, - CKey: "", - }, - { - GID: 222, - ID: 2, - GUID: 2, - LocationCode: "beta", - Name: "beta", - Flag: "", - Meta: []interface{}{ - "cloudbroker", - "location", - 1, + { + GID: 222, + ID: 2, + GUID: 2, + LocationCode: "beta", + Name: "beta", + Flag: "", + Meta: []interface{}{ + "cloudbroker", + "location", + 1, + }, + CKey: "", }, - CKey: "", - }, - { - GID: 232, - ID: 3, - GUID: 3, - LocationCode: "gamma", - Name: "gamma", - Flag: "", - Meta: []interface{}{ - "cloudbroker", - "location", - 1, + { + GID: 232, + ID: 3, + GUID: 3, + LocationCode: "gamma", + Name: "gamma", + Flag: "", + Meta: []interface{}{ + "cloudbroker", + "location", + 1, + }, + CKey: "", }, - CKey: "", }, + EntryCount: 3, } func TestFilterByID(t *testing.T) { diff --git a/pkg/cloudapi/locations/list.go b/pkg/cloudapi/locations/list.go index ec3254d..0ef33f7 100644 --- a/pkg/cloudapi/locations/list.go +++ b/pkg/cloudapi/locations/list.go @@ -15,10 +15,26 @@ type ListRequest struct { // Page size // Required: false Size uint64 `url:"size,omitempty" json:"size,omitempty"` + + // Find by flag + // Required: false + Flag string `url:"flag,omitempty" json:"flag,omitempty"` + + // Find by name + // Required: false + Name string `url:"name,omitempty" json:"name,omitempty"` + + // Find by ID + // Required: false + ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"` + + // Find by code location + // Required: false + LocationCode string `url:"locationCode,omitempty" json:"locationCode,omitempty"` } // List gets list all locations -func (l Locations) List(ctx context.Context, req ListRequest) (ListLocations, error) { +func (l Locations) List(ctx context.Context, req ListRequest) (*ListLocations, error) { url := "/cloudapi/locations/list" res, err := l.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -33,5 +49,5 @@ func (l Locations) List(ctx context.Context, req ListRequest) (ListLocations, er return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/locations/models.go b/pkg/cloudapi/locations/models.go index 80df20a..2077d0a 100644 --- a/pkg/cloudapi/locations/models.go +++ b/pkg/cloudapi/locations/models.go @@ -28,4 +28,10 @@ type ItemLocation struct { } // List of locations -type ListLocations []ItemLocation +type ListLocations struct { + // Data + Data []ItemLocation `json:"data"` + + // Entry count + EntryCount uint64 `json:"entryCount"` +} diff --git a/pkg/cloudapi/locations/serialize.go b/pkg/cloudapi/locations/serialize.go index 0ab0501..fdc30e0 100644 --- a/pkg/cloudapi/locations/serialize.go +++ b/pkg/cloudapi/locations/serialize.go @@ -12,7 +12,7 @@ import ( // - First argument -> prefix // - Second argument -> indent func (ll ListLocations) Serialize(params ...string) (serialization.Serialized, error) { - if len(ll) == 0 { + if len(ll.Data) == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/rg/filter.go b/pkg/cloudapi/rg/filter.go index af6b14a..bf6130b 100644 --- a/pkg/cloudapi/rg/filter.go +++ b/pkg/cloudapi/rg/filter.go @@ -58,21 +58,23 @@ func (lrg ListResourceGroups) FilterByDefNetType(defNetType string) ListResource func (lrg ListResourceGroups) FilterFunc(predicate func(irg ItemResourceGroup) bool) ListResourceGroups { var result ListResourceGroups - for _, rgItem := range lrg { + for _, rgItem := range lrg.Data { if predicate(rgItem) { - result = append(result, rgItem) + result.Data = append(result.Data, rgItem) } } + result.EntryCount = uint64(len(result.Data)) + return result } // FindOne returns first found ItemResourceGroup. // If none was found, returns an empty struct. func (lrg ListResourceGroups) FindOne() ItemResourceGroup { - if len(lrg) == 0 { + if len(lrg.Data) == 0 { return ItemResourceGroup{} } - return lrg[0] + return lrg.Data[0] } diff --git a/pkg/cloudapi/rg/filter_test.go b/pkg/cloudapi/rg/filter_test.go index d2ba496..5caab07 100644 --- a/pkg/cloudapi/rg/filter_test.go +++ b/pkg/cloudapi/rg/filter_test.go @@ -3,137 +3,140 @@ package rg import "testing" var rgs = ListResourceGroups{ - { - AccountID: 1, - AccountName: "std", - ACL: ListACL{ - { - Explicit: true, - GUID: "", - Right: "ARCXDU", - Status: "CONFIRMED", - Type: "U", - UserGroupID: "sample_user_1@decs3o", + Data: []ItemResourceGroup{ + { + AccountID: 1, + AccountName: "std", + ACL: ListACL{ + { + Explicit: true, + GUID: "", + Right: "ARCXDU", + Status: "CONFIRMED", + Type: "U", + UserGroupID: "sample_user_1@decs3o", + }, }, - }, - CreatedBy: "sample_user_1@decs3o", - CreatedTime: 1676645305, - DefNetID: 1, - DefNetType: "NONE", - DeletedBy: "", - DeletedTime: 0, - Description: "", - GID: 212, - GUID: 7971, - ID: 7971, - LockStatus: "UNLOCKED", - Milestones: 363459, - Name: "rg_1", - RegisterComputes: false, - ResourceLimits: ResourceLimits{ - CUC: -1, - CUI: -1, - CUM: -1, - CUNP: -1, - GPUUnits: -1, - }, - Secret: "", - Status: "CREATED", - UpdatedBy: "", - UpdatedTime: 0, - VINS: []uint64{}, - Computes: []uint64{}, - ResTypes: []string{}, - UniqPools: []string{}, - }, - { - AccountID: 2, - AccountName: "std_2", - ACL: ListACL{ - { - Explicit: true, - GUID: "", - Right: "ARCXDU", - Status: "CONFIRMED", - Type: "U", - UserGroupID: "sample_user_1@decs3o", + CreatedBy: "sample_user_1@decs3o", + CreatedTime: 1676645305, + DefNetID: 1, + DefNetType: "NONE", + DeletedBy: "", + DeletedTime: 0, + Description: "", + GID: 212, + GUID: 7971, + ID: 7971, + LockStatus: "UNLOCKED", + Milestones: 363459, + Name: "rg_1", + RegisterComputes: false, + ResourceLimits: ResourceLimits{ + CUC: -1, + CUI: -1, + CUM: -1, + CUNP: -1, + GPUUnits: -1, }, + Secret: "", + Status: "CREATED", + UpdatedBy: "", + UpdatedTime: 0, + VINS: []uint64{}, + Computes: []uint64{}, + ResTypes: []string{}, + UniqPools: []string{}, }, - CreatedBy: "sample_user_1@decs3o", - CreatedTime: 1676645461, - DefNetID: 2, - DefNetType: "NONE", - DeletedBy: "", - DeletedTime: 0, - Description: "", - GID: 212, - GUID: 7972, - ID: 7972, - LockStatus: "UNLOCKED", - Milestones: 363468, - Name: "rg_2", - RegisterComputes: false, - ResourceLimits: ResourceLimits{ - CUC: -1, - CUI: -1, - CUM: -1, - CUNP: -1, - GPUUnits: -1, - }, - Secret: "", - Status: "CREATED", - UpdatedBy: "", - UpdatedTime: 0, - VINS: []uint64{}, - Computes: []uint64{}, - ResTypes: []string{}, - UniqPools: []string{}, - }, - { - AccountID: 3, - AccountName: "std_3", - ACL: ListACL{ - { - Explicit: true, - GUID: "", - Right: "ARCXDU", - Status: "CONFIRMED", - Type: "U", - UserGroupID: "sample_user_2@decs3o", + { + AccountID: 2, + AccountName: "std_2", + ACL: ListACL{ + { + Explicit: true, + GUID: "", + Right: "ARCXDU", + Status: "CONFIRMED", + Type: "U", + UserGroupID: "sample_user_1@decs3o", + }, }, + CreatedBy: "sample_user_1@decs3o", + CreatedTime: 1676645461, + DefNetID: 2, + DefNetType: "NONE", + DeletedBy: "", + DeletedTime: 0, + Description: "", + GID: 212, + GUID: 7972, + ID: 7972, + LockStatus: "UNLOCKED", + Milestones: 363468, + Name: "rg_2", + RegisterComputes: false, + ResourceLimits: ResourceLimits{ + CUC: -1, + CUI: -1, + CUM: -1, + CUNP: -1, + GPUUnits: -1, + }, + Secret: "", + Status: "CREATED", + UpdatedBy: "", + UpdatedTime: 0, + VINS: []uint64{}, + Computes: []uint64{}, + ResTypes: []string{}, + UniqPools: []string{}, }, - CreatedBy: "sample_user_2@decs3o", - CreatedTime: 1676645548, - DefNetID: 3, - DefNetType: "NONE", - DeletedBy: "", - DeletedTime: 0, - Description: "", - GID: 212, - GUID: 7973, - ID: 7973, - LockStatus: "kjLOCKED", - Milestones: 363471, - Name: "rg_3", - RegisterComputes: false, - ResourceLimits: ResourceLimits{ - CUC: -1, - CUI: -1, - CUM: -1, - CUNP: -1, - GPUUnits: -1, - }, - Secret: "", - Status: "DISABLED", - UpdatedBy: "", - UpdatedTime: 0, - VINS: []uint64{}, - Computes: []uint64{ - 48500, + { + AccountID: 3, + AccountName: "std_3", + ACL: ListACL{ + { + Explicit: true, + GUID: "", + Right: "ARCXDU", + Status: "CONFIRMED", + Type: "U", + UserGroupID: "sample_user_2@decs3o", + }, + }, + CreatedBy: "sample_user_2@decs3o", + CreatedTime: 1676645548, + DefNetID: 3, + DefNetType: "NONE", + DeletedBy: "", + DeletedTime: 0, + Description: "", + GID: 212, + GUID: 7973, + ID: 7973, + LockStatus: "kjLOCKED", + Milestones: 363471, + Name: "rg_3", + RegisterComputes: false, + ResourceLimits: ResourceLimits{ + CUC: -1, + CUI: -1, + CUM: -1, + CUNP: -1, + GPUUnits: -1, + }, + Secret: "", + Status: "DISABLED", + UpdatedBy: "", + UpdatedTime: 0, + VINS: []uint64{}, + Computes: []uint64{ + 48500, + }, + ResTypes: []string{}, + UniqPools: []string{}, }, - ResTypes: []string{}, - UniqPools: []string{}, }, + EntryCount: 3, } func TestFilterByID(t *testing.T) { @@ -155,11 +158,11 @@ func TestFilterByName(t *testing.T) { func TestFilterByCreatedBy(t *testing.T) { actual := rgs.FilterByCreatedBy("sample_user_1@decs3o") - 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.CreatedBy != "sample_user_1@decs3o" { t.Fatal("expected CreatedBy 'sample_user_1@decs3o', found: ", item.CreatedBy) } @@ -169,11 +172,11 @@ func TestFilterByCreatedBy(t *testing.T) { func TestFilterByStatus(t *testing.T) { actual := rgs.FilterByStatus("CREATED") - 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.Status != "CREATED" { t.Fatal("expected Status 'ENABLED', found: ", item.Status) } @@ -183,11 +186,11 @@ func TestFilterByStatus(t *testing.T) { func TestFilterByLockStatus(t *testing.T) { actual := rgs.FilterByLockStatus("UNLOCKED") - 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.LockStatus != "UNLOCKED" { t.Fatal("expected LockStatus 'UNLOCKED', found: ", item.LockStatus) } @@ -197,11 +200,11 @@ func TestFilterByLockStatus(t *testing.T) { func TestFilterByDefNetType(t *testing.T) { actual := rgs.FilterByDefNetType("NONE") - if len(actual) != 3 { - t.Fatal("expected 3 found, actual: ", len(actual)) + if len(actual.Data) != 3 { + t.Fatal("expected 3 found, actual: ", len(actual.Data)) } - for _, item := range actual { + for _, item := range actual.Data { if item.DefNetType != "NONE" { t.Fatal("expected DefNetType 'NONE', found: ", item.DefNetType) } @@ -213,11 +216,11 @@ func TestFilterFunc(t *testing.T) { return len(ir.Computes) > 0 }) - if len(actual) < 1 { - t.Fatal("expected 1 found, actual: ", len(actual)) + if len(actual.Data) < 1 { + t.Fatal("expected 1 found, actual: ", len(actual.Data)) } - for _, item := range actual { + for _, item := range actual.Data { if len(item.Computes) < 1 { t.Fatal("expected VMs to contain at least 1 element, found empty") } @@ -227,7 +230,7 @@ func TestFilterFunc(t *testing.T) { func TestSortByCreatedTime(t *testing.T) { actual := rgs.SortByCreatedTime(true) - if actual[0].CreatedTime != 1676645548 || actual[2].CreatedTime != 1676645305 { + if actual.Data[0].CreatedTime != 1676645548 || actual.Data[2].CreatedTime != 1676645305 { t.Fatal("expected descending order, found ascending") } } diff --git a/pkg/cloudapi/rg/get_resource_consumption.go b/pkg/cloudapi/rg/get_resource_consumption.go new file mode 100644 index 0000000..9217737 --- /dev/null +++ b/pkg/cloudapi/rg/get_resource_consumption.go @@ -0,0 +1,42 @@ +package rg + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// Request struct for get detailed information about resource consumption for ResGroup +type GetResourceConsumptionRequest struct { + // Resource group ID + // Required: true + RGID uint64 `url:"rgId" json:"rgId" validate:"required"` +} + +// GetResourceConsumption gets resource consumption of the resource group +func (r RG) GetResourceConsumption(ctx context.Context, req GetResourceConsumptionRequest) (*ItemResourceConsumption, error) { + err := validators.ValidateRequest(req) + if err != nil { + for _, validationError := range validators.GetErrors(err) { + return nil, validators.ValidationError(validationError) + } + } + + url := "/cloudapi/rg/getResourceConsumption" + + res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + info := ItemResourceConsumption{} + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudapi/rg/list.go b/pkg/cloudapi/rg/list.go index 9aa9694..9c32467 100644 --- a/pkg/cloudapi/rg/list.go +++ b/pkg/cloudapi/rg/list.go @@ -8,6 +8,38 @@ import ( // Request struct for get list of resource groups 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 account ID + // Required: false + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + + // Find by name account + // Required: false + AccountName string `url:"accountName,omitempty" json:"accountName,omitempty"` + + // Find by created after time (unix timestamp) + // Required: false + CreatedAfter uint64 `url:"createdAfter,omitempty" json:"createdAfter,omitempty"` + + // Find by created before time (unix timestamp) + // Required: false + CreatedBefore uint64 `url:"createdBefore,omitempty" json:"createdBefore,omitempty"` + + // Find by status + // Required: false + Status string `url:"status,omitempty" json:"status,omitempty"` + + // Find by status lock + // Required: false + LockStatus string `url:"lockStatus,omitempty" json:"lockStatus,omitempty"` + // Included deleted resource groups // Required: false IncludeDeleted bool `url:"includedeleted,omitempty" json:"includedeleted,omitempty"` @@ -22,7 +54,7 @@ type ListRequest struct { } // List gets list of all resource groups the user has access to -func (r RG) List(ctx context.Context, req ListRequest) (ListResourceGroups, error) { +func (r RG) List(ctx context.Context, req ListRequest) (*ListResourceGroups, error) { url := "/cloudapi/rg/list" res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -37,5 +69,5 @@ func (r RG) List(ctx context.Context, req ListRequest) (ListResourceGroups, erro return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/rg/list_deleted.go b/pkg/cloudapi/rg/list_deleted.go index 1f059de..f9625d0 100644 --- a/pkg/cloudapi/rg/list_deleted.go +++ b/pkg/cloudapi/rg/list_deleted.go @@ -18,7 +18,7 @@ type ListDeletedRequest struct { } // ListDeleted gets list all deleted resource groups the user has access to -func (r RG) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListResourceGroups, error) { +func (r RG) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListResourceGroups, error) { url := "/cloudapi/rg/listDeleted" res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -33,5 +33,5 @@ func (r RG) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListResour return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/rg/list_resource_consumption.go b/pkg/cloudapi/rg/list_resource_consumption.go new file mode 100644 index 0000000..badf325 --- /dev/null +++ b/pkg/cloudapi/rg/list_resource_consumption.go @@ -0,0 +1,26 @@ +package rg + +import ( + "context" + "encoding/json" + "net/http" +) + +// ListResourceConsumption gets resource consumptions of the resource groups +func (r RG) ListResourceConsumption(ctx context.Context) (*ListResourceConsumption, error) { + url := "/cloudapi/rg/listResourceConsumption" + + res, err := r.client.DecortApiCall(ctx, http.MethodPost, url, nil) + if err != nil { + return nil, err + } + + list := ListResourceConsumption{} + + err = json.Unmarshal(res, &list) + if err != nil { + return nil, err + } + + return &list, nil +} diff --git a/pkg/cloudapi/rg/models.go b/pkg/cloudapi/rg/models.go index bc6c196..74eb40a 100644 --- a/pkg/cloudapi/rg/models.go +++ b/pkg/cloudapi/rg/models.go @@ -9,7 +9,7 @@ type Resource struct { DiskSize float64 `json:"disksize"` // Max disk size - DiskSizeMax uint64 `json:"disksizemax"` + DiskSizeMax float64 `json:"disksizemax"` // Number of External IPs ExtIPs int64 `json:"extips"` @@ -33,7 +33,7 @@ type DiskUsage struct { DiskSize float64 `json:"disksize"` // Disk size max - DiskSizeMax uint64 `json:"disksizemax"` + DiskSizeMax float64 `json:"disksizemax"` } // Information about resources @@ -45,11 +45,26 @@ type Resources struct { Reserved Resource `json:"Reserved"` } +// Detailed information about resource consumption +type ItemResourceConsumption struct { + // Consumed information about resources + Consumed Resource `json:"Consumed"` + + // Reserved information about resources + Reserved Resource `json:"Reserved"` + + // Resource group ID + RGID uint64 `json:"rgid"` +} + +type ListResourceConsumption struct { + Data []ItemResourceConsumption `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} + // Detailed information about resource group type RecordResourceGroup struct { - // Resources - Resources Resources `json:"Resources"` - // Account ID AccountID uint64 `json:"accountId"` @@ -232,7 +247,11 @@ type ItemResourceGroup struct { } // List of resource groups -type ListResourceGroups []ItemResourceGroup +type ListResourceGroups struct { + Data []ItemResourceGroup `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} // Main information about Access Control List type ItemACL struct { @@ -266,6 +285,9 @@ type ResourceLimits struct { // CUD CUD float64 `json:"CU_D"` + // CUDM + CUDM float64 `json:"CU_DM"` + // CUI CUI float64 `json:"CU_I"` diff --git a/pkg/cloudapi/rg/serialize.go b/pkg/cloudapi/rg/serialize.go index 070b022..0e98913 100644 --- a/pkg/cloudapi/rg/serialize.go +++ b/pkg/cloudapi/rg/serialize.go @@ -12,7 +12,7 @@ import ( // - First argument -> prefix // - Second argument -> indent func (lrg ListResourceGroups) Serialize(params ...string) (serialization.Serialized, error) { - if len(lrg) == 0 { + if len(lrg.Data) == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/rg/sorting.go b/pkg/cloudapi/rg/sorting.go index 3516660..a723a32 100644 --- a/pkg/cloudapi/rg/sorting.go +++ b/pkg/cloudapi/rg/sorting.go @@ -6,16 +6,16 @@ import "sort" // // If inverse param is set to true, the order is reversed. func (lrg ListResourceGroups) SortByCreatedTime(inverse bool) ListResourceGroups { - if len(lrg) < 2 { + if len(lrg.Data) < 2 { return lrg } - sort.Slice(lrg, func(i, j int) bool { + sort.Slice(lrg.Data, func(i, j int) bool { if inverse { - return lrg[i].CreatedTime > lrg[j].CreatedTime + return lrg.Data[i].CreatedTime > lrg.Data[j].CreatedTime } - return lrg[i].CreatedTime < lrg[j].CreatedTime + return lrg.Data[i].CreatedTime < lrg.Data[j].CreatedTime }) return lrg @@ -25,16 +25,16 @@ func (lrg ListResourceGroups) SortByCreatedTime(inverse bool) ListResourceGroups // // If inverse param is set to true, the order is reversed. func (lrg ListResourceGroups) SortByUpdatedTime(inverse bool) ListResourceGroups { - if len(lrg) < 2 { + if len(lrg.Data) < 2 { return lrg } - sort.Slice(lrg, func(i, j int) bool { + sort.Slice(lrg.Data, func(i, j int) bool { if inverse { - return lrg[i].UpdatedTime > lrg[j].UpdatedTime + return lrg.Data[i].UpdatedTime > lrg.Data[j].UpdatedTime } - return lrg[i].UpdatedTime < lrg[j].UpdatedTime + return lrg.Data[i].UpdatedTime < lrg.Data[j].UpdatedTime }) return lrg @@ -44,16 +44,16 @@ func (lrg ListResourceGroups) SortByUpdatedTime(inverse bool) ListResourceGroups // // If inverse param is set to true, the order is reversed. func (lrg ListResourceGroups) SortByDeletedTime(inverse bool) ListResourceGroups { - if len(lrg) < 2 { + if len(lrg.Data) < 2 { return lrg } - sort.Slice(lrg, func(i, j int) bool { + sort.Slice(lrg.Data, func(i, j int) bool { if inverse { - return lrg[i].DeletedTime > lrg[j].DeletedTime + return lrg.Data[i].DeletedTime > lrg.Data[j].DeletedTime } - return lrg[i].DeletedTime < lrg[j].DeletedTime + return lrg.Data[i].DeletedTime < lrg.Data[j].DeletedTime }) return lrg diff --git a/pkg/cloudapi/tasks/list.go b/pkg/cloudapi/tasks/list.go index 31d3983..2088e16 100644 --- a/pkg/cloudapi/tasks/list.go +++ b/pkg/cloudapi/tasks/list.go @@ -18,7 +18,7 @@ type ListRequest struct { } // List gets list user API tasks with status PROCESSING -func (t Tasks) List(ctx context.Context, req ListRequest) (ListTasks, error) { +func (t Tasks) List(ctx context.Context, req ListRequest) (*ListTasks, error) { url := "/cloudapi/tasks/list" res, err := t.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -33,6 +33,5 @@ func (t Tasks) List(ctx context.Context, req ListRequest) (ListTasks, error) { return nil, err } - return list, nil - + return &list, nil } diff --git a/pkg/cloudapi/tasks/models.go b/pkg/cloudapi/tasks/models.go index 8a3edfe..94bc472 100644 --- a/pkg/cloudapi/tasks/models.go +++ b/pkg/cloudapi/tasks/models.go @@ -69,9 +69,46 @@ type RecordAsyncTask struct { // Update time UpdateTime uint64 `json:"updateTime"` + // Updated by + UpdatedBy string `json:"updatedBy"` + + // Updated time + UpdatedTime uint64 `json:"updatedTime"` +} + +// Detailed information about task +type ItemAsyncTask struct { + // Audit ID + AuditID string `json:"auditId"` + + // Completed + Completed bool `json:"completed"` + + // Error + Error string `json:"error"` + + // List of logs + Log []string `json:"log"` + + // Final result + Result TaskResult `json:"result"` + + // Stage + Stage string `json:"stage"` + + // Status + Status string `json:"status"` + + // Update time + UpdateTime uint64 `json:"updateTime"` + // Updated time UpdatedTime uint64 `json:"updatedTime"` } // List of tasks -type ListTasks []RecordAsyncTask +type ListTasks struct { + Data []ItemAsyncTask `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} diff --git a/pkg/cloudapi/vins/filter.go b/pkg/cloudapi/vins/filter.go index e46092f..d635887 100644 --- a/pkg/cloudapi/vins/filter.go +++ b/pkg/cloudapi/vins/filter.go @@ -58,21 +58,23 @@ func (lv ListVINS) FilterByDeletedBy(deletedBy string) ListVINS { func (lv ListVINS) FilterFunc(predicate func(ItemVINS) bool) ListVINS { var result ListVINS - for _, item := range lv { + for _, item := range lv.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 ItemVINS // If none was found, returns an empty struct. func (lv ListVINS) FindOne() ItemVINS { - if len(lv) == 0 { + if len(lv.Data) == 0 { return ItemVINS{} } - return lv[0] + return lv.Data[0] } diff --git a/pkg/cloudapi/vins/filter_test.go b/pkg/cloudapi/vins/filter_test.go index 579e463..5d4ccba 100644 --- a/pkg/cloudapi/vins/filter_test.go +++ b/pkg/cloudapi/vins/filter_test.go @@ -3,60 +3,64 @@ package vins import "testing" var vinsItems = ListVINS{ - { - AccountID: 1, - AccountName: "std", - CreatedBy: "sample_user_1@decs3o", - CreatedTime: 1676898844, - DeletedBy: "", - DeletedTime: 0, - ExternalIP: "", - ID: 1, - Name: "vins01", - Network: "192.168.1.0/24", - RGID: 7971, - RGName: "rg_01", - Status: "ENABLED", - UpdatedBy: "", - UpdatedTime: 0, - VXLANID: 3544, - }, - { - AccountID: 2, - AccountName: "std2", - CreatedBy: "sample_user_1@decs3o", - CreatedTime: 1676898948, - DeletedBy: "", - DeletedTime: 0, - ExternalIP: "", - ID: 2, - Name: "vins02", - Network: "192.168.2.0/24", - RGID: 7972, - RGName: "rg_02", - Status: "ENABLED", - UpdatedBy: "", - UpdatedTime: 0, - VXLANID: 3545, - }, - { - AccountID: 3, - AccountName: "std3", - CreatedBy: "sample_user_2@decs3o", - CreatedTime: 1676899026, - DeletedBy: "", - DeletedTime: 0, - ExternalIP: "", - ID: 3, - Name: "vins03", - Network: "192.168.3.0/24", - RGID: 7973, - RGName: "rg_03", - Status: "DISABLED", - UpdatedBy: "", - UpdatedTime: 0, - VXLANID: 3546, + Data: []ItemVINS{ + { + AccountID: 1, + AccountName: "std", + CreatedBy: "sample_user_1@decs3o", + CreatedTime: 1676898844, + DeletedBy: "", + DeletedTime: 0, + ExternalIP: "", + ID: 1, + Name: "vins01", + Network: "192.168.1.0/24", + RGID: 7971, + RGName: "rg_01", + Status: "ENABLED", + UpdatedBy: "", + UpdatedTime: 0, + VXLANID: 3544, + }, + { + AccountID: 2, + AccountName: "std2", + CreatedBy: "sample_user_1@decs3o", + CreatedTime: 1676898948, + DeletedBy: "", + DeletedTime: 0, + ExternalIP: "", + ID: 2, + Name: "vins02", + Network: "192.168.2.0/24", + RGID: 7972, + RGName: "rg_02", + Status: "ENABLED", + UpdatedBy: "", + UpdatedTime: 0, + VXLANID: 3545, + }, + { + AccountID: 3, + AccountName: "std3", + CreatedBy: "sample_user_2@decs3o", + CreatedTime: 1676899026, + DeletedBy: "", + DeletedTime: 0, + ExternalIP: "", + ID: 3, + Name: "vins03", + Network: "192.168.3.0/24", + RGID: 7973, + RGName: "rg_03", + Status: "DISABLED", + UpdatedBy: "", + UpdatedTime: 0, + VXLANID: 3546, + }, }, + + EntryCount: 3, } func TestFilterByID(t *testing.T) { @@ -86,11 +90,11 @@ func TestFilterByAccountID(t *testing.T) { func TestFilterByCreatedBy(t *testing.T) { actual := vinsItems.FilterByCreatedBy("sample_user_1@decs3o") - 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.CreatedBy != "sample_user_1@decs3o" { t.Fatal("expected CreatedBy 'sample_user_1@decs3o', found: ", item.CreatedBy) } @@ -111,7 +115,7 @@ func TestFilterFunc(t *testing.T) { func TestSortByCreatedTime(t *testing.T) { actual := vinsItems.SortByCreatedTime(false) - if actual[0].CreatedTime != 1676898844 || actual[2].CreatedTime != 1676899026 { + if actual.Data[0].CreatedTime != 1676898844 || actual.Data[2].CreatedTime != 1676899026 { t.Fatal("expected ascending order, found descending") } } diff --git a/pkg/cloudapi/vins/list.go b/pkg/cloudapi/vins/list.go index 937b6f8..4632f53 100644 --- a/pkg/cloudapi/vins/list.go +++ b/pkg/cloudapi/vins/list.go @@ -8,6 +8,26 @@ import ( // Request struct for get list of VINSes 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 account ID + // Required: false + AccountID uint64 `url:"accountId,omitempty" json:"accountId,omitempty"` + + // Find by resource group id + // Required: false + RGID uint64 `url:"rgId,omitempty" json:"rgId,omitempty"` + + // Find by external network IP + // Required: false + ExtIP string `url:"extIp,omitempty" json:"extIp,omitempty"` + // Include deleted // Required: false IncludeDeleted bool `url:"includeDeleted,omitempty" json:"includeDeleted,omitempty"` @@ -22,7 +42,7 @@ type ListRequest struct { } // List gets list of VINSes available for current user -func (v VINS) List(ctx context.Context, req ListRequest) (ListVINS, error) { +func (v VINS) List(ctx context.Context, req ListRequest) (*ListVINS, error) { url := "/cloudapi/vins/list" res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -37,5 +57,5 @@ func (v VINS) List(ctx context.Context, req ListRequest) (ListVINS, error) { return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/vins/list_deleted.go b/pkg/cloudapi/vins/list_deleted.go index dcbb6af..cf86683 100644 --- a/pkg/cloudapi/vins/list_deleted.go +++ b/pkg/cloudapi/vins/list_deleted.go @@ -18,7 +18,7 @@ type ListDeletedRequest struct { } // ListDeleted gets list of deleted VINSes available for current user -func (v VINS) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListVINS, error) { +func (v VINS) ListDeleted(ctx context.Context, req ListDeletedRequest) (*ListVINS, error) { url := "/cloudapi/vins/listDeleted" res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -33,5 +33,5 @@ func (v VINS) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListVINS return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudapi/vins/models.go b/pkg/cloudapi/vins/models.go index e01936b..d66529e 100644 --- a/pkg/cloudapi/vins/models.go +++ b/pkg/cloudapi/vins/models.go @@ -52,7 +52,14 @@ type ItemVINS struct { } // List of VINSes -type ListVINS []ItemVINS +type ListVINS struct { + Data []ItemVINS `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} + +// List of VINSes search result +type SearchListVINS []ItemVINS // Main information about audit type ItemAudit struct { @@ -620,6 +627,12 @@ type RecordVINS struct { // Status Status string `json:"status"` + // Updated by + UpdatedBy string `json:"updatedBy"` + + // Updated time + UpdatedTime uint64 `json:"updatedTime"` + // User managed UserManaged bool `json:"userManaged"` diff --git a/pkg/cloudapi/vins/search.go b/pkg/cloudapi/vins/search.go index 0e81cc9..b5a2508 100644 --- a/pkg/cloudapi/vins/search.go +++ b/pkg/cloudapi/vins/search.go @@ -26,7 +26,7 @@ type SearchRequest struct { } // Search search VINSes -func (v VINS) Search(ctx context.Context, req SearchRequest) (ListVINS, error) { +func (v VINS) Search(ctx context.Context, req SearchRequest) (SearchListVINS, error) { url := "/cloudapi/vins/search" res, err := v.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -34,7 +34,7 @@ func (v VINS) Search(ctx context.Context, req SearchRequest) (ListVINS, error) { return nil, err } - list := ListVINS{} + list := SearchListVINS{} err = json.Unmarshal(res, &list) if err != nil { diff --git a/pkg/cloudapi/vins/serialize.go b/pkg/cloudapi/vins/serialize.go index 7ff8242..adbe5bb 100644 --- a/pkg/cloudapi/vins/serialize.go +++ b/pkg/cloudapi/vins/serialize.go @@ -12,7 +12,7 @@ import ( // - First argument -> prefix // - Second argument -> indent func (lv ListVINS) Serialize(params ...string) (serialization.Serialized, error) { - if len(lv) == 0 { + if len(lv.Data) == 0 { return []byte{}, nil } diff --git a/pkg/cloudapi/vins/sorting.go b/pkg/cloudapi/vins/sorting.go index df7c7c0..80d898c 100644 --- a/pkg/cloudapi/vins/sorting.go +++ b/pkg/cloudapi/vins/sorting.go @@ -6,16 +6,16 @@ import "sort" // // If inverse param is set to true, the order is reversed. func (lv ListVINS) SortByCreatedTime(inverse bool) ListVINS { - if len(lv) < 2 { + if len(lv.Data) < 2 { return lv } - sort.Slice(lv, func(i, j int) bool { + sort.Slice(lv.Data, func(i, j int) bool { if inverse { - return lv[i].CreatedTime > lv[j].CreatedTime + return lv.Data[i].CreatedTime > lv.Data[j].CreatedTime } - return lv[i].CreatedTime < lv[j].CreatedTime + return lv.Data[i].CreatedTime < lv.Data[j].CreatedTime }) return lv @@ -25,16 +25,16 @@ func (lv ListVINS) SortByCreatedTime(inverse bool) ListVINS { // // If inverse param is set to true, the order is reversed. func (lv ListVINS) SortByUpdatedTime(inverse bool) ListVINS { - if len(lv) < 2 { + if len(lv.Data) < 2 { return lv } - sort.Slice(lv, func(i, j int) bool { + sort.Slice(lv.Data, func(i, j int) bool { if inverse { - return lv[i].UpdatedTime > lv[j].UpdatedTime + return lv.Data[i].UpdatedTime > lv.Data[j].UpdatedTime } - return lv[i].UpdatedTime < lv[j].UpdatedTime + return lv.Data[i].UpdatedTime < lv.Data[j].UpdatedTime }) return lv @@ -44,16 +44,16 @@ func (lv ListVINS) SortByUpdatedTime(inverse bool) ListVINS { // // If inverse param is set to true, the order is reversed. func (lv ListVINS) SortByDeletedTime(inverse bool) ListVINS { - if len(lv) < 2 { + if len(lv.Data) < 2 { return lv } - sort.Slice(lv, func(i, j int) bool { + sort.Slice(lv.Data, func(i, j int) bool { if inverse { - return lv[i].DeletedTime > lv[j].DeletedTime + return lv.Data[i].DeletedTime > lv.Data[j].DeletedTime } - return lv[i].DeletedTime < lv[j].DeletedTime + return lv.Data[i].DeletedTime < lv.Data[j].DeletedTime }) return lv diff --git a/pkg/cloudbroker/account/delete.go b/pkg/cloudbroker/account/delete.go index fbf98ab..3becf47 100644 --- a/pkg/cloudbroker/account/delete.go +++ b/pkg/cloudbroker/account/delete.go @@ -14,8 +14,8 @@ type DeleteRequest struct { AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` // Reason to delete - // Required: true - Reason string `url:"reason" json:"reason" validate:"required"` + // Required: false + Reason string `url:"reason,omitempty" json:"reason,omitempty"` // Whether to completely delete the account // Required: false diff --git a/pkg/cloudbroker/account/delete_accounts.go b/pkg/cloudbroker/account/delete_accounts.go index a5c10a7..6ef2d7c 100644 --- a/pkg/cloudbroker/account/delete_accounts.go +++ b/pkg/cloudbroker/account/delete_accounts.go @@ -14,8 +14,8 @@ type DeleteAccountsRequest struct { AccountsIDs []uint64 `url:"accountIds" json:"accountIds" validate:"min=1"` // Reason for deletion - // Required: true - Reason string `url:"reason" json:"reason" validate:"required"` + // Required: false + Reason string `url:"reason,omitempty" json:"reason,omitempty"` // Whether to completely destroy accounts or not // Required: false diff --git a/pkg/cloudbroker/account/filter.go b/pkg/cloudbroker/account/filter.go index a54f554..bf1c60b 100644 --- a/pkg/cloudbroker/account/filter.go +++ b/pkg/cloudbroker/account/filter.go @@ -1,34 +1,34 @@ package account -// FilterByID returns ListAccounts with specified ID. -func (la ListAccounts) FilterByID(id uint64) ListAccounts { +// FilterByID returns ListDeleted with specified ID. +func (ld ListDeleted) FilterByID(id uint64) ListDeleted { predicate := func(ia ItemAccount) bool { return ia.ID == id } - return la.FilterFunc(predicate) + return ld.FilterFunc(predicate) } -// FilterByName returns ListAccounts with specified Name. -func (la ListAccounts) FilterByName(name string) ListAccounts { +// FilterByName returns ListDeleted with specified Name. +func (ld ListDeleted) FilterByName(name string) ListDeleted { predicate := func(ia ItemAccount) bool { return ia.Name == name } - return la.FilterFunc(predicate) + return ld.FilterFunc(predicate) } -// FilterByStatus returns ListAccounts with specified Status. -func (la ListAccounts) FilterByStatus(status string) ListAccounts { +// FilterByStatus returns ListDeleted with specified Status. +func (ld ListDeleted) FilterByStatus(status string) ListDeleted { predicate := func(ia ItemAccount) bool { return ia.Status == status } - return la.FilterFunc(predicate) + return ld.FilterFunc(predicate) } -// FilterByUserGroupID returns ListAccounts with specified UserGroupID. -func (la ListAccounts) FilterByUserGroupID(userGroupID string) ListAccounts { +// FilterByUserGroupID returns ListDeleted with specified UserGroupID. +func (ld ListDeleted) FilterByUserGroupID(userGroupID string) ListDeleted { predicate := func(ia ItemAccount) bool { acl := ia.ACL @@ -41,32 +41,32 @@ func (la ListAccounts) FilterByUserGroupID(userGroupID string) ListAccounts { return false } - return la.FilterFunc(predicate) + return ld.FilterFunc(predicate) } -// FilterByCompany returns ListAccounts with specified Company. -func (la ListAccounts) FilterByCompany(company string) ListAccounts { +// FilterByCompany returns ListDeleted with specified Company. +func (ld ListDeleted) FilterByCompany(company string) ListDeleted { predicate := func(ia ItemAccount) bool { return ia.Company == company } - return la.FilterFunc(predicate) + return ld.FilterFunc(predicate) } -// FilterByCreatedBy returns ListAccounts created by specified user. -func (la ListAccounts) FilterByCreatedBy(createdBy string) ListAccounts { +// FilterByCreatedBy returns ListDeleted created by specified user. +func (ld ListDeleted) FilterByCreatedBy(createdBy string) ListDeleted { predicate := func(ia ItemAccount) bool { return ia.CreatedBy == createdBy } - return la.FilterFunc(predicate) + return ld.FilterFunc(predicate) } -// FilterFunc allows filtering ListAccounts based on a user-specified predicate. -func (la ListAccounts) FilterFunc(predicate func(ItemAccount) bool) ListAccounts { - var result ListAccounts +// FilterFunc allows filtering ListDeleted based on a user-specified predicate. +func (ld ListDeleted) FilterFunc(predicate func(ItemAccount) bool) ListDeleted { + var result ListDeleted - for _, item := range la { + for _, item := range ld { if predicate(item) { result = append(result, item) } @@ -77,10 +77,10 @@ func (la ListAccounts) FilterFunc(predicate func(ItemAccount) bool) ListAccounts // FindOne returns first found ItemAccount. // If none was found, returns an empty struct. -func (la ListAccounts) FindOne() ItemAccount { - if len(la) == 0 { +func (ld ListDeleted) FindOne() ItemAccount { + if len(ld) == 0 { return ItemAccount{} } - return la[0] + return ld[0] } diff --git a/pkg/cloudbroker/account/filter_test.go b/pkg/cloudbroker/account/filter_test.go index f8ae94a..f12ec4c 100644 --- a/pkg/cloudbroker/account/filter_test.go +++ b/pkg/cloudbroker/account/filter_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -var accounts = ListAccounts{ +var accounts = ListDeleted{ ItemAccount{ Meta: []interface{}{}, InfoAccount: InfoAccount{ diff --git a/pkg/cloudbroker/account/get_resource_consumption.go b/pkg/cloudbroker/account/get_resource_consumption.go new file mode 100644 index 0000000..67285d2 --- /dev/null +++ b/pkg/cloudbroker/account/get_resource_consumption.go @@ -0,0 +1,42 @@ +package account + +import ( + "context" + "encoding/json" + "net/http" + + "repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators" +) + +// Request struct for getting resource consumption +type GetResourceConsumptionRequest struct { + // ID an account + // Required: true + AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` +} + +// 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) { + err := validators.ValidateRequest(req) + if err != nil { + for _, validationError := range validators.GetErrors(err) { + return nil, validators.ValidationError(validationError) + } + } + + url := "/cloudbroker/account/getResourceConsumption" + + info := RecordResources{} + + res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) + if err != nil { + return nil, err + } + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudbroker/account/list.go b/pkg/cloudbroker/account/list.go index 03f5245..136fd8b 100644 --- a/pkg/cloudbroker/account/list.go +++ b/pkg/cloudbroker/account/list.go @@ -8,6 +8,22 @@ import ( // Request struct for get list of accounts type ListRequest struct { + // Find by ID + // Required: false + ByID uint64 `url:"by_id" json:"by_id"` + + // Find by name + // Required: false + Name string `urL:"name" json:"name"` + + // Find by access control list + // Required: false + ACL string `url:"acl" json:"acl"` + + // Find by status + // Required: false + Status string `url:"status" json:"status"` + // Page number // Required: false Page uint64 `url:"page" json:"page"` @@ -18,7 +34,7 @@ type ListRequest struct { } // List gets list all accounts the user has access to -func (a Account) List(ctx context.Context, req ListRequest) (ListAccounts, error) { +func (a Account) List(ctx context.Context, req ListRequest) (*ListAccounts, error) { url := "/cloudbroker/account/list" res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -33,5 +49,5 @@ func (a Account) List(ctx context.Context, req ListRequest) (ListAccounts, error return nil, err } - return list, nil + return &list, nil } diff --git a/pkg/cloudbroker/account/list_deleted.go b/pkg/cloudbroker/account/list_deleted.go index a096a90..5b65e59 100644 --- a/pkg/cloudbroker/account/list_deleted.go +++ b/pkg/cloudbroker/account/list_deleted.go @@ -18,7 +18,7 @@ type ListDeletedRequest struct { } // ListDeleted gets list all deleted accounts the user has access to -func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListAccounts, error) { +func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListDeleted, error) { url := "/cloudbroker/account/listDeleted" res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, req) @@ -26,7 +26,7 @@ func (a Account) ListDeleted(ctx context.Context, req ListDeletedRequest) (ListA return nil, err } - list := ListAccounts{} + list := ListDeleted{} err = json.Unmarshal(res, &list) if err != nil { diff --git a/pkg/cloudbroker/account/list_resource_consumption.go b/pkg/cloudbroker/account/list_resource_consumption.go new file mode 100644 index 0000000..29d8b34 --- /dev/null +++ b/pkg/cloudbroker/account/list_resource_consumption.go @@ -0,0 +1,26 @@ +package account + +import ( + "context" + "encoding/json" + "net/http" +) + +// ListResourceConsumption show data list amount of consumed and reserved resources (cpu, ram, disk) by specific accounts +func (a Account) ListResourceConsumption(ctx context.Context) (*ListResources, error) { + url := "/cloudbroker/account/listResourceConsumption" + + info := ListResources{} + + res, err := a.client.DecortApiCall(ctx, http.MethodPost, url, nil) + if err != nil { + return nil, err + } + + err = json.Unmarshal(res, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/cloudbroker/account/models.go b/pkg/cloudbroker/account/models.go index 21ba071..39382fd 100644 --- a/pkg/cloudbroker/account/models.go +++ b/pkg/cloudbroker/account/models.go @@ -27,6 +27,17 @@ type RecordResources struct { // Reserved information about resources Reserved Resource `json:"Reserved"` + + // ID of account + AccountID uint64 `json:"id"` +} + +type ListResources struct { + // Data + Data []RecordResources `json:"data"` + + // Entry count + EntryCount uint64 `json:"entryCount"` } type Resource struct { @@ -61,7 +72,7 @@ type DiskUsage struct { DiskSize float64 `json:"disksize"` // Disk size max - DiskSizeMax uint64 `json:"disksizemax"` + DiskSizeMax float64 `json:"disksizemax"` } // Access Control List @@ -87,12 +98,15 @@ type ACL struct { // Resource limits type ResourceLimits struct { - // CuC + // CuC CuC float64 `json:"CU_C"` // CuD CuD float64 `json:"CU_D"` + // CuDM + CuDM float64 `json:"CU_DM"` + // CuI CuI float64 `json:"CU_I"` @@ -183,9 +197,6 @@ type InfoAccount struct { // Deatailed information about account type RecordAccount struct { - // Resources - Resources RecordResources `json:"Resources"` - // Main information about account InfoAccount } @@ -200,7 +211,14 @@ type ItemAccount struct { } // List of accounts -type ListAccounts []ItemAccount +type ListDeleted []ItemAccount + +// List of accounts +type ListAccounts struct { + Data []ItemAccount `json:"data"` + + EntryCount uint64 `json:"entryCount"` +} // List of computes type ListComputes []ItemCompute @@ -379,7 +397,7 @@ type Consumed struct { CPU uint64 `json:"cpu"` // Disk size - DiskSize uint64 `json:"disksize"` + DiskSize float64 `json:"disksize"` // Disk size max DiskSizeMax int64 `json:"disksizemax"` diff --git a/pkg/cloudbroker/account/restore.go b/pkg/cloudbroker/account/restore.go index 7dd697a..edf2d5a 100644 --- a/pkg/cloudbroker/account/restore.go +++ b/pkg/cloudbroker/account/restore.go @@ -14,8 +14,8 @@ type RestoreRequest struct { AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` // Reason to restore - // Required: true - Reason string `url:"reason" json:"reason" validate:"required"` + // Required: false + Reason string `url:"reason,omitempty" json:"reason,omitempty"` } // Restore restores a deleted account diff --git a/pkg/cloudbroker/account/serialize.go b/pkg/cloudbroker/account/serialize.go index 8ee25ca..d2bcfda 100644 --- a/pkg/cloudbroker/account/serialize.go +++ b/pkg/cloudbroker/account/serialize.go @@ -6,13 +6,33 @@ import ( "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 (ld ListDeleted) Serialize(params ...string) (serialization.Serialized, error) { + if len(ld) == 0 { + return []byte{}, nil + } + + if len(params) > 1 { + prefix := params[0] + indent := params[1] + + return json.MarshalIndent(ld, prefix, indent) + } + + return json.Marshal(ld) +} + // 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 (la ListAccounts) Serialize(params ...string) (serialization.Serialized, error) { - if len(la) == 0 { + if la.EntryCount == 0 { return []byte{}, nil } diff --git a/pkg/cloudbroker/account/sorting.go b/pkg/cloudbroker/account/sorting.go index daf5ffd..0f959c8 100644 --- a/pkg/cloudbroker/account/sorting.go +++ b/pkg/cloudbroker/account/sorting.go @@ -2,20 +2,77 @@ package account import "sort" +// SortByCreatedTime sorts ListDeleted by the CreatedTime field in ascending order. +// +// If inverse param is set to true, the order is reversed. +func (ld ListDeleted) SortByCreatedTime(inverse bool) ListDeleted { + if len(ld) < 2 { + return ld + } + + sort.Slice(ld, func(i, j int) bool { + if inverse { + return ld[i].CreatedTime > ld[j].CreatedTime + } + + return ld[i].CreatedTime < ld[j].CreatedTime + }) + + return ld +} + +// SortByUpdatedTime sorts ListDeleted by the UpdatedTime field in ascending order. +// +// If inverse param is set to true, the order is reversed. +func (ld ListDeleted) SortByUpdatedTime(inverse bool) ListDeleted { + if len(ld) < 2 { + return ld + } + + sort.Slice(ld, func(i, j int) bool { + if inverse { + return ld[i].UpdatedTime > ld[j].UpdatedTime + } + + return ld[i].UpdatedTime < ld[j].UpdatedTime + }) + + return ld +} + +// SortByDeletedTime sorts ListDeleted by the DeletedTime field in ascending order. +// +// If inverse param is set to true, the order is reversed. +func (ld ListDeleted) SortByDeletedTime(inverse bool) ListDeleted { + if len(ld) < 2 { + return ld + } + + sort.Slice(ld, func(i, j int) bool { + if inverse { + return ld[i].DeletedTime > ld[j].DeletedTime + } + + return ld[i].DeletedTime < ld[j].DeletedTime + }) + + return ld +} + // SortByCreatedTime sorts ListAccounts by the CreatedTime field in ascending order. // // If inverse param is set to true, the order is reversed. func (la ListAccounts) SortByCreatedTime(inverse bool) ListAccounts { - if len(la) < 2 { + if la.EntryCount < 2 { return la } - sort.Slice(la, func(i, j int) bool { + sort.Slice(la.Data, func(i, j int) bool { if inverse { - return la[i].CreatedTime > la[j].CreatedTime + return la.Data[i].CreatedTime > la.Data[j].CreatedTime } - return la[i].CreatedTime < la[j].CreatedTime + return la.Data[i].CreatedTime < la.Data[j].CreatedTime }) return la @@ -25,35 +82,35 @@ func (la ListAccounts) SortByCreatedTime(inverse bool) ListAccounts { // // If inverse param is set to true, the order is reversed. func (la ListAccounts) SortByUpdatedTime(inverse bool) ListAccounts { - if len(la) < 2 { + if la.EntryCount < 2 { return la } - sort.Slice(la, func(i, j int) bool { + sort.Slice(la.Data, func(i, j int) bool { if inverse { - return la[i].UpdatedTime > la[j].UpdatedTime + return la.Data[i].UpdatedTime > la.Data[j].UpdatedTime } - return la[i].UpdatedTime < la[j].UpdatedTime + return la.Data[i].UpdatedTime < la.Data[j].UpdatedTime }) return la } -// SortByDeletedTime sorts ListAccounts by the DeletedTime field in ascending order. +// SortByDeletedTime sorts LisAccounts by the DeletedTime field in ascending order. // // If inverse param is set to true, the order is reversed. func (la ListAccounts) SortByDeletedTime(inverse bool) ListAccounts { - if len(la) < 2 { + if la.EntryCount < 2 { return la } - sort.Slice(la, func(i, j int) bool { + sort.Slice(la.Data, func(i, j int) bool { if inverse { - return la[i].DeletedTime > la[j].DeletedTime + return la.Data[i].DeletedTime > la.Data[j].DeletedTime } - return la[i].DeletedTime < la[j].DeletedTime + return la.Data[i].DeletedTime < la.Data[j].DeletedTime }) return la diff --git a/pkg/cloudbroker/account/update.go b/pkg/cloudbroker/account/update.go index 72f71fb..12e00ff 100644 --- a/pkg/cloudbroker/account/update.go +++ b/pkg/cloudbroker/account/update.go @@ -14,17 +14,9 @@ type UpdateRequest struct { // Required: true AccountID uint64 `url:"accountId" json:"accountId" validate:"required"` - // Display name - // Required: false - Name string `url:"name" json:"name"` - // Name of the account - // Required: true - Username string `url:"username,omitempty" json:"username,omitempty"` - - // Email // Required: false - EmailAddress string `url:"emailaddress,omitempty" json:"emailaddress,omitempty" validate:"omitempty,email"` + Name string `url:"name" json:"name"` // Max size of memory in MB // Required: false