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

move LIQUID client implementation to go-bits #595

Merged
merged 2 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/prometheus/common v0.60.1
github.com/rs/cors v1.11.1
github.com/sapcc/go-api-declarations v1.12.9
github.com/sapcc/go-bits v0.0.0-20241030155708-d3f315057be8
github.com/sapcc/go-bits v0.0.0-20241105152144-8029a9fd2533
go.uber.org/automaxprocs v1.6.0
gopkg.in/yaml.v2 v2.4.0
)
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/sapcc/go-api-declarations v1.12.9 h1:4CWkt333oQxGnbka1TH4qApC0bxZe+WIBduygEcxiNw=
github.com/sapcc/go-api-declarations v1.12.9/go.mod h1:83R3hTANhuRXt/pXDby37IJetw8l7DG41s33Tp9NXxI=
github.com/sapcc/go-bits v0.0.0-20241030155708-d3f315057be8 h1:vKnI1g8PD7vU/3krdUcYftH8Yt9c4uCHyEIyxkPhiYU=
github.com/sapcc/go-bits v0.0.0-20241030155708-d3f315057be8/go.mod h1:edzu9ZBNooNFNX1J70nkhV2cOibYvADvr4C39K0stbc=
github.com/sapcc/go-bits v0.0.0-20241105152144-8029a9fd2533 h1:3+cnJz40Y0nmIY8I7Aln5n8318pZ7YEtn5g4ovlZ1+A=
github.com/sapcc/go-bits v0.0.0-20241105152144-8029a9fd2533/go.mod h1:edzu9ZBNooNFNX1J70nkhV2cOibYvADvr4C39K0stbc=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
Expand Down
8 changes: 6 additions & 2 deletions internal/plugins/capacity_liquid.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/sapcc/go-api-declarations/limes"
"github.com/sapcc/go-api-declarations/liquid"
"github.com/sapcc/go-bits/liquidapi"
"github.com/sapcc/go-bits/logg"

"github.com/sapcc/limes/internal/core"
Expand All @@ -42,7 +43,7 @@ type liquidCapacityPlugin struct {

// state
LiquidServiceInfo liquid.ServiceInfo `yaml:"-"`
LiquidClient *LiquidV1Client `yaml:"-"`
LiquidClient *liquidapi.Client `yaml:"-"`
}

func init() {
Expand All @@ -63,7 +64,10 @@ func (p *liquidCapacityPlugin) Init(ctx context.Context, client *gophercloud.Pro
p.LiquidServiceType = "liquid-" + string(p.ServiceType)
}

p.LiquidClient, err = NewLiquidV1(client, eo, p.LiquidServiceType, p.EndpointOverride)
p.LiquidClient, err = liquidapi.NewClient(client, eo, liquidapi.ClientOpts{
ServiceType: p.LiquidServiceType,
EndpointOverride: p.EndpointOverride,
})
if err != nil {
return fmt.Errorf("cannot initialize ServiceClient for %s: %w", p.LiquidServiceType, err)
}
Expand Down
88 changes: 0 additions & 88 deletions internal/plugins/client_liquid.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,102 +20,14 @@
package plugins

import (
"context"
"encoding/json"
"fmt"
"net/http"
"slices"

"github.com/gophercloud/gophercloud/v2"
"github.com/prometheus/client_golang/prometheus"
"github.com/sapcc/go-api-declarations/liquid"
)

type LiquidV1Client struct {
gophercloud.ServiceClient
}

// NewLiquidV1 creates a ServiceClient for interacting with a liquid.
// Ref: <https://pkg.go.dev/github.com/sapcc/go-api-declarations/liquid>
func NewLiquidV1(client *gophercloud.ProviderClient, endpointOpts gophercloud.EndpointOpts, liquidServiceType, endpointOverride string) (*LiquidV1Client, error) {
var (
endpoint string
err error
)
if endpointOverride == "" {
endpointOpts.ApplyDefaults(liquidServiceType)
endpoint, err = client.EndpointLocator(endpointOpts)
if err != nil {
return nil, err
}
} else {
endpoint = endpointOverride
}

return &LiquidV1Client{
ServiceClient: gophercloud.ServiceClient{
ProviderClient: client,
Endpoint: endpoint,
Type: liquidServiceType,
},
}, nil
}

// GetInfo executes GET /v1/info.
func (c *LiquidV1Client) GetInfo(ctx context.Context) (result liquid.ServiceInfo, err error) {
url := c.ServiceURL("v1", "info")
opts := gophercloud.RequestOpts{KeepResponseBody: true}
resp, err := c.Get(ctx, url, nil, &opts)
if err == nil {
err = parseLiquidResponse(resp, &result)
}
return
}

// GetCapacityReport executes POST /v1/report-capacity.
func (c *LiquidV1Client) GetCapacityReport(ctx context.Context, req liquid.ServiceCapacityRequest) (result liquid.ServiceCapacityReport, err error) {
url := c.ServiceURL("v1", "report-capacity")
opts := gophercloud.RequestOpts{KeepResponseBody: true, OkCodes: []int{http.StatusOK}}
resp, err := c.Post(ctx, url, req, nil, &opts)
if err == nil {
err = parseLiquidResponse(resp, &result)
}
return
}

// GetUsageReport executes POST /v1/projects/:uuid/report-usage.
func (c *LiquidV1Client) GetUsageReport(ctx context.Context, projectUUID string, req liquid.ServiceUsageRequest) (result liquid.ServiceUsageReport, err error) {
url := c.ServiceURL("v1", "projects", projectUUID, "report-usage")
opts := gophercloud.RequestOpts{KeepResponseBody: true, OkCodes: []int{http.StatusOK}}
resp, err := c.Post(ctx, url, req, nil, &opts)
if err == nil {
err = parseLiquidResponse(resp, &result)
}
return
}

// PutQuota executes PUT /v1/projects/:uuid/quota.
func (c *LiquidV1Client) PutQuota(ctx context.Context, projectUUID string, req liquid.ServiceQuotaRequest) (err error) {
url := c.ServiceURL("v1", "projects", projectUUID, "quota")
opts := gophercloud.RequestOpts{KeepResponseBody: true, OkCodes: []int{http.StatusNoContent}}
_, err = c.Put(ctx, url, req, nil, &opts) //nolint:bodyclose // either the response is 204 and does not have a body, or it's an error and Gophercloud does a ReadAll() internally
return
}

// We do not use the standard response body parsing from Gophercloud
// because we want to be strict and DisallowUnknownFields().
func parseLiquidResponse(resp *http.Response, result any) error {
defer resp.Body.Close()
dec := json.NewDecoder(resp.Body)
dec.DisallowUnknownFields()
err := dec.Decode(&result)
if err != nil {
return fmt.Errorf("could not parse response body from %s %s: %w",
resp.Request.Method, resp.Request.URL.String(), err)
}
return nil
}

// Plugin-internal serialization format for metrics (see Scrape() and CollectMetrics()).
//
// When storing metrics from LIQUID in the Limes DB, we must also store parts of the
Expand Down
8 changes: 6 additions & 2 deletions internal/plugins/liquid.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/sapcc/go-api-declarations/limes"
"github.com/sapcc/go-api-declarations/liquid"
"github.com/sapcc/go-bits/liquidapi"
"github.com/sapcc/go-bits/logg"

"github.com/sapcc/limes/internal/core"
Expand All @@ -52,7 +53,7 @@ type liquidQuotaPlugin struct {

// state
LiquidServiceInfo liquid.ServiceInfo `yaml:"-"`
LiquidClient *LiquidV1Client `yaml:"-"`
LiquidClient *liquidapi.Client `yaml:"-"`
}

func init() {
Expand All @@ -74,7 +75,10 @@ func (p *liquidQuotaPlugin) Init(ctx context.Context, client *gophercloud.Provid
p.LiquidServiceType = "liquid-" + string(p.ServiceType)
}

p.LiquidClient, err = NewLiquidV1(client, eo, p.LiquidServiceType, p.EndpointOverride)
p.LiquidClient, err = liquidapi.NewClient(client, eo, liquidapi.ClientOpts{
ServiceType: p.LiquidServiceType,
EndpointOverride: p.EndpointOverride,
})
if err != nil {
return fmt.Errorf("cannot initialize ServiceClient for liquid-%s: %w", serviceType, err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/plugins/nova.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func (p *novaPlugin) Init(ctx context.Context, provider *gophercloud.ProviderCli
func getDefaultQuotaClassSet(ctx context.Context, novaV2 *gophercloud.ServiceClient) (map[string]any, error) {
url := novaV2.ServiceURL("os-quota-class-sets", "default")
var result gophercloud.Result
_, err := novaV2.Get(ctx, url, &result.Body, nil) //nolint:bodyclose // already closed by gophercloud
_, err := novaV2.Get(ctx, url, &result.Body, nil)
if err != nil {
return nil, err
}
Expand Down
13 changes: 9 additions & 4 deletions vendor/github.com/sapcc/go-bits/gopherpolicy/pkg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

164 changes: 164 additions & 0 deletions vendor/github.com/sapcc/go-bits/gopherpolicy/serialize.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading