Skip to content

Commit

Permalink
feat(application-controller): Add support for rollback multi-source a…
Browse files Browse the repository at this point in the history
…pplications (argoproj#14124)

* feat(application-controller): Add support for rollback multi-source applications

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* regenerate codegen after rebase

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* fix tests

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* fix front linting

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* update test

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* update codegen

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* Update server/application/application.go

Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
Signed-off-by: Jorge Turrado Ferrero <Jorge_turrado@hotmail.es>

* apply feedback

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* fix errors

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* add support for switching between single and multi

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* fix dereference issue

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* remove unnecesary code

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* Rebase master

Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>

* fix style

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* fix reference

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>

* add a comment

Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>

---------

Signed-off-by: Jorge Turrado <jorge_turrado@hotmail.es>
Signed-off-by: Jorge Turrado Ferrero <Jorge_turrado@hotmail.es>
Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
  • Loading branch information
2 people authored and mkieweg committed Jun 11, 2024
1 parent 41da241 commit 2a794b2
Show file tree
Hide file tree
Showing 35 changed files with 1,006 additions and 436 deletions.
38 changes: 38 additions & 0 deletions assets/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1633,6 +1633,20 @@
"type": "string",
"name": "project",
"in": "query"
},
{
"type": "integer",
"format": "int32",
"description": "source index (for multi source apps).",
"name": "sourceIndex",
"in": "query"
},
{
"type": "integer",
"format": "int32",
"description": "versionId from historical data (for multi source apps).",
"name": "versionId",
"in": "query"
}
],
"responses": {
Expand Down Expand Up @@ -1683,6 +1697,20 @@
"type": "string",
"name": "project",
"in": "query"
},
{
"type": "integer",
"format": "int32",
"description": "source index (for multi source apps).",
"name": "sourceIndex",
"in": "query"
},
{
"type": "integer",
"format": "int32",
"description": "versionId from historical data (for multi source apps).",
"name": "versionId",
"in": "query"
}
],
"responses": {
Expand Down Expand Up @@ -5130,6 +5158,16 @@
},
"source": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
},
"sourceIndex": {
"type": "integer",
"format": "int32",
"title": "source index (for multi source apps)"
},
"versionId": {
"type": "integer",
"format": "int32",
"title": "versionId from historical data (for multi source apps)"
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion cmd/argocd/commands/admin/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ func reconcileApplications(
sources = append(sources, app.Spec.GetSource())
revisions = append(revisions, app.Spec.GetSource().TargetRevision)

res, err := appStateManager.CompareAppState(&app, proj, revisions, sources, false, false, nil, false)
res, err := appStateManager.CompareAppState(&app, proj, revisions, sources, false, false, nil, false, false)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/argocd/commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ func printAppSourceDetails(appSrc *argoappv1.ApplicationSource) {
if appSrc.Path != "" {
fmt.Printf(printOpFmtStr, " Path:", appSrc.Path)
}
if appSrc.Ref != "" {
if appSrc.IsRef() {
fmt.Printf(printOpFmtStr, " Ref:", appSrc.Ref)
}
if appSrc.Helm != nil && len(appSrc.Helm.ValueFiles) > 0 {
Expand Down Expand Up @@ -923,7 +923,7 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C

func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, nothingToUnset bool) {
needToUnsetRef := false
if opts.ref && source.Ref != "" {
if opts.ref && source.IsRef() {
source.Ref = ""
updated = true
needToUnsetRef = true
Expand Down
36 changes: 36 additions & 0 deletions cmd/argocd/commands/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,42 @@ func TestPrintTreeViewDetailedAppGet(t *testing.T) {
assert.Contains(t, output, "numalogic-rollout-demo-5dcd5457d5-6trpt")
assert.Contains(t, output, "Degraded")
assert.Contains(t, output, "Readiness Gate failed")
}

func TestFindRevisionHistoryWithoutPassedIdWithMultipleSources(t *testing.T) {

histories := v1alpha1.RevisionHistories{}

histories = append(histories, v1alpha1.RevisionHistory{ID: 1})
histories = append(histories, v1alpha1.RevisionHistory{ID: 2})
histories = append(histories, v1alpha1.RevisionHistory{ID: 3})

status := v1alpha1.ApplicationStatus{
Resources: nil,
Sync: v1alpha1.SyncStatus{},
Health: v1alpha1.HealthStatus{},
History: histories,
Conditions: nil,
ReconciledAt: nil,
OperationState: nil,
ObservedAt: nil,
SourceType: "",
Summary: v1alpha1.ApplicationSummary{},
}

application := v1alpha1.Application{
Status: status,
}

history, err := findRevisionHistory(&application, -1)

if err != nil {
t.Fatal("Find revision history should fail without errors")
}

if history == nil {
t.Fatal("History should be found")
}

}

Expand Down
2 changes: 1 addition & 1 deletion controller/appcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1594,7 +1594,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo

compareResult, err := ctrl.appStateManager.CompareAppState(app, project, revisions, sources,
refreshType == appv1.RefreshTypeHard,
comparisonLevel == CompareWithLatestForceResolve, localManifests, hasMultipleSources)
comparisonLevel == CompareWithLatestForceResolve, localManifests, hasMultipleSources, false)

if goerrors.Is(err, CompareStateRepoError) {
logCtx.Warnf("Ignoring temporary failed attempt to compare app state against repo: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion controller/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (ctrl *ApplicationController) executePostDeleteHooks(app *v1alpha1.Applicat
revisions = append(revisions, src.TargetRevision)
}

targets, _, err := ctrl.appStateManager.GetRepoObjs(app, app.Spec.GetSources(), appLabelKey, revisions, false, false, false, proj)
targets, _, err := ctrl.appStateManager.GetRepoObjs(app, app.Spec.GetSources(), appLabelKey, revisions, false, false, false, proj, false)
if err != nil {
return false, err
}
Expand Down
15 changes: 8 additions & 7 deletions controller/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ type managedResource struct {

// AppStateManager defines methods which allow to compare application spec and actual application state.
type AppStateManager interface {
CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localObjects []string, hasMultipleSources bool) (*comparisonResult, error)
CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localObjects []string, hasMultipleSources bool, rollback bool) (*comparisonResult, error)
SyncAppState(app *v1alpha1.Application, state *v1alpha1.OperationState)
GetRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, error)
GetRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject, rollback bool) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, error)
}

// comparisonResult holds the state of an application after the reconciliation
Expand Down Expand Up @@ -126,7 +126,7 @@ type appStateManager struct {
// task to the repo-server. It returns the list of generated manifests as unstructured
// objects. It also returns the full response from all calls to the repo server as the
// second argument.
func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, error) {
func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject, rollback bool) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, error) {
ts := stats.NewTimingStats()
helmRepos, err := m.db.ListHelmRepositories(context.Background())
if err != nil {
Expand Down Expand Up @@ -178,7 +178,9 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
targetObjs := make([]*unstructured.Unstructured, 0)

// Store the map of all sources having ref field into a map for applications with sources field
refSources, err := argo.GetRefSources(context.Background(), app.Spec, m.db.GetRepository)
// If it's for a rollback process, the refSources[*].targetRevision fields are the desired
// revisions for the rollback
refSources, err := argo.GetRefSources(context.Background(), sources, app.Spec.Project, m.db.GetRepository, revisions, rollback)
if err != nil {
return nil, nil, fmt.Errorf("failed to get ref sources: %v", err)
}
Expand Down Expand Up @@ -264,7 +266,6 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
return nil, nil, fmt.Errorf("failed to unmarshal manifests for source %d of %d: %w", i+1, len(sources), err)
}
targetObjs = append(targetObjs, targetObj...)

manifestInfos = append(manifestInfos, manifestInfo)
}

Expand Down Expand Up @@ -395,7 +396,7 @@ func isManagedNamespace(ns *unstructured.Unstructured, app *v1alpha1.Application
// CompareAppState compares application git state to the live app state, using the specified
// revision and supplied source. If revision or overrides are empty, then compares against
// revision and overrides in the app spec.
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localManifests []string, hasMultipleSources bool) (*comparisonResult, error) {
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localManifests []string, hasMultipleSources bool, rollback bool) (*comparisonResult, error) {
ts := stats.NewTimingStats()
appLabelKey, resourceOverrides, resFilter, err := m.getComparisonSettings()

Expand Down Expand Up @@ -453,7 +454,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
}
}

targetObjs, manifestInfos, err = m.GetRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project)
targetObjs, manifestInfos, err = m.GetRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project, rollback)
if err != nil {
targetObjs = make([]*unstructured.Unstructured, 0)
msg := fmt.Sprintf("Failed to load target state: %s", err.Error())
Expand Down
Loading

0 comments on commit 2a794b2

Please sign in to comment.