2022-09-05 03:06:08 -04:00
|
|
|
/*
|
|
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
2022-08-16 10:06:38 -04:00
|
|
|
package license
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// CommunityLicense is used by everyone who has not bought an enterprise license.
|
|
|
|
CommunityLicense = "00000000-0000-0000-0000-000000000000"
|
2022-08-25 08:06:29 -04:00
|
|
|
apiHost = "license.confidential.cloud"
|
|
|
|
licensePath = "api/v1/license"
|
2022-08-16 10:06:38 -04:00
|
|
|
)
|
|
|
|
|
2022-09-08 05:02:04 -04:00
|
|
|
type (
|
2022-11-09 09:57:54 -05:00
|
|
|
// Action performed by Constellation.
|
2022-09-08 05:02:04 -04:00
|
|
|
Action string
|
|
|
|
)
|
2022-08-16 10:06:38 -04:00
|
|
|
|
|
|
|
const (
|
2022-11-09 09:57:54 -05:00
|
|
|
// Init action denotes the initialization of a Constellation cluster.
|
2022-08-16 10:06:38 -04:00
|
|
|
Init Action = "init"
|
2022-11-09 09:57:54 -05:00
|
|
|
// test action is only to be used in testing.
|
2022-08-16 10:06:38 -04:00
|
|
|
test Action = "test"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Client interacts with the ES license server.
|
|
|
|
type Client struct {
|
|
|
|
httpClient *http.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewClient creates a new client to interact with ES license server.
|
|
|
|
func NewClient() *Client {
|
|
|
|
return &Client{
|
|
|
|
httpClient: http.DefaultClient,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-25 08:06:29 -04:00
|
|
|
// QuotaCheckRequest is JSON request to license server to check quota for a given license and action.
|
|
|
|
type QuotaCheckRequest struct {
|
2022-09-08 05:02:04 -04:00
|
|
|
Action Action `json:"action"`
|
|
|
|
Provider string `json:"provider"`
|
|
|
|
License string `json:"license"`
|
2022-08-16 10:06:38 -04:00
|
|
|
}
|
|
|
|
|
2022-08-25 08:06:29 -04:00
|
|
|
// QuotaCheckResponse is JSON response by license server.
|
|
|
|
type QuotaCheckResponse struct {
|
2022-08-16 10:06:38 -04:00
|
|
|
Quota int `json:"quota"`
|
|
|
|
}
|
|
|
|
|
2022-08-25 08:06:29 -04:00
|
|
|
// QuotaCheck for a given license and action, passed via CheckQuotaRequest.
|
|
|
|
func (c *Client) QuotaCheck(ctx context.Context, checkRequest QuotaCheckRequest) (QuotaCheckResponse, error) {
|
2022-08-16 10:06:38 -04:00
|
|
|
reqBody, err := json.Marshal(checkRequest)
|
|
|
|
if err != nil {
|
2022-08-25 08:06:29 -04:00
|
|
|
return QuotaCheckResponse{}, fmt.Errorf("unable to marshal input: %w", err)
|
2022-08-16 10:06:38 -04:00
|
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, licenseURL().String(), bytes.NewBuffer(reqBody))
|
|
|
|
if err != nil {
|
2022-08-25 08:06:29 -04:00
|
|
|
return QuotaCheckResponse{}, fmt.Errorf("unable to create request: %w", err)
|
2022-08-16 10:06:38 -04:00
|
|
|
}
|
|
|
|
resp, err := c.httpClient.Do(req)
|
|
|
|
if err != nil {
|
2022-08-25 08:06:29 -04:00
|
|
|
return QuotaCheckResponse{}, fmt.Errorf("unable to do request: %w", err)
|
2022-08-16 10:06:38 -04:00
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
2022-08-25 08:06:29 -04:00
|
|
|
return QuotaCheckResponse{}, fmt.Errorf("http error %d", resp.StatusCode)
|
2022-08-16 10:06:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
responseContentType := resp.Header.Get("Content-Type")
|
|
|
|
if responseContentType != "application/json" {
|
2022-08-25 08:06:29 -04:00
|
|
|
return QuotaCheckResponse{}, fmt.Errorf("expected server JSON response but got '%s'", responseContentType)
|
2022-08-16 10:06:38 -04:00
|
|
|
}
|
|
|
|
|
2022-08-25 08:06:29 -04:00
|
|
|
var parsedResponse QuotaCheckResponse
|
2022-08-16 10:06:38 -04:00
|
|
|
err = json.NewDecoder(resp.Body).Decode(&parsedResponse)
|
|
|
|
if err != nil {
|
2022-08-25 08:06:29 -04:00
|
|
|
return QuotaCheckResponse{}, fmt.Errorf("unable to parse response: %w", err)
|
2022-08-16 10:06:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return parsedResponse, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func licenseURL() *url.URL {
|
|
|
|
return &url.URL{
|
|
|
|
Scheme: "https",
|
|
|
|
Host: apiHost,
|
|
|
|
Path: licensePath,
|
|
|
|
}
|
|
|
|
}
|
2022-08-25 08:06:29 -04:00
|
|
|
|
2022-11-09 09:57:54 -05:00
|
|
|
// QuotaChecker checks the vCPU quota for a given license.
|
2022-08-25 08:06:29 -04:00
|
|
|
type QuotaChecker interface {
|
|
|
|
QuotaCheck(ctx context.Context, checkRequest QuotaCheckRequest) (QuotaCheckResponse, error)
|
|
|
|
}
|