constellation/internal/license/license.go
Fabian Kammel 82eb9f4544 AB#2299 License check in CLI during init (#366)
* license server interaction
* logic to read from license file
* print license information during init
Signed-off-by: Fabian Kammel <fk@edgeless.systems>
Co-authored-by: Moritz Eckert <m1gh7ym0@gmail.com>
2022-08-16 16:06:38 +02:00

92 lines
2.4 KiB
Go

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"
// CommunityQuota is the vCPU quota allowed for community installations of Constellation.
CommunityQuota = 8
apiHost = "license.confidential.cloud"
licensePath = "api/v1/license"
)
type Action string
const (
Init Action = "init"
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,
}
}
// CheckQuotaRequest is JSON request to license server to check quota for a given license and action.
type CheckQuotaRequest struct {
Action Action `json:"action"`
License string `json:"license"`
}
// CheckQuotaResponse is JSON response by license server.
type CheckQuotaResponse struct {
Quota int `json:"quota"`
}
// CheckQuota for a given license and action, passed via CheckQuotaRequest.
func (c *Client) CheckQuota(ctx context.Context, checkRequest CheckQuotaRequest) (CheckQuotaResponse, error) {
reqBody, err := json.Marshal(checkRequest)
if err != nil {
return CheckQuotaResponse{}, fmt.Errorf("unable to marshal input: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, licenseURL().String(), bytes.NewBuffer(reqBody))
if err != nil {
return CheckQuotaResponse{}, fmt.Errorf("unable to create request: %w", err)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return CheckQuotaResponse{}, fmt.Errorf("unable to do request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return CheckQuotaResponse{}, fmt.Errorf("http error %d", resp.StatusCode)
}
responseContentType := resp.Header.Get("Content-Type")
if responseContentType != "application/json" {
return CheckQuotaResponse{}, fmt.Errorf("expected server JSON response but got '%s'", responseContentType)
}
var parsedResponse CheckQuotaResponse
err = json.NewDecoder(resp.Body).Decode(&parsedResponse)
if err != nil {
return CheckQuotaResponse{}, fmt.Errorf("unable to parse response: %w", err)
}
return parsedResponse, nil
}
func licenseURL() *url.URL {
return &url.URL{
Scheme: "https",
Host: apiHost,
Path: licensePath,
}
}