From 35900aa0f82713bf2c1bc2de8d2e734c9b74339e Mon Sep 17 00:00:00 2001 From: r-vasquez Date: Fri, 22 Nov 2024 11:50:10 -0800 Subject: [PATCH 1/3] rpk: modify CTA in license warning This also adds a new warning case, for enterprise license which have expired. --- src/go/rpk/pkg/adminapi/admin.go | 43 ++++++++++++++++++++------- src/go/rpk/pkg/adminapi/admin_test.go | 3 +- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/go/rpk/pkg/adminapi/admin.go b/src/go/rpk/pkg/adminapi/admin.go index 3348dca9c9367..8c67799a932ea 100644 --- a/src/go/rpk/pkg/adminapi/admin.go +++ b/src/go/rpk/pkg/adminapi/admin.go @@ -160,13 +160,22 @@ func licenseFeatureChecks(ctx context.Context, fs afero.Fs, cl *rpadmin.AdminAPI enabledFeatures = append(enabledFeatures, f.Name) } } - isTrialCheck := isTrialAboutToExpire(info, enabledFeatures) - - if featResp.Violation { - msg = fmt.Sprintf("\nWARNING: The following Enterprise features are being used in your Redpanda cluster: %v. These features require a license. To get a license, contact us at https://www.redpanda.com/contact. For more information, see https://docs.redpanda.com/current/get-started/licenses/#redpanda-enterprise-edition\n", enabledFeatures) - } else if isTrialCheck { - msg = fmt.Sprintf("\nWARNING: your TRIAL license is about to expire. The following Enterprise features are being used in your Redpanda cluster: %v. These features require a license. To get a license, contact us at https://www.redpanda.com/contact. For more information, see https://docs.redpanda.com/current/get-started/licenses/#redpanda-enterprise-edition\n", enabledFeatures) - } else { + // We have 3 types of warnings: + // 1. WHEN license.type=TRIAL, enterprise feature(s) enabled, AND + // expiry in <15 days + // 2. WHEN license.type=ENTERPRISE and license EXPIRED, AND VIOLATION + // (enterprise featured enabled) + // 3. WHEN there is a VIOLATION (no or expired license and + // enterprise(s) features enabled) + daysLeft, isTrialCheck := isTrialAboutToExpire(info, enabledFeatures) + switch { + case isTrialCheck: + msg = fmt.Sprintf("\nNote: your TRIAL license will expire in %v days. The following Enterprise features are being used in your Redpanda cluster: %v. These features require a license. To request a license, please visit https://redpanda.com/upgrade. For more information, see https://docs.redpanda.com/current/get-started/licenses/#redpanda-enterprise-edition\n", daysLeft, enabledFeatures) + case isEnterpriseExpired(info, enabledFeatures): + msg = fmt.Sprintf("\nWARNING: your ENTERPRISE license has expired. The following Enterprise features are being used in your Redpanda cluster: %v. These features require a license. To request a new license, please visit https://support.redpanda.com. For more information, see https://docs.redpanda.com/current/get-started/licenses/#redpanda-enterprise-edition\n", enabledFeatures) + case featResp.Violation: + msg = fmt.Sprintf("\nWARNING: The following Enterprise features are being used in your Redpanda cluster: %v. These features require a license. To request a license, please visit http://redpanda.com/upgrade. To try Redpanda Enterprise for 30 days, visit http://redpanda.com/try-enterprise. For more information, see https://docs.redpanda.com/current/get-started/licenses/#redpanda-enterprise-edition\n", enabledFeatures) + default: licenseCheck = &config.LicenseStatusCache{ LastUpdate: time.Now().Unix(), } @@ -188,14 +197,26 @@ func licenseFeatureChecks(ctx context.Context, fs afero.Fs, cl *rpadmin.AdminAPI return msg } -// isTrialAboutToExpire returns true if we have a loaded free_trial license that -// expires in less than 15 days, and we have enterprise features enabled. -func isTrialAboutToExpire(info rpadmin.License, enabledFeatures []string) bool { +// isTrialAboutToExpire checks if the loaded "free_trial" license will expire in +// less than 15 days and if enterprise features are enabled. It returns the +// number of days remaining until expiration and a boolean indicating whether +// the trial is about to expire. +func isTrialAboutToExpire(info rpadmin.License, enabledFeatures []string) (int, bool) { if len(enabledFeatures) > 0 && info.Loaded && strings.EqualFold(info.Properties.Type, "free_trial") { ut := time.Unix(info.Properties.Expires, 0) daysLeft := int(time.Until(ut).Hours() / 24) - return daysLeft < 15 && !ut.Before(time.Now()) + return daysLeft, daysLeft < 15 && !ut.Before(time.Now()) + } + return -1, false +} + +// isEnterpriseExpired returns true if we have a loaded enterprise license +// that has expired and the user still has enterprise features enabled. +func isEnterpriseExpired(info rpadmin.License, enabledFeatures []string) bool { + if len(enabledFeatures) > 0 && info.Loaded && strings.EqualFold(info.Properties.Type, "enterprise") { + ut := time.Unix(info.Properties.Expires, 0) + return ut.Before(time.Now()) } return false } diff --git a/src/go/rpk/pkg/adminapi/admin_test.go b/src/go/rpk/pkg/adminapi/admin_test.go index 9c8f417fae41f..9b6d89dfa6549 100644 --- a/src/go/rpk/pkg/adminapi/admin_test.go +++ b/src/go/rpk/pkg/adminapi/admin_test.go @@ -38,7 +38,7 @@ func Test_licenseFeatureChecks(t *testing.T) { name: "free_trial about to expire, with features", prof: &config.RpkProfile{}, responseCase: "ok-features", - expContain: "WARNING: your TRIAL license is about to expire", + expContain: "Note: your TRIAL license will expire in", }, { name: "license ok, cache valid", @@ -175,7 +175,6 @@ var mapLicenseInfoResponses = map[string]response{ func licenseHandler(respCase string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - fmt.Println(r.URL.Path) if r.URL.Path == "/v1/features/enterprise" { resp := mapLicenseFeatureResponses[respCase] w.WriteHeader(resp.status) From 1c358a73091356c0eef98b2c97ac4eeda38b1ea7 Mon Sep 17 00:00:00 2001 From: r-vasquez Date: Fri, 22 Nov 2024 11:52:26 -0800 Subject: [PATCH 2/3] rpk: add CTA to rpk cluster license info --- src/go/rpk/pkg/cli/cluster/license/BUILD | 2 ++ src/go/rpk/pkg/cli/cluster/license/info.go | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/go/rpk/pkg/cli/cluster/license/BUILD b/src/go/rpk/pkg/cli/cluster/license/BUILD index 4fe310a804507..34bf13d5b836a 100644 --- a/src/go/rpk/pkg/cli/cluster/license/BUILD +++ b/src/go/rpk/pkg/cli/cluster/license/BUILD @@ -13,6 +13,8 @@ go_library( "//src/go/rpk/pkg/adminapi", "//src/go/rpk/pkg/config", "//src/go/rpk/pkg/out", + "@com_github_kr_text//:text", + "@com_github_moby_term//:term", "@com_github_redpanda_data_common_go_rpadmin//:rpadmin", "@com_github_spf13_afero//:afero", "@com_github_spf13_cobra//:cobra", diff --git a/src/go/rpk/pkg/cli/cluster/license/info.go b/src/go/rpk/pkg/cli/cluster/license/info.go index be69b4fa489ba..50705671ae722 100644 --- a/src/go/rpk/pkg/cli/cluster/license/info.go +++ b/src/go/rpk/pkg/cli/cluster/license/info.go @@ -6,6 +6,8 @@ import ( "strings" "time" + "github.com/kr/text" + mTerm "github.com/moby/term" "github.com/redpanda-data/common-go/rpadmin" "github.com/redpanda-data/redpanda/src/go/rpk/pkg/adminapi" "github.com/redpanda-data/redpanda/src/go/rpk/pkg/config" @@ -134,21 +136,30 @@ func printTextLicenseInfo(resp infoResponse) { if *resp.Expired { tw.Print("License expired:", *resp.Expired) } - checkLicenseExpiry(resp.ExpiresUnix, resp.Type) + checkLicenseExpiry(resp.ExpiresUnix, resp.Type, resp.EnterpriseFeatures) } out.Section("LICENSE INFORMATION") tw.Flush() } -func checkLicenseExpiry(expiresUnix int64, licenseType string) { +func checkLicenseExpiry(expiresUnix int64, licenseType string, enterpriseFeatures []string) { ut := time.Unix(expiresUnix, 0) daysLeft := int(time.Until(ut).Hours() / 24) dayThreshold := 30 - if strings.EqualFold(licenseType, "free_trial") { + isTrial := strings.EqualFold(licenseType, "free_trial") + if isTrial { dayThreshold = 15 } if daysLeft < dayThreshold && !ut.Before(time.Now()) { - fmt.Fprintf(os.Stderr, "WARNING: your license will expire soon.\n\n") + msg := "WARNING: your license will expire soon.\n\n" + if isTrial && len(enterpriseFeatures) == 0 { + msg = fmt.Sprintf("Note: your TRIAL license will expire in %v days. To request a license, please visit https://redpanda.com/upgrade. To try Redpanda Enterprise for 30 days, visit https://redpanda.com/try-enterprise. For more information, see https://docs.redpanda.com/current/get-started/licenses/#redpanda-enterprise-edition\n\n", daysLeft) + } + if ws, err := mTerm.GetWinsize(0); err == nil { + // text.Wrap removes the newlines from the text. We add it back. + msg = text.Wrap(msg, int(ws.Width)) + "\n\n" + } + fmt.Fprint(os.Stderr, msg) } } From 45d48d58918c64e5110b382e7bf9a4c5fee35aba Mon Sep 17 00:00:00 2001 From: r-vasquez Date: Fri, 22 Nov 2024 12:16:46 -0800 Subject: [PATCH 3/3] rpk: avoid repeating warning for trial licenses When the license is a trial license and the cluster has enterprise features enabled, rpk already prints a warning when creating the admin API client We avoid printing another warning in this command as this can be repetitive. --- src/go/rpk/pkg/cli/cluster/license/info.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/go/rpk/pkg/cli/cluster/license/info.go b/src/go/rpk/pkg/cli/cluster/license/info.go index 50705671ae722..d729ba728135f 100644 --- a/src/go/rpk/pkg/cli/cluster/license/info.go +++ b/src/go/rpk/pkg/cli/cluster/license/info.go @@ -153,7 +153,14 @@ func checkLicenseExpiry(expiresUnix int64, licenseType string, enterpriseFeature } if daysLeft < dayThreshold && !ut.Before(time.Now()) { msg := "WARNING: your license will expire soon.\n\n" - if isTrial && len(enterpriseFeatures) == 0 { + if isTrial { + if len(enterpriseFeatures) > 0 { + // We don't print if isTrial and we have enterprise features. + // Because in this case we already print the warning when + // creating the admin client and printing another warning is + // repetitive. + return + } msg = fmt.Sprintf("Note: your TRIAL license will expire in %v days. To request a license, please visit https://redpanda.com/upgrade. To try Redpanda Enterprise for 30 days, visit https://redpanda.com/try-enterprise. For more information, see https://docs.redpanda.com/current/get-started/licenses/#redpanda-enterprise-edition\n\n", daysLeft) } if ws, err := mTerm.GetWinsize(0); err == nil {