Skip to content

Commit

Permalink
feat: [TKC-1207] TCL license checker (#5021)
Browse files Browse the repository at this point in the history
* feat: license-checker

* fix: format license

* feat: plan check via grpc

* docs: add reference to FAQ

* fix: test

* ci: goimports

* fix: remove check based on rest endpoint
  • Loading branch information
vLia authored Feb 21, 2024
1 parent 72a7466 commit a6b2812
Show file tree
Hide file tree
Showing 13 changed files with 735 additions and 1 deletion.
1 change: 1 addition & 0 deletions cmd/api-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ func main() {
EnvID: cfg.TestkubeProEnvID,
OrgID: cfg.TestkubeProOrgID,
Migrate: cfg.TestkubeProMigrate,
ConnectionTimeout: cfg.TestkubeProConnectionTimeout,
}

api.WithProContext(&proContext)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ require (
golang.org/x/time v0.3.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/protobuf v1.31.0
google.golang.org/protobuf v1.32.0
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type Config struct {
TestkubeProEnvID string `envconfig:"TESTKUBE_PRO_ENV_ID" default:""`
TestkubeProOrgID string `envconfig:"TESTKUBE_PRO_ORG_ID" default:""`
TestkubeProMigrate string `envconfig:"TESTKUBE_PRO_MIGRATE" default:"false"`
TestkubeProConnectionTimeout int `envconfig:"TESTKUBE_PRO_CONNECTION_TIMEOUT" default:"10"`
TestkubeWatcherNamespaces string `envconfig:"TESTKUBE_WATCHER_NAMESPACES" default:""`
GraphqlPort string `envconfig:"TESTKUBE_GRAPHQL_PORT" default:"8070"`
TestkubeRegistry string `envconfig:"TESTKUBE_REGISTRY" default:""`
Expand Down
1 change: 1 addition & 0 deletions internal/config/procontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ type ProContext struct {
EnvID string
OrgID string
Migrate string
ConnectionTimeout int
}
391 changes: 391 additions & 0 deletions licenses/TCL.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pkg/cloud/data/config/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ const (
CmdConfigGetTelemetryEnabled executor.Command = "get_telemetry_enabled"
CmdConfigGet executor.Command = "get"
CmdConfigUpsert executor.Command = "upsert"
CmdConfigGetOrganizationPlan executor.Command = "get_org_plan"
)
4 changes: 4 additions & 0 deletions pkg/executor/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ var RunnerEnvVars = []corev1.EnvVar{
Name: "RUNNER_PRO_API_SKIP_VERIFY",
Value: getOr("TESTKUBE_PRO_SKIP_VERIFY", "false"),
},
{
Name: "RUNNER_PRO_CONNECTION_TIMEOUT",
Value: getOr("TESTKUBE_PRO_CONNECTION_TIMEOUT", "10"),
},
{
Name: "RUNNER_DASHBOARD_URI",
Value: os.Getenv("TESTKUBE_DASHBOARD_URI"),
Expand Down
1 change: 1 addition & 0 deletions pkg/executor/containerexecutor/containerexecutor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ func TestNewExecutorJobSpecWithArgs(t *testing.T) {
{Name: "RUNNER_PRO_API_URL", Value: ""},
{Name: "RUNNER_PRO_API_TLS_INSECURE", Value: "false"},
{Name: "RUNNER_PRO_API_SKIP_VERIFY", Value: "false"},
{Name: "RUNNER_PRO_CONNECTION_TIMEOUT", Value: "10"},
{Name: "RUNNER_CLOUD_MODE", Value: "false"}, // DEPRECATED
{Name: "RUNNER_CLOUD_API_KEY", Value: ""}, // DEPRECATED
{Name: "RUNNER_CLOUD_API_URL", Value: ""}, // DEPRECATED
Expand Down
7 changes: 7 additions & 0 deletions pkg/tcl/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Testkube Operator - TCL Package

This folder contains special code with the Testkube Community license.

## License

The code in this folder is licensed under the Testkube Community License. Please see the [LICENSE](../../licenses/TCL.txt) file and consult the [FAQ](../../docs/docs/articles/testkube-licensing-FAQ.md) for more information.
50 changes: 50 additions & 0 deletions pkg/tcl/checktcl/organization_plan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2024 Testkube.
//
// Licensed as a Testkube Pro file under the Testkube Community
// License (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// https://github.com/kubeshop/testkube/blob/main/licenses/TCL.txt

package checktcl

// Enterprise / Pro mode.
type OrganizationPlanTestkubeMode string

const (
OrganizationPlanTestkubeModeEnterprise OrganizationPlanTestkubeMode = "enterprise"
// TODO: Use "pro" in the future when refactoring TK Pro API server to use "pro" instead of "cloud"
OrganizationPlanTestkubeModePro OrganizationPlanTestkubeMode = "cloud"
)

// Ref: #/components/schemas/PlanStatus
type PlanStatus string

const (
PlanStatusActive PlanStatus = "Active"
PlanStatusCanceled PlanStatus = "Canceled"
PlanStatusIncomplete PlanStatus = "Incomplete"
PlanStatusIncompleteExpired PlanStatus = "IncompleteExpired"
PlanStatusPastDue PlanStatus = "PastDue"
PlanStatusTrailing PlanStatus = "Trailing"
PlanStatusUnpaid PlanStatus = "Unpaid"
PlanStatusDeleted PlanStatus = "Deleted"
PlanStatusLocked PlanStatus = "Locked"
PlanStatusBlocked PlanStatus = "Blocked"
)

// Ref: #/components/schemas/OrganizationPlan
type OrganizationPlan struct {
// Enterprise / Pro mode.
TestkubeMode OrganizationPlanTestkubeMode `json:"testkubeMode"`
// Is current plan trial.
IsTrial bool `json:"isTrial"`
PlanStatus PlanStatus `json:"planStatus"`
}

type GetOrganizationPlanRequest struct{}
type GetOrganizationPlanResponse struct {
TestkubeMode string
IsTrial bool
PlanStatus string
}
83 changes: 83 additions & 0 deletions pkg/tcl/checktcl/subscription.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright 2024 Testkube.
//
// Licensed as a Testkube Pro file under the Testkube Community
// License (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// https://github.com/kubeshop/testkube/blob/main/licenses/TCL.txt

package checktcl

import (
"context"
"encoding/json"

"github.com/pkg/errors"
"google.golang.org/grpc"

"github.com/kubeshop/testkube/internal/config"
"github.com/kubeshop/testkube/pkg/cloud"
cloudconfig "github.com/kubeshop/testkube/pkg/cloud/data/config"
"github.com/kubeshop/testkube/pkg/cloud/data/executor"
)

type SubscriptionChecker struct {
proContext config.ProContext
orgPlan *OrganizationPlan
}

// NewSubscriptionChecker creates a new subscription checker using the agent token
func NewSubscriptionChecker(ctx context.Context, proContext config.ProContext, cloudClient cloud.TestKubeCloudAPIClient, grpcConn *grpc.ClientConn) (*SubscriptionChecker, error) {
executor := executor.NewCloudGRPCExecutor(cloudClient, grpcConn, proContext.APIKey)

req := GetOrganizationPlanRequest{}
response, err := executor.Execute(ctx, cloudconfig.CmdConfigGetOrganizationPlan, req)
if err != nil {
return nil, err
}

var commandResponse GetOrganizationPlanResponse
if err := json.Unmarshal(response, &commandResponse); err != nil {
return nil, err
}

subscription := OrganizationPlan{
TestkubeMode: OrganizationPlanTestkubeMode(commandResponse.TestkubeMode),
IsTrial: commandResponse.IsTrial,
PlanStatus: PlanStatus(commandResponse.PlanStatus),
}

return &SubscriptionChecker{proContext: proContext, orgPlan: &subscription}, nil
}

// GetCurrentOrganizationPlan returns current organization plan
func (c *SubscriptionChecker) GetCurrentOrganizationPlan() (*OrganizationPlan, error) {
if c.orgPlan == nil {
return nil, errors.New("organization plan is not set")
}
return c.orgPlan, nil
}

// IsOrgPlanEnterprise checks if organization plan is enterprise
func (c *SubscriptionChecker) IsOrgPlanEnterprise() (bool, error) {
if c.orgPlan == nil {
return false, errors.New("organization plan is not set")
}
return c.orgPlan.TestkubeMode == OrganizationPlanTestkubeModeEnterprise, nil
}

// IsOrgPlanCloud checks if organization plan is cloud
func (c *SubscriptionChecker) IsOrgPlanPro() (bool, error) {
if c.orgPlan == nil {
return false, errors.New("organization plan is not set")
}
return c.orgPlan.TestkubeMode == OrganizationPlanTestkubeModePro, nil
}

// IsOrgPlanActive checks if organization plan is active
func (c *SubscriptionChecker) IsOrgPlanActive() (bool, error) {
if c.orgPlan == nil {
return false, errors.New("organization plan is not set")
}
return c.orgPlan.PlanStatus == PlanStatusActive, nil
}
Loading

0 comments on commit a6b2812

Please sign in to comment.