diff --git a/cmd/main.go b/cmd/main.go index 3a4019dd..1f4f911c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -45,6 +45,7 @@ type ImageUpdaterConfig struct { GitCommitMail string GitCommitMessage *template.Template DisableKubeEvents bool + ManualTagValue string } // newRootCommand implements the root command of argocd-image-updater diff --git a/cmd/run.go b/cmd/run.go index 305863db..b63d69c8 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -33,6 +33,7 @@ func newRunCommand() *cobra.Command { var warmUpCache bool = true var commitMessagePath string var commitMessageTpl string + var runCmd = &cobra.Command{ Use: "run", Short: "Runs the argocd-image-updater with a set of options", @@ -223,7 +224,7 @@ func newRunCommand() *cobra.Command { runCmd.Flags().StringVar(&cfg.GitCommitMail, "git-commit-email", env.GetStringVal("GIT_COMMIT_EMAIL", "noreply@argoproj.io"), "E-Mail address to use for Git commits") runCmd.Flags().StringVar(&commitMessagePath, "git-commit-message-path", defaultCommitTemplatePath, "Path to a template to use for Git commit messages") runCmd.Flags().BoolVar(&cfg.DisableKubeEvents, "disable-kube-events", env.GetBoolVal("IMAGE_UPDATER_KUBE_EVENTS", false), "Disable kubernetes events") - + runCmd.Flags().StringVar(&cfg.ManualTagValue, "manual-tag-value", "", "Defines the image tag that will be used to update the app") return runCmd } @@ -309,6 +310,7 @@ func runImageUpdater(cfg *ImageUpdaterConfig, warmUp bool) (argocd.ImageUpdaterR GitCommitEmail: cfg.GitCommitMail, GitCommitMessage: cfg.GitCommitMessage, DisableKubeEvents: cfg.DisableKubeEvents, + ManualTagValue: cfg.ManualTagValue, } res := argocd.UpdateApplication(upconf, syncState) result.NumApplicationsProcessed += 1 diff --git a/pkg/argocd/update.go b/pkg/argocd/update.go index c92730dc..64219002 100644 --- a/pkg/argocd/update.go +++ b/pkg/argocd/update.go @@ -43,6 +43,7 @@ type UpdateConfiguration struct { GitCommitMessage *template.Template DisableKubeEvents bool IgnorePlatforms bool + ManualTagValue string } type GitCredsSource func(app *v1alpha1.Application) (git.Creds, error) @@ -196,6 +197,12 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat } vc.Strategy = applicationImage.GetParameterUpdateStrategy(updateConf.UpdateApp.Application.Annotations) + // If strategy is manual but no tag has been set, default to SemVer + if vc.Strategy == image.StrategyManual && updateConf.ManualTagValue == "" { + imgCtx.Infof("strategy is set to %s but it requires a tag defined via --manual-tag-value. Defaulting to %s strategy instead.", vc.Strategy.String(), image.StrategySemVer.String()) + vc.Strategy = image.StrategySemVer + } + vc.MatchFunc, vc.MatchArgs = applicationImage.GetParameterMatch(updateConf.UpdateApp.Application.Annotations) vc.IgnoreList = applicationImage.GetParameterIgnoreTags(updateConf.UpdateApp.Application.Annotations) vc.Options = applicationImage. @@ -234,13 +241,20 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat result.NumErrors += 1 continue } + var tags *tag.ImageTagList = tag.NewImageTagList() - // Get list of available image tags from the repository - tags, err := rep.GetTags(applicationImage, regClient, &vc) - if err != nil { - imgCtx.Errorf("Could not get tags from registry: %v", err) - result.NumErrors += 1 - continue + if vc.Strategy != image.StrategyManual { + // Get list of available image tags from the repository + tags, err = rep.GetTags(applicationImage, regClient, &vc) + if err != nil { + imgCtx.Errorf("Could not get tags from registry: %v", err) + result.NumErrors += 1 + continue + } + } else { + manualTag := tag.NewImageTag(updateConf.ManualTagValue, time.Unix(0, 0), "") + + tags.Add(manualTag) } imgCtx.Tracef("List of available tags found: %v", tags.Tags()) diff --git a/pkg/image/options.go b/pkg/image/options.go index af6d12a0..98dcae98 100644 --- a/pkg/image/options.go +++ b/pkg/image/options.go @@ -112,6 +112,8 @@ func (img *ContainerImage) ParseUpdateStrategy(val string) UpdateStrategy { return StrategyAlphabetical case "digest": return StrategyDigest + case "manual": + return StrategyManual default: logCtx.Warnf("Unknown sort option %s -- using semver", val) return StrategySemVer diff --git a/pkg/image/version.go b/pkg/image/version.go index 43b3f5c2..616e069d 100644 --- a/pkg/image/version.go +++ b/pkg/image/version.go @@ -22,6 +22,8 @@ const ( StrategyAlphabetical UpdateStrategy = 2 // VersionSortDigest uses latest digest of an image StrategyDigest UpdateStrategy = 3 + // VersionManual uses a user provided tag for an image + StrategyManual UpdateStrategy = 4 ) func (us UpdateStrategy) String() string { @@ -34,6 +36,8 @@ func (us UpdateStrategy) String() string { return "alphabetical" case StrategyDigest: return "digest" + case StrategyManual: + return "manual" } return "unknown" @@ -93,6 +97,8 @@ func (img *ContainerImage) GetNewestVersionFromTags(vc *VersionConstraint, tagLi availableTags = tagList.SortByDate() case StrategyDigest: availableTags = tagList.SortAlphabetically() + case StrategyManual: + availableTags = tagList.SortAlphabetically() } considerTags := tag.SortableImageTagList{}