From 18fd3bea5e6344bb856275dc319a05bc841715d2 Mon Sep 17 00:00:00 2001 From: Casey Morton Date: Fri, 20 Oct 2023 14:07:06 -0400 Subject: [PATCH] Added annotation for image aliases to target a specific source index --- pkg/argocd/argocd.go | 4 ++-- pkg/argocd/git.go | 3 +-- pkg/argocd/update.go | 34 ++++++++++++++++++++++++++++------ pkg/common/constants.go | 1 + pkg/image/options.go | 32 +++++++++++++++++++++++++++++++- pkg/image/version.go | 26 +++++++++++++++++--------- 6 files changed, 80 insertions(+), 20 deletions(-) diff --git a/pkg/argocd/argocd.go b/pkg/argocd/argocd.go index 0f5a11a7..c2b8d4d0 100644 --- a/pkg/argocd/argocd.go +++ b/pkg/argocd/argocd.go @@ -198,11 +198,11 @@ func FilterApplicationsForUpdate(apps []v1alpha1.Application, patterns []string, for sourceIndex, _ := range getApplicationTypes(&app) { // Check for valid application type if !IsValidApplicationTypeForSource(&app, sourceIndex) { - logCtx.Infof("skipping app '%s' of type '%s' because it's not of supported source type", app.GetName(), GetSourceTypes(app.Status)[sourceIndex]) + logCtx.Infof("skipping application '%s' source index %d of type '%s' because it's not a supported source type", app.GetName(), sourceIndex, GetSourceTypes(app.Status)[sourceIndex]) continue } - logCtx.Tracef("processing app '%s' of type '%v'", app.GetName(), app.Status.SourceType) + logCtx.Tracef("processing application '%s' source index %s of type '%s'", app.GetName(), sourceIndex, GetSourceTypes(app.Status)[sourceIndex]) imageList := parseImageList(annotations) appImages := ApplicationImages{} appImages.Application = app diff --git a/pkg/argocd/git.go b/pkg/argocd/git.go index e7ac20ec..b96b5c22 100644 --- a/pkg/argocd/git.go +++ b/pkg/argocd/git.go @@ -247,8 +247,7 @@ func commitChangesGit(app *v1alpha1.Application, wbc *WriteBackConfig, sourceInd } func writeOverrides(app *v1alpha1.Application, wbc *WriteBackConfig, sourceIndex int, gitC git.Client) (err error, skip bool) { - logCtx := log.WithContext().AddField("application", app.GetName()) - logCtx = log.WithContext().AddField("source", sourceIndex) + logCtx := log.WithContext().AddField("application", app.GetName()).AddField("source", sourceIndex) targetExists := true targetFile := path.Join(gitC.Root(), wbc.Targets[sourceIndex]) _, err = os.Stat(targetFile) diff --git a/pkg/argocd/update.go b/pkg/argocd/update.go index cedc39af..998991a2 100644 --- a/pkg/argocd/update.go +++ b/pkg/argocd/update.go @@ -201,6 +201,7 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat vc.Strategy = applicationImage.GetParameterUpdateStrategy(updateConf.UpdateApp.Application.Annotations) vc.MatchFunc, vc.MatchArgs = applicationImage.GetParameterMatch(updateConf.UpdateApp.Application.Annotations) vc.IgnoreList = applicationImage.GetParameterIgnoreTags(updateConf.UpdateApp.Application.Annotations) + vc.SourceIndex = applicationImage.GetSourceIndex(updateConf.UpdateApp.Application.Annotations) vc.Options = applicationImage. GetPlatformOptions(updateConf.UpdateApp.Application.Annotations, updateConf.IgnorePlatforms). WithMetadata(vc.Strategy.NeedsMetadata()). @@ -378,15 +379,36 @@ func needsUpdate(updateableImage *image.ContainerImage, applicationImage *image. } func setAppImage(app *v1alpha1.Application, img *image.ContainerImage) error { + logCtx := img.LogContext() imageUpdated := false imageUpdatable := false for i, appType := range getApplicationTypes(app) { - if appType == ApplicationTypeKustomize { - imageUpdatable = true - imageUpdated = SetKustomizeImageWithIndex(app, i, img) || imageUpdated - } else if appType == ApplicationTypeHelm { - imageUpdatable = true - imageUpdated = SetHelmImageWithIndex(app, i, img) || imageUpdated + logCtx.Tracef("Examining source index %d for update", i) + if imgSourceIndex := img.GetSourceIndex(app.Annotations); imgSourceIndex == image.SourceIndexAll || i == int(imgSourceIndex) { + logCtx.Debugf("Image source index %d - attempting to update source", i) + if appType == ApplicationTypeKustomize { + logCtx.Debugf("Image source index %d - attempting to update source as Kustomize application type", i) + imageUpdatable = true + if imageSourceUpdated := SetKustomizeImageWithIndex(app, i, img); imageSourceUpdated { + logCtx.Debugf("Image source index %d - successfully updated source as Kustomize image", i) + imageUpdated = true + } else { + logCtx.Debugf("Image source index %d - unable to update Kustomize images - no updatable images found", i) + } + } else if appType == ApplicationTypeHelm { + logCtx.Debugf("Image source index %d - attempting to update source as Helm application type", i) + imageUpdatable = true + if imageSourceUpdated := SetHelmImageWithIndex(app, i, img); imageSourceUpdated { + logCtx.Debugf("Image source index %d - successfully updated source as Helm parameters", i) + imageUpdated = true + } else { + logCtx.Debugf("Image source index %d - unable to update source as helm parameters - no updatable images found", i) + } + } else { + logCtx.Debugf("Image source index %d - skipping update to source due to unsupported application type", i) + } + } else { + logCtx.Tracef("Skipping update of source index %d due to image source index %d", i, imgSourceIndex) } } diff --git a/pkg/common/constants.go b/pkg/common/constants.go index cbe23d95..50336225 100644 --- a/pkg/common/constants.go +++ b/pkg/common/constants.go @@ -35,6 +35,7 @@ const ( UpdateStrategyAnnotation = ImageUpdaterAnnotationPrefix + "/%s.update-strategy" PullSecretAnnotation = ImageUpdaterAnnotationPrefix + "/%s.pull-secret" PlatformsAnnotation = ImageUpdaterAnnotationPrefix + "/%s.platforms" + SourceIndexAnnotation = ImageUpdaterAnnotationPrefix + "/%s.source-index" ) // Application-wide update strategy related annotations diff --git a/pkg/image/options.go b/pkg/image/options.go index af6d12a0..8360f53a 100644 --- a/pkg/image/options.go +++ b/pkg/image/options.go @@ -4,6 +4,7 @@ import ( "fmt" "regexp" "runtime" + "strconv" "strings" "github.com/argoproj-labs/argocd-image-updater/pkg/common" @@ -71,7 +72,7 @@ func (img *ContainerImage) HasForceUpdateOptionAnnotation(annotations map[string return forceUpdateVal == "true" } -// GetParameterSort gets and validates the value for the sort option for the +// GetParameterUpdateStrategy gets and validates the value for the update strategy for the // image from a set of annotations func (img *ContainerImage) GetParameterUpdateStrategy(annotations map[string]string) UpdateStrategy { updateStrategyAnnotations := []string{ @@ -205,6 +206,35 @@ func (img *ContainerImage) GetParameterPullSecret(annotations map[string]string) return credSrc } +func (img *ContainerImage) GetSourceIndex(annotations map[string]string) SourceIndex { + sourceIndexAnnotation := fmt.Sprintf(common.SourceIndexAnnotation, img.normalizedSymbolicName()) + + var sourceIndexVal = "" + if val, ok := annotations[sourceIndexAnnotation]; ok { + sourceIndexVal = val + } + + logCtx := img.LogContext() + if sourceIndexVal == "" { + logCtx.Tracef("No source index found. Defaulting to all.") + // Default is sort by version + return SourceIndexAll + } + logCtx.Tracef("Found source index %s", sourceIndexVal) + return img.ParseSourceIndex(sourceIndexVal) +} + +func (img *ContainerImage) ParseSourceIndex(sourceIndexVal string) SourceIndex { + logCtx := img.LogContext() + + if num, err := strconv.ParseInt(sourceIndexVal, 10, 0); err == nil { + return SourceIndex(num) + } else { + logCtx.Warnf("Invalid sourceIndex. Defaulting to all. Unexpected results may occur.") + return SourceIndexAll + } +} + // GetParameterIgnoreTags retrieves a list of tags to ignore from a comma-separated string func (img *ContainerImage) GetParameterIgnoreTags(annotations map[string]string) []string { ignoreTagsAnnotations := []string{ diff --git a/pkg/image/version.go b/pkg/image/version.go index 7613e4b9..d1285195 100644 --- a/pkg/image/version.go +++ b/pkg/image/version.go @@ -24,6 +24,12 @@ const ( StrategyDigest UpdateStrategy = 3 ) +type SourceIndex int + +const ( + SourceIndexAll SourceIndex = -1 +) + func (us UpdateStrategy) String() string { switch us { case StrategySemVer: @@ -53,12 +59,13 @@ const ( // VersionConstraint defines a constraint for comparing versions type VersionConstraint struct { - Constraint string - MatchFunc MatchFuncFn - MatchArgs interface{} - IgnoreList []string - Strategy UpdateStrategy - Options *options.ManifestOptions + Constraint string + MatchFunc MatchFuncFn + MatchArgs interface{} + IgnoreList []string + Strategy UpdateStrategy + Options *options.ManifestOptions + SourceIndex SourceIndex } type MatchFuncFn func(tagName string, pattern interface{}) bool @@ -70,9 +77,10 @@ func (vc *VersionConstraint) String() string { func NewVersionConstraint() *VersionConstraint { return &VersionConstraint{ - MatchFunc: MatchFuncNone, - Strategy: StrategySemVer, - Options: options.NewManifestOptions(), + MatchFunc: MatchFuncNone, + Strategy: StrategySemVer, + SourceIndex: SourceIndexAll, + Options: options.NewManifestOptions(), } }