constellation-lib: run license check in Terraform provider and refactor code (#2740)

* Clean up license checker code

Signed-off-by: Daniel Weiße <dw@edgeless.systems>

* Create license check depending on init/upgrade actions

Signed-off-by: Daniel Weiße <dw@edgeless.systems>

* Run license check in Terraform provider

Signed-off-by: Daniel Weiße <dw@edgeless.systems>

* fix license integration test action

Signed-off-by: Daniel Weiße <dw@edgeless.systems>

* Run tests with enterprise tag

Signed-off-by: Daniel Weiße <dw@edgeless.systems>

* Allow b64 encoding for license ID

Signed-off-by: Daniel Weiße <dw@edgeless.systems>

* Update checker_enterprise.go

---------

Signed-off-by: Daniel Weiße <dw@edgeless.systems>
Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com>
This commit is contained in:
Daniel Weiße 2023-12-22 10:16:36 +01:00 committed by GitHub
parent ac1f322044
commit 519efe637d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 206 additions and 162 deletions

View file

@ -35,6 +35,7 @@ import (
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
"github.com/edgelesssys/constellation/v2/internal/grpc/dialer"
"github.com/edgelesssys/constellation/v2/internal/kms/uri"
"github.com/edgelesssys/constellation/v2/internal/license"
"github.com/edgelesssys/constellation/v2/internal/semver"
"github.com/edgelesssys/constellation/v2/internal/versions"
datastruct "github.com/edgelesssys/constellation/v2/terraform-provider-constellation/internal/data"
@ -91,6 +92,7 @@ type ClusterResourceModel struct {
MasterSecretSalt types.String `tfsdk:"master_secret_salt"`
MeasurementSalt types.String `tfsdk:"measurement_salt"`
InitSecret types.String `tfsdk:"init_secret"`
LicenseID types.String `tfsdk:"license_id"`
Attestation types.Object `tfsdk:"attestation"`
GCP types.Object `tfsdk:"gcp"`
Azure types.Object `tfsdk:"azure"`
@ -258,7 +260,14 @@ func (r *ClusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
Description: "Secret used for initialization of the cluster.",
Required: true,
},
"license_id": schema.StringAttribute{
MarkdownDescription: "Constellation license ID. When not set, the community license is used.",
Description: "Constellation license ID. When not set, the community license is used.",
Optional: true,
},
"attestation": newAttestationConfigAttributeSchema(attributeInput),
// CSP specific inputs
"gcp": schema.SingleNestedAttribute{
MarkdownDescription: "GCP-specific configuration.",
Description: "GCP-specific configuration.",
@ -442,15 +451,36 @@ func (r *ClusterResource) Configure(_ context.Context, req resource.ConfigureReq
}
r.newApplier = func(ctx context.Context, validator atls.Validator) *constellation.Applier {
return constellation.NewApplier(&tfContextLogger{ctx: ctx}, &nopSpinner{}, newDialer)
return constellation.NewApplier(&tfContextLogger{ctx: ctx}, &nopSpinner{}, constellation.ApplyContextTerraform, newDialer)
}
}
// ModifyPlan is called when the resource is planned for creation, updates, or deletion. This allows to set pre-apply
// warnings and errors.
func (r *ClusterResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
if req.Plan.Raw.IsNull() {
return
}
// Read plannedState supplied by Terraform runtime into the model
var plannedState ClusterResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plannedState)...)
if resp.Diagnostics.HasError() {
return
}
licenseID := plannedState.LicenseID.ValueString()
if licenseID == "" {
resp.Diagnostics.AddWarning("Constellation license not found.",
"Using community license.\nFor details, see https://docs.edgeless.systems/constellation/overview/license")
}
if licenseID == license.CommunityLicense {
resp.Diagnostics.AddWarning("Using community license.",
"For details, see https://docs.edgeless.systems/constellation/overview/license")
}
// Checks running on updates to the resource. (i.e. state and plan != nil)
if !req.Plan.Raw.IsNull() && !req.State.Raw.IsNull() {
if !req.State.Raw.IsNull() {
// Read currentState supplied by Terraform runtime into the model
var currentState ClusterResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &currentState)...)
@ -458,13 +488,6 @@ func (r *ClusterResource) ModifyPlan(ctx context.Context, req resource.ModifyPla
return
}
// Read plannedState supplied by Terraform runtime into the model
var plannedState ClusterResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plannedState)...)
if resp.Diagnostics.HasError() {
return
}
// Warn the user about possibly destructive changes in case microservice changes are to be applied.
currVer, diags := r.getMicroserviceVersion(ctx, &currentState)
resp.Diagnostics.Append(diags...)
@ -714,6 +737,17 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
return diags
}
// parse license ID
licenseID := data.LicenseID.ValueString()
if licenseID == "" {
licenseID = license.CommunityLicense
}
// license ID can be base64-encoded
licenseIDFromB64, err := base64.StdEncoding.DecodeString(licenseID)
if err == nil {
licenseID = string(licenseIDFromB64)
}
// Parse in-cluster service account info.
serviceAccPayload := constellation.ServiceAccountPayload{}
var gcpConfig gcpAttribute
@ -802,6 +836,16 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
}
}
// Check license
quota, err := applier.CheckLicense(ctx, csp, !skipInitRPC, licenseID)
if err != nil {
diags.AddWarning("Unable to contact license server.", "Please keep your vCPU quota in mind.")
} else if licenseID == license.CommunityLicense {
diags.AddWarning("Using community license.", "For details, see https://docs.edgeless.systems/constellation/overview/license")
} else {
tflog.Info(ctx, fmt.Sprintf("Please keep your vCPU quota (%d) in mind.", quota))
}
// Now, we perform the actual applying.
// Run init RPC