Skip to content

Conversation

@ajanikow
Copy link
Collaborator

No description provided.

@cla-bot cla-bot bot added the cla-signed label Oct 22, 2025
@ajanikow ajanikow force-pushed the feature/license/master_management branch from 836066b to 2dbc103 Compare October 31, 2025 16:14
@ajanikow ajanikow force-pushed the feature/license/master_management branch from 2dbc103 to 4650dec Compare October 31, 2025 16:21
@ajanikow ajanikow requested a review from Copilot November 4, 2025 08:52
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements License Activation API Integration, enabling automatic license generation and renewal through the ArangoDB License Manager API. The key changes include:

  • Introduction of dual license modes: "key" (static license) and "api" (dynamically generated license)
  • New actions for license generation and cleanup
  • Support for automatic license regeneration based on expiration grace periods
  • Refactoring of license-related code including package renaming from pkg/license/manager to pkg/license_manager

Reviewed Changes

Copilot reviewed 44 out of 45 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pkg/util/k8sutil/license.go Added LicenseSecretMaster struct and API field to support license API credentials
pkg/util/constants/constants.go Added constants for license client ID and secret keys
pkg/util/cli/lm.go Updated imports to use renamed license_manager package
pkg/util/arangod/request.go Refactored AcceptCode method to use extracted error evaluation logic
pkg/util/arangod/error.go Added InvalidCode error type and evaluation utilities
pkg/apis/deployment/v1/license_spec.go Added LicenseMode, TTL, ExpirationGracePeriod, Telemetry, and Inventory fields
pkg/apis/deployment/v1/deployment_status_license.go New file defining license status tracking
pkg/deployment/reconcile/action_license_generate.go New action for automatic license generation via API
pkg/deployment/reconcile/action_license_clean.go New action for cleaning license references
pkg/deployment/reconcile/plan_builder_license.go Enhanced license plan builder with mode discovery and API support
pkg/platform/inventory/*.go Refactored inventory fetching into reusable function
pkg/license_manager/*.go Renamed from pkg/license/manager and updated types
internal/actions.yaml Added LicenseGenerate and LicenseClean action definitions

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


if expires.After(license.Expires()) {
// License will expire before grace period, reduce to 90%
expires = time.Now().Add(time.Duration(math.Round(float64(time.Since(license.Expires())) * api.LicenseExpirationGraceRatio)))
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The calculation uses time.Since(license.Expires()) which will be negative if the license hasn't expired yet. This should be time.Until(license.Expires()) to get a positive duration representing the time remaining until expiration.

Suggested change
expires = time.Now().Add(time.Duration(math.Round(float64(time.Since(license.Expires())) * api.LicenseExpirationGraceRatio)))
expires = time.Now().Add(time.Duration(math.Round(float64(time.Until(license.Expires())) * api.LicenseExpirationGraceRatio)))

Copilot uses AI. Check for mistakes.
@ajanikow ajanikow requested a review from Copilot November 4, 2025 11:09
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 44 out of 45 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

pkg/platform/inventory/consts_test.go:21

  • The file was completely rewritten from a license package with interface definitions to an inventory package with a UUID test. This appears to be an incorrect replacement - the original content (Loader interface and MockLoader) seems unrelated to consts_test.go and may have been misplaced. Verify this file change is intentional.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return api.Plan{actions.NewClusterAction(api.ActionTypeLicenseClean, "Removing license reference - Invalid Hash")}
}

if status.License.Regenerate.After(time.Now()) {
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition is inverted - it should trigger regeneration when Regenerate time is before (not after) time.Now(). Currently, it will clean the license when regeneration is NOT yet needed. Change to if status.License.Regenerate.Before(time.Now()) or if !status.License.Regenerate.After(time.Now()).

Suggested change
if status.License.Regenerate.After(time.Now()) {
if status.License.Regenerate.Before(time.Now()) {

Copilot uses AI. Check for mistakes.
expires := time.Now().Add(expiration)

if expires.After(license.Expires()) {
// License will expire before grace period, reduce to 90%
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states 'License will expire before grace period, reduce to 90%' but LicenseExpirationGraceRatio is 0.75 (75%), not 0.90. The comment should be updated to say 'reduce to 75%' or use a named constant for clarity.

Suggested change
// License will expire before grace period, reduce to 90%
// License will expire before grace period, reduce to 75%

Copilot uses AI. Check for mistakes.
@ajanikow ajanikow requested a review from Copilot November 4, 2025 11:58
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 44 out of 45 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

pkg/platform/inventory/consts_test.go:21

  • The test file appears to have been completely replaced with only a UUID validation test. The original file contained interface and mock definitions that may have been used elsewhere. Verify that removing the Loader interface and MockLoader doesn't break other tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}

if inv.DeploymentId != did {
a.log.Err(err).Error("Invalid deployment ID in inventory")
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error logging references 'err' but the variable 'err' is nil at this point (line 98 shows err is only used for FetchInventorySpec). This will log a nil error. Should either create a proper error or remove the .Err(err) call.

Suggested change
a.log.Err(err).Error("Invalid deployment ID in inventory")
a.log.Error("Invalid deployment ID in inventory")

Copilot uses AI. Check for mistakes.
return api.LicenseModeAPI, nil
}

return "", errors.Errorf("Unable to discover LicenseAPIKey mode")
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message says 'LicenseAPIKey mode' but should be 'License mode' for consistency with the rest of the codebase and to avoid confusion.

Suggested change
return "", errors.Errorf("Unable to discover LicenseAPIKey mode")
return "", errors.Errorf("Unable to discover License mode")

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 44 out of 45 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +89 to +91
} else if l.API == nil {
return LicenseSecret{}, errors.Errorf("Key (%s, %s, %s, or %s+%s) is missing in the license secret (%s)",
utilConstants.SecretKeyToken, utilConstants.SecretKeyV2License, utilConstants.SecretKeyV2Token, utilConstants.SecretKeyLicenseClientID, utilConstants.SecretKeyLicenseClientSecret, name)
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message lists individual secret keys but the logic only requires either V2 license keys OR API credentials (not all of them). The message should clarify that it needs 'either (token/license-v2/token-v2) or (client-id + client-secret)' rather than listing all keys with 'or'.

Copilot uses AI. Check for mistakes.
return api.Plan{actions.NewClusterAction(api.ActionTypeLicenseClean, "Removing license reference - Invalid Hash")}
}

if status.License.Regenerate.Time.Before(time.Now()) {
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The time comparison is inverted. When Regenerate.Time.Before(time.Now()) is true, it means the regeneration time is in the past, so regeneration should be triggered. However, the current logic triggers regeneration when the time is in the past, which is correct. But note that this check should use !After or proper time comparison to handle edge cases. Consider using time.Now().After(status.License.Regenerate.Time) for clarity.

Suggested change
if status.License.Regenerate.Time.Before(time.Now()) {
if time.Now().After(status.License.Regenerate.Time) {

Copilot uses AI. Check for mistakes.
expires := time.Now().Add(expiration)

if expires.After(license.Expires()) {
// License will expire before grace period, reduce to 75%
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on line 166 is misleading. The condition checks if expires.After(license.Expires()), which means the calculated regeneration time is AFTER the license expiration. This is when we need to reduce the time, but the comment says 'License will expire before grace period' which describes the opposite scenario. The comment should say 'Grace period extends beyond license expiration, reduce to 75% of remaining license time'.

Suggested change
// License will expire before grace period, reduce to 75%
// Grace period extends beyond license expiration, reduce to 75% of remaining license time

Copilot uses AI. Check for mistakes.
Comment on lines +143 to +144
s.TTL = util.NewTypeOrNil(other.TTL)
s.ExpirationGracePeriod = util.NewTypeOrNil(other.ExpirationGracePeriod)
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 143-144 unconditionally overwrite TTL and ExpirationGracePeriod from other regardless of whether they are already set in s. This is inconsistent with the SecretName logic (lines 140-142) which only sets the value if not already present. These fields should follow the same pattern with conditional checks.

Suggested change
s.TTL = util.NewTypeOrNil(other.TTL)
s.ExpirationGracePeriod = util.NewTypeOrNil(other.ExpirationGracePeriod)
if s.TTL == nil {
s.TTL = util.NewTypeOrNil(other.TTL)
}
if s.ExpirationGracePeriod == nil {
s.ExpirationGracePeriod = util.NewTypeOrNil(other.ExpirationGracePeriod)
}

Copilot uses AI. Check for mistakes.
Comment on lines +147 to +151
expiration := time.Until(license.Expires())
if expiration <= 0 {
a.log.Error("Unable to get license - invalid timestamp")
return true, nil
}
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message 'Unable to get license - invalid timestamp' is misleading because the license was successfully retrieved. The issue is that the license has already expired. The message should be 'License has already expired' or 'Invalid license expiration time'.

Copilot uses AI. Check for mistakes.
Comment on lines +68 to +70
if c, ok := arangod.IsInvalidCode(err); ok && c.Got == goHttp.StatusForbidden {
// Fallback to the Deployment ID Single
return FixedSingleDeploymentID, nil
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment 'Fallback to the Deployment ID Single' is unclear. It should explain why StatusForbidden triggers a fallback to a fixed deployment ID (e.g., 'Use fixed single deployment ID when cluster health endpoint returns Forbidden (single server mode)').

Copilot uses AI. Check for mistakes.
Comment on lines +87 to +91
func (i InvalidCode) Error() string {
return fmt.Sprintf("Code %d not allowed in expected status codes: %s", i.Got, goStrings.Join(util.FormatList(i.Expected, func(a int) string {
return fmt.Sprintf("%d", a)
}), ", "))
}
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The error message could be more informative by indicating what the expected vs actual codes represent (HTTP status codes). Consider: 'HTTP status code %d not allowed, expected one of: %s'.

Copilot uses AI. Check for mistakes.
@ajanikow ajanikow merged commit 8761cf6 into master Nov 4, 2025
8 of 9 checks passed
@ajanikow ajanikow deleted the feature/license/master_management branch November 4, 2025 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants