Skip to content

Commit

Permalink
Notify users about version update being available
Browse files Browse the repository at this point in the history
Signed-off-by: Danil-Grigorev <danil.grigorev@suse.com>
  • Loading branch information
Danil-Grigorev committed Sep 23, 2024
1 parent bc87424 commit 246ee1b
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 25 deletions.
8 changes: 8 additions & 0 deletions api/v1alpha1/conditions_consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,11 @@ const (
// CheckLatestVersionTime is set as a timestamp info of the last timestamp of the latest version being up-to-date for the CAPIProvider.
CheckLatestVersionTime = "CheckLatestVersionTime"
)

const (
// CheckLatestUpdateAvailableReason is a reason for a False condition, due to update being available.
CheckLatestUpdateAvailableReason = "UpdateAvailable"

// CheckLatestProviderUnknown is a reason for an Unknown condition, due to provider not being available.
CheckLatestProviderUnknown = "ProviderUnknown"
)
28 changes: 15 additions & 13 deletions internal/controllers/clusterctl/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ var (
)

const (
latest = "latest"
latestVersionKey = "latest"
)

func init() {
Expand Down Expand Up @@ -113,14 +113,14 @@ func ClusterConfig(ctx context.Context, c client.Client) (*ConfigRepository, err

// GetProviderVersion collects version of the collected provider overrides state.
// Returns latest if the version is not found.
func (r *ConfigRepository) GetProviderVersion(ctx context.Context, name, providerType string) string {
func (r *ConfigRepository) GetProviderVersion(ctx context.Context, name, providerType string) (version string, providerKnown bool) {
for _, provider := range r.Providers {
if provider.Name == name && strings.EqualFold(provider.Type, providerType) {
return collectVersion(ctx, provider.URL)
return collectVersion(ctx, provider.URL), true
}
}

return latest
return latestVersionKey, false
}

func collectVersion(ctx context.Context, url string) string {
Expand All @@ -130,16 +130,17 @@ func collectVersion(ctx context.Context, url string) string {
if len(version) < 2 {
log.FromContext(ctx).Info("Provider url is invalid for version resolve, defaulting to latest", "url", url)

return latest
return latestVersionKey
}

return version[1]
}

// VerifyProviderVersion checks version against the expected max version, and returns false
// IsLatestVersion checks version against the expected max version, and returns false
// if the version given is newer then the latest in the clusterctlconfig override.
func (r *ConfigRepository) VerifyProviderVersion(providerVersion, expected string) (bool, error) {
if providerVersion == latest {
func (r *ConfigRepository) IsLatestVersion(providerVersion, expected string) (bool, error) {
// Return true for providers without version boundary or unknown providers
if providerVersion == latestVersionKey {
return true, nil
}

Expand All @@ -150,18 +151,19 @@ func (r *ConfigRepository) VerifyProviderVersion(providerVersion, expected strin
return false, fmt.Errorf("unable to parse default provider version %s: %w", providerVersion, err)
}

if expected == latest {
expected = cmp.Or(expected, latestVersionKey)
if expected == latestVersionKey {
// Latest should be reduced to the actual version set on the clusterctlprovider resource
return false, nil
}

version, _ = strings.CutPrefix(expected, "v")

destinatonVersion, err := semver.Parse(version)
desiredVersion, err := semver.Parse(version)
if err != nil {
return false, fmt.Errorf("unable to parse provider version %s: %w", expected, err)
return false, fmt.Errorf("unable to parse desired version %s: %w", expected, err)
}

// Disallow versions beyond clusterctl.yaml default
return maxVersion.LTE(destinatonVersion), nil
// Disallow versions beyond current clusterctl.yaml override default
return maxVersion.LTE(desiredVersion), nil
}
33 changes: 21 additions & 12 deletions internal/sync/provider_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log"

operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/util/conditions"

turtlesv1 "github.com/rancher/turtles/api/v1alpha1"
Expand Down Expand Up @@ -159,31 +160,39 @@ func (s *ProviderSync) rolloutInfrastructure() {
}

func (s *ProviderSync) updateLatestVersion(ctx context.Context) error {
// Skip for user specified versions
// TODO: We may potentially need to verify if version specified is built in the override,
// and notify user with condition otherwise
if s.Source.Spec.Version != "" {
return nil
}

log := log.FromContext(ctx)

config, err := clusterctl.ClusterConfig(ctx, s.client)
if err != nil {
return err
}

providerVersion := config.GetProviderVersion(ctx, cmp.Or(s.Source.Spec.Name, s.Source.Name), s.Source.Spec.Type.ToKind())
expected := cmp.Or(s.Source.Spec.Version, "latest")
providerVersion, knownProvider := config.GetProviderVersion(ctx, cmp.Or(s.Source.Spec.Name, s.Source.Name), s.Source.Spec.Type.ToKind())

if valid, err := config.VerifyProviderVersion(providerVersion, expected); err != nil {
latest, err := config.IsLatestVersion(providerVersion, s.Source.Spec.Version)
if err != nil {
return err
} else if !valid {
}

switch {
case !knownProvider:
conditions.MarkUnknown(s.Source, turtlesv1.CheckLatestVersionTime, turtlesv1.CheckLatestProviderUnknown, "Provider is unknown")
case s.Source.Spec.Version != "" && latest:
conditions.MarkTrue(s.Source, turtlesv1.CheckLatestVersionTime)
case s.Source.Spec.Version != "" && !latest:
conditions.MarkFalse(
s.Source,
turtlesv1.CheckLatestVersionTime,
turtlesv1.CheckLatestUpdateAvailableReason,
clusterv1.ConditionSeverityInfo,
"Provider version update available. Current latest is %s", providerVersion,
)
case !latest:
lastCheck := conditions.Get(s.Source, turtlesv1.CheckLatestVersionTime)
updatedMessage := fmt.Sprintf("Updated to latest %s version", providerVersion)

if lastCheck == nil || lastCheck.Message != updatedMessage {
log.Info(fmt.Sprintf("Version %s is beyound current latest, setting to %s", expected, providerVersion))
log.Info(fmt.Sprintf("Version %s is beyound current latest, updated to %s", cmp.Or(s.Source.Spec.Version, "latest"), providerVersion))

lastCheck = conditions.TrueCondition(turtlesv1.CheckLatestVersionTime)
lastCheck.Message = updatedMessage
Expand Down

0 comments on commit 246ee1b

Please sign in to comment.