Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sdk): qos #124

Merged
merged 19 commits into from
Jan 21, 2025
148 changes: 148 additions & 0 deletions internal/sdk/cloudian/qos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package cloudian

import (
"context"
"encoding/json"
"fmt"
"strconv"
)

// QualityOfService configures data limits for a Group or User.
type QualityOfService struct {
// Warning is the soft limit that triggers a warning.
Warning QualityOfServiceLimits
// Hard is the hard limit.
Hard QualityOfServiceLimits
}

// QualityOfService configures data limits.
type QualityOfServiceLimits struct {
// StorageQuotaKiBs is the limit for total stored data in KiB.
StorageQuotaKiBs *int64
// StorageQuotaCount is the limit for total number of objects.
StorageQuotaCount *int64
// RequestsPerMin is the limit for number of HTTP requests per minute.
RequestsPerMin *int64
// InboundKiBsPerMin is the limit for inbound data per minute in KiB.
InboundKiBsPerMin *int64
// OutboundKiBsPerMin is the limit for outbound data per minute in KiB.
OutboundKiBsPerMin *int64
}

// nolint: gocyclo
func (qos *QualityOfService) unmarshalQOSList(raw []byte) error {
var data struct {
QOSLimitList []struct {
Type string `json:"type"`
Value int64 `json:"value"`
} `json:"qosLimitList"`
}

if err := json.Unmarshal(raw, &data); err != nil {
return err
}

for _, item := range data.QOSLimitList {
v := &item.Value
switch item.Type {
case "STORAGE_QUOTA_KBYTES_LH":
qos.Hard.StorageQuotaKiBs = v
case "STORAGE_QUOTA_KBYTES_LW":
qos.Warning.StorageQuotaKiBs = v
case "STORAGE_QUOTA_COUNT_LH":
qos.Hard.StorageQuotaCount = v
case "STORAGE_QUOTA_COUNT_LW":
qos.Warning.StorageQuotaCount = v
case "REQUEST_RATE_LH":
qos.Hard.RequestsPerMin = v
case "REQUEST_RATE_LW":
qos.Warning.RequestsPerMin = v
case "DATAKBYTES_IN_LH":
qos.Hard.InboundKiBsPerMin = v
case "DATAKBYTES_IN_LW":
qos.Warning.InboundKiBsPerMin = v
case "DATAKBYTES_OUT_LH":
qos.Hard.OutboundKiBsPerMin = v
case "DATAKBYTES_OUT_LW":
qos.Warning.OutboundKiBsPerMin = v
}
}
return nil
}

func (qos *QualityOfService) queryParams(params map[string]string) error {
rawParams := map[string]*int64{
"hlStorageQuotaKBytes": qos.Hard.StorageQuotaKiBs,
"wlStorageQuotaKBytes": qos.Warning.StorageQuotaKiBs,
"hlStorageQuotaCount": qos.Hard.StorageQuotaCount,
"wlStorageQuotaCount": qos.Warning.StorageQuotaCount,
"hlRequestRate": qos.Hard.RequestsPerMin,
"wlRequestRate": qos.Warning.RequestsPerMin,
"hlDataKBytesIn": qos.Hard.InboundKiBsPerMin,
"wlDataKBytesIn": qos.Warning.InboundKiBsPerMin,
"hlDataKBytesOut": qos.Hard.OutboundKiBsPerMin,
"wlDataKBytesOut": qos.Warning.OutboundKiBsPerMin,
}

for key, raw := range rawParams {
val := int64(-1)
if raw != nil {
val = *raw
}
if val < -1 {
return fmt.Errorf("invalid QoS limit value: %d", val)
}
params[key] = strconv.FormatInt(val, 10)
tenstad marked this conversation as resolved.
Show resolved Hide resolved
}
return nil
}

// SetQOS sets QualityOfService limits for a Group or User, depending on the value of GroupID and UserID.
//
// User-level QoS for a specific user (GroupID="<groupId>", UserID="<userId>")
// Default user-level QoS for a specific group (GroupID="<groupId>", UserID="ALL")
// Default user-level QoS for the whole region (GroupID="*", UserID="ALL")
// Group-level QoS for a specific group (GroupID="<groupId>", UserID="*")
// Default group-level QoS for the whole region (GroupID="ALL", UserID="*")
func (client Client) SetQOS(ctx context.Context, user User, qos QualityOfService) error {
params := make(map[string]string)
if err := qos.queryParams(params); err != nil {
return err
}

resp, err := client.newRequest(ctx).
SetQueryParam("userId", user.UserID).
SetQueryParam("groupId", user.GroupID).
SetQueryParams(params).
Post("/qos/limits")
if err != nil {
return err
}

switch resp.StatusCode() {
case 200:
return nil
default:
return fmt.Errorf("POST quota unexpected status: %d", resp.StatusCode())
}
}

// SetQOS gets QualityOfService limits for a Group or User, depending on the value of GroupID and UserID.
// See SetQOS for details.
func (client Client) GetQOS(ctx context.Context, user User) (*QualityOfService, error) {
resp, err := client.newRequest(ctx).
SetQueryParam("userId", user.UserID).
SetQueryParam("groupId", user.GroupID).
Get("/qos/limits")
if err != nil {
return nil, err
}

switch resp.StatusCode() {
case 200:
qos := &QualityOfService{}
return qos, qos.unmarshalQOSList(resp.Body())
default:
return nil, fmt.Errorf("GET quota unexpected status: %d", resp.StatusCode())
}
}
Loading